-
Notifications
You must be signed in to change notification settings - Fork 0
/
snake.sh
executable file
Β·164 lines (149 loc) Β· 4.63 KB
/
snake.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#!/usr/bin/env bash
clear
tput civis # Stop blinking cursor
if [ -t 0 ]; then stty -echo -icanon -icrnl time 0 min 0; fi # Set bash to non-blocking mode
# Define dimensions of the field
width=$(($(tput cols)-1))
height=$(($(tput lines)-2))
# Define starting position for the snake
snake=("$(($width/2)),$(($height/2)), $(($width/2-1)),$(($height/2)), $(($width/2-2)),$(($height/2))")
# Some starting variables
dir="right"
speed=0
keypress=''
score=0
fruits=(π π π π π π π π π π π π π)
# Display some game information, used for debugging
debug () {
tput cup 0 0
printf "Field: ${width},${height} Player: $(echo ${snake[0]} | cut -d, -f1),$(echo ${snake[0]} | cut -d, -f2) Direction: $dir Food: $food \n"
printf "Snake length ${#snake[@]}, def: ${snake[*]}, last: $last "
}
# Prints something on the third line. Used for debugging.
print () {
tput cup 3 0
printf " "
tput cup 3 0
printf "$1"
}
# Prints the score in the bottom left of the screen
score () {
score=$(($score+1))
tput cup $height 0
printf $score
}
# Check if $1 is in array $2. Used for collision detection and eating fruits
checkHit () {
local e match="$1"
shift
for e; do [[ "$e" == "$match" ]] && return 0; done
return 1
}
renderSnake () {
# Draw the snake by only drawing its head
tput cup $(echo ${snake[0]} | cut -d, -f2) $(echo ${snake[0]} | cut -d, -f1)
printf β
# Remove the butt from last draw
tput cup $(echo $last | cut -d, -f2) $(echo $last | cut -d, -f1)
printf ' '
}
# Defines the new position of the head and removes its tail if it hasn't eaten
moveSnake () {
last=${snake[${#snake[@]}-1]}
length=${#snake[*]}
if [ $dir == right ]; then # Moving right
if [[ $(($(echo ${snake[0]} | cut -d, -f1)+1)) -le $width ]]; then
newpart="$(($(echo ${snake[0]} | cut -d, -f1)+1)),$(echo ${snake[0]} | cut -d, -f2)"
else
newpart="0,$(echo ${snake[0]} | cut -d, -f2)"
fi
elif [ $dir == left ]; then # Moving left
if [[ $(($(echo ${snake[0]} | cut -d, -f1)-1)) -ge 0 ]]; then
newpart="$(($(echo ${snake[0]} | cut -d, -f1)-1)),$(echo ${snake[0]} | cut -d, -f2)"
else
newpart="$width,$(echo ${snake[0]} | cut -d, -f2)"
fi
elif [ $dir == up ]; then # Moving up
if [[ $(($(echo ${snake[0]} | cut -d, -f2)-1)) -ge 0 ]]; then
newpart="$(echo ${snake[0]} | cut -d, -f1),$(($(echo ${snake[0]} | cut -d, -f2)-1))"
else
newpart="$(echo ${snake[0]} | cut -d, -f1),$height"
fi
elif [ $dir == down ]; then # Moving down
if [[ $(($(echo ${snake[0]} | cut -d, -f2)+1)) -le $height ]]; then
newpart="$(echo ${snake[0]} | cut -d, -f1),$(($(echo ${snake[0]} | cut -d, -f2)+1))"
else
newpart="$(echo ${snake[0]} | cut -d, -f1),0"
fi
fi
if checkHit "$newpart" "${snake[@]}"; then
die # It has hit itself here
fi
snake=($newpart ${snake[@]})
if checkFood || [ "$grow" == 1 ]; then
unset grow
else
unset 'snake[${#snake[@]}-1]'
fi
}
# Draws the fruit. If the position overlaps with the snake array, it calls itself to define a new position and draw it.
drawFood () {
food="$((RANDOM%$width)),$((RANDOM%$height))"
tput cup $(echo $food | cut -d, -f2) $(echo $food | cut -d, -f1)
printf ${fruits[$RANDOM % ${#fruits[*]} ]}
if checkHit "$food" "${snake[@]}"; then
drawFood
fi
}
# Checks if the head is at the position of the food, if so, increase the score and draw new food.
checkFood () {
if [[ "${snake[0]}" == "$food" ]]; then
score
drawFood
return 0
fi
return 1
}
# Stop the game and reset the terminal
stop () {
if [ -t 0 ]; then stty sane; fi
tput reset
exit 0
}
# Die, reset the terminal to display some sad text and stop the game.
die () {
tput reset
tput civis
tput cup $(($height/2)) $(($width/2-10))
printf "π₯Ί You've died... π₯Ί"
sleep 3
stop
}
# The gameloop which reads the key input. Uncomment debug to show debugging information. Note the g key which makes the snake grow.
game () {
while :; do
# debug
renderSnake
moveSnake
sleep $speed
read keypress
if [ "$keypress" == 'i' ]; then
if [ "$dir" != "down" ]; then dir="up"; fi
elif [ "$keypress" == 'k' ]; then
if [ "$dir" != "up" ]; then dir="down"; fi
elif [ "$keypress" == 'j' ]; then
if [ "$dir" != "right" ]; then dir="left"; fi
elif [ "$keypress" == 'l' ]; then
if [ "$dir" != "left" ]; then dir="right"; fi
elif [ "$keypress" == "q" ]; then
stop
elif [ "$keypress" == "g" ]; then
grow=1
elif [ "$keypress" == "" ]; then
echo
fi
done
}
# The function calls to set up the game
drawFood
game