client/scripts/snake.sh
François Patron c6b707f0fb Push snake game
2024-12-14 01:12:29 +01:00

239 lines
6.4 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
IFS=''
declare -i height=$(($(tput lines)-5)) width=$(($(tput cols)-2))
declare -i head_r head_c tail_r tail_c
declare -i alive
declare -i length
declare body
declare -i direction delta_dir
declare -i score=0
border_color="\e[30;43m"
snake_color="\e[32;42m"
food_color="\e[34;44m"
text_color="\e[31;43m"
no_color="\e[0m"
SIG_UP=USR1
SIG_RIGHT=USR2
SIG_DOWN=URG
SIG_LEFT=IO
SIG_QUIT=WINCH
SIG_DEAD=HUP
move_r=([0]=-1 [1]=0 [2]=1 [3]=0)
move_c=([0]=0 [1]=1 [2]=0 [3]=-1)
init_game() {
clear
echo -ne "\e[?25l"
stty -echo
for ((i=0; i<height; i++)); do
for ((j=0; j<width; j++)); do
eval "arr$i[$j]=' '"
done
done
}
move_and_draw() {
echo -ne "\e[${1};${2}H$3"
}
draw_board() {
move_and_draw 1 1 "$border_color+$no_color"
for ((i=2; i<=width+1; i++)); do
move_and_draw 1 $i "$border_color-$no_color"
done
move_and_draw 1 $((width + 2)) "$border_color+$no_color"
echo
for ((i=0; i<height; i++)); do
move_and_draw $((i+2)) 1 "$border_color|$no_color"
eval echo -en "\"\${arr$i[*]}\""
echo -e "$border_color|$no_color"
done
move_and_draw $((height+2)) 1 "$border_color+$no_color"
for ((i=2; i<=width+1; i++)); do
move_and_draw $((height+2)) $i "$border_color-$no_color"
done
move_and_draw $((height+2)) $((width + 2)) "$border_color+$no_color"
echo
}
init_snake() {
alive=0
length=10
direction=0
delta_dir=-1
head_r=$((height / 4))
head_c=$((width / 4))
body=''
for ((i = 0; i < length - 1; i++)); do
body="1$body"
done
local p=$((${move_r[1]} * (length - 1)))
local q=$((${move_c[1]} * (length - 1)))
tail_r=$((head_r + p))
tail_c=$((head_c + q))
eval "arr$head_r[$head_c]=\"${snake_color}o$no_color\""
prev_r=$head_r
prev_c=$head_c
b=$body
while [ -n "$b" ]; do
local p=${move_r[$(echo $b | grep -o '^[0-3]')]}
local q=${move_c[$(echo $b | grep -o '^[0-3]')]}
new_r=$((prev_r + p))
new_c=$((prev_c + q))
eval "arr$new_r[$new_c]=\"${snake_color}o$no_color\""
prev_r=$new_r
prev_c=$new_c
b=${b#[0-3]}
done
}
is_dead() {
if [ "$1" -lt 0 ] || [ "$1" -ge "$height" ] || \
[ "$2" -lt 0 ] || [ "$2" -ge "$width" ]; then
return 0
fi
eval "local pos=\${arr$1[$2]}"
if [ "$pos" == "${snake_color}o$no_color" ] || [[ "$pos" == *"$border_color"* ]]; then
return 0
fi
return 1
}
init_wall() {
local wall_start_r=$((height / 2 - 3))
local wall_start_c=$((width / 2 - 30))
local wall_text=(
"████████╗██╗ ██████╗ ██████╗ ██████╗ ██████╗ ██╗ "
"╚══██╔══╝██║ ██╔════╝ ██╔══██╗██╔═══██╗██╔═══██╗██║ "
" ██║ ██║ ██║ ███╗ ██████╔╝██║ ██║██║ ██║██║ "
" ██║ ██║ ██║ ██║ ██╔═══╝ ██║ ██║██║ ██║██║ "
" ██║ ██║ ╚██████╔╝ ██║ ╚██████╔╝╚██████╔╝███████╗"
" ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝"
)
for ((i = 0; i < ${#wall_text[@]}; i++)); do
for ((j = 0; j < ${#wall_text[i]}; j++)); do
local r=$((wall_start_r + i))
local c=$((wall_start_c + j))
eval "arr$r[$c]=\"${border_color}${wall_text[i]:j:1}$no_color\""
done
done
}
give_food() {
local food_r=$((RANDOM % height))
local food_c=$((RANDOM % width))
eval "local pos=\${arr$food_r[$food_c]}"
while [ "$pos" != ' ' ]; do
food_r=$((RANDOM % height))
food_c=$((RANDOM % width))
eval "pos=\${arr$food_r[$food_c]}"
done
eval "arr$food_r[$food_c]=\"$food_color@$no_color\""
}
move_snake() {
local newhead_r=$((head_r + move_r[direction]))
local newhead_c=$((head_c + move_c[direction]))
eval "local pos=\${arr$newhead_r[$newhead_c]}"
if $(is_dead $newhead_r $newhead_c); then
alive=1
return
fi
if [ "$pos" == "$food_color@$no_color" ]; then
length+=1
eval "arr$newhead_r[$newhead_c]=\"${snake_color}o$no_color\""
body="$(((direction+2)%4))$body"
head_r=$newhead_r
head_c=$newhead_c
score+=1
give_food;
return
fi
head_r=$newhead_r
head_c=$newhead_c
local d=$(echo $body | grep -o '[0-3]$')
body="$(((direction+2)%4))${body%[0-3]}"
eval "arr$tail_r[$tail_c]=' '"
eval "arr$head_r[$head_c]=\"${snake_color}o$no_color\""
local p=${move_r[(d+2)%4]}
local q=${move_c[(d+2)%4]}
tail_r=$((tail_r+p))
tail_c=$((tail_c+q))
}
change_dir() {
if [ $(((direction+2)%4)) -ne $1 ]; then
direction=$1
fi
delta_dir=-1
}
getchar() {
trap "" SIGINT SIGQUIT
trap "return;" $SIG_DEAD
while true; do
read -s -n 1 key
if [[ "$key" == $'\e' ]]; then
read -s -n 2 arrow
key+="$arrow"
fi
case "$key" in
[qQ]) kill -$SIG_QUIT $game_pid
return
;;
$'\e[A') kill -$SIG_UP $game_pid
;;
$'\e[C') kill -$SIG_RIGHT $game_pid
;;
$'\e[B') kill -$SIG_DOWN $game_pid
;;
$'\e[D') kill -$SIG_LEFT $game_pid
;;
esac
done
}
game_loop() {
trap "delta_dir=0;" $SIG_UP
trap "delta_dir=1;" $SIG_RIGHT
trap "delta_dir=2;" $SIG_DOWN
trap "delta_dir=3;" $SIG_LEFT
trap "exit 1;" $SIG_QUIT
while [ "$alive" -eq 0 ]; do
echo -e "\n${text_color}Your score: $score $no_color"
if [ "$delta_dir" -ne -1 ]; then
change_dir $delta_dir
fi
move_snake
draw_board
sleep 0.03
done
echo -e "${text_color}Oh no! Youre dead! Share your best score! :)$no_color"
kill -$SIG_DEAD $$
}
clear_game() {
stty echo
echo -e "\e[?25h"
}
init_game
init_snake
init_wall
give_food
draw_board
game_loop &
game_pid=$!
getchar
clear_game
exit 0