xtitle(){
printf "\033]0;%s\007" "${*}π${HOSTNAME}"
}
MY_STRING="πβπΈπΆππ
ππ₯π§Ώ"
STRING_LENGTH=${#MY_STRING}
RANDOM_INDEX=$((RANDOM % STRING_LENGTH))
ASCII="${MY_STRING:$RANDOM_INDEX:1}"
xtitle "${ASCII} Life"
declare -r DEAD_CELL_VALUE="π΄"
declare -r LIVE_CELL_VALUE="$ASCII"
declare -i TICK_RATE_S=1
declare -i current_lines
declare -i current_cols
declare -i current_tick
declare -a current_state
declare -a next_state
declare -i array_index
declare -i line_from_index
declare -i col_from_index
declare -a surrounding_indexes
declare -i living_neighbours_count=0
declare next_cell_state
declare -a input_state
function log() {
printf "%s: %s\n" "$(perl -e 'use Time::HiRes qw(time); print time')" "$1" >> bash-life.log
}
function set_cursor_pos() {
typeset line=$1
typeset col=$2
printf "\033[${line};${col}H"
}
function print_at_pos() {
typeset line=$1
typeset col=$2
typeset to_print=$3
set_cursor_pos $line $col
printf "$to_print"
}
function print_cell() {
print_at_pos $(($1 + 1)) $2 "$3"
}
function get_term_lines() {
printf $(tput lines)
}
function get_term_cols() {
printf $(tput cols)
}
function update_term_size() {
current_lines=$(get_term_lines - 1)
current_cols=$(get_term_cols)
}
function get_array_index() {
let array_index="($1-1) * (current_cols) + $2 - 1"
}
function get_line_from_index() {
let line_from_index="$1/current_cols + 1"
}
function get_col_from_index() {
let col_from_index="$1 % current_cols + 1"
}
function init_current_state() {
for (( line=1; line<=current_lines; ++line )); do
for (( col=1; col<=current_cols; ++col )); do
get_array_index $line $col
current_state[$array_index]=$DEAD_CELL_VALUE
done
done
}
function init_game_state() {
current_tick=0
update_term_size
init_current_state
}
function get_living_neighbours_count() {
declare -i line=$1
declare -i col=$2
declare -i index=0
living_neighbours_count=0
for l in $((line-1)) $line $((line+1)); do
(( l > 0 && l <= current_lines )) || continue
for c in $((col-1)) $col $((col+1)); do
(( c > 0 && c <= current_cols )) || continue
if (( !(l == line && c == col) )); then
get_array_index $l $c
[[ ${current_state[$array_index]} == $LIVE_CELL_VALUE ]] && ((++living_neighbours_count))
fi
done
done
}
function get_next_cell_state() {
declare -i line=$1
declare -i col=$2
get_living_neighbours_count $line $col
get_array_index $line $col
if (( living_neighbours_count < 2 || living_neighbours_count > 3 )); then
next_cell_state=$DEAD_CELL_VALUE
elif [[ ${current_state[$array_index]} == $LIVE_CELL_VALUE ]]; then
next_cell_state=$LIVE_CELL_VALUE
elif (( living_neighbours_count == 3 )); then
next_cell_state=$LIVE_CELL_VALUE
else
next_cell_state=$DEAD_CELL_VALUE
fi
}
function update() {
next_state=()
for (( line=1; line<=$current_lines; ++line )); do
for (( col=1; col<=$current_cols; ++col )); do
get_next_cell_state $line $col
get_array_index $line $col
next_state[$array_index]=$next_cell_state
done
done
current_state=("${next_state[@]}")
}
function draw_header() {
print_at_pos 1 1 "Current tick: $current_tick"
}
function draw() {
clear
draw_header
for (( index=1; index<=${#current_state[*]}; ++index)); do
if [[ ${current_state[$index - 1]} == $LIVE_CELL_VALUE ]]; then
get_line_from_index $((index-1))
get_col_from_index $((index-1))
print_cell $line_from_index $col_from_index $LIVE_CELL_VALUE
fi
done
}
function set_current_state_from_input_state() {
declare -i i=0
while ((i < ${#input_state[*]})); do
get_array_index ${input_state[$i]} ${input_state[$((i+1))]}
current_state[$array_index]=$LIVE_CELL_VALUE
((i+=2))
done
}
function set_current_state_parallels() {
input_state=(5 5 5 6 6 5 6 6 7 5 7 6)
set_current_state_from_input_state
}
function set_current_state_cross() {
input_state=(5 30 6 29 6 30 6 31 7 30)
set_current_state_from_input_state
}
function set_current_state_glider() {
input_state=(1 2 2 3 3 1 3 2 3 3)
set_current_state_from_input_state
}
function set_current_state_glider_gun() {
input_state=(2 26 3 24 3 26 4 14 4 15 4 22 4 23 4 36 4 37 5 13 5 17 5 22 5 23 5 36 5 37 6 2 6 3 6 12 6 18 6 22 6 23 7 2 7 3 7 12 7 16 7 18 7 19 7 24 7 26 8 12 8 18 8 26 9 13 9 17 10 14 10 15)
set_current_state_from_input_state
}
rm -f bash-life.log
init_game_state
set_current_state_glider_gun
draw
while ((1 == 1)); do
let current_tick=current_tick+1
update
draw
done