forked from liungkejin/Bash-Games
-
Notifications
You must be signed in to change notification settings - Fork 0
/
snake.sh
executable file
·215 lines (180 loc) · 6.96 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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
#!/usr/bin/env bash
# filename: snake.sh
# snake game
# Author: LKJ 2013.5.17
good_game=(
' '
' G A M E O V E R ! '
' '
' Score: '
' press q to quit '
' press n to start a new game '
' press s to change the speed '
' '
);
game_start=(
' '
' ~~~ S N A K E ~~~ '
' '
' Author: LKJ '
' space or enter pause/play '
' q quit at any time '
' s change the speed '
' '
' Press <Enter> to start the game '
' '
);
snake_exit() { #退出游戏
stty echo; #恢复回显
tput rmcup; #恢复屏幕
tput cvvis; #恢复光标
exit 0;
}
draw_gui() { # 画边框
clear;
color="\033[34m*\033[0m";
for (( i = 0; i < $1; i++ )); do
echo -ne "\033[$i;0H${color}";
echo -ne "\033[$i;$2H${color}";
done
for (( i = 0; i <= $2; i++ )); do
echo -ne "\033[0;${i}H${color}";
echo -ne "\033[$1;${i}H${color}";
done
ch_speed 0;
echo -ne "\033[$Lines;$((yscore-10))H\033[36mScores: 0\033[0m";
echo -en "\033[$Lines;$((Cols-50))H\033[33mPress <space> or enter to pause game\033[0m";
}
snake_init() {
Lines=`tput lines`; Cols=`tput cols`; #得到屏幕的长宽
xline=$((Lines/2)); ycols=4; #开始的位置
xscore=$Lines; yscore=$((Cols/2)); #打印分数的位置
xcent=$xline; ycent=$yscore; #中心点位置
xrand=0; yrand=0; #随机点
sumscore=0; liveflag=1; #总分和点存在标记
sumnode=0; foodscore=0; #总共要加长的节点和点的分数
snake="0000 "; #初始化贪吃蛇
pos=(right right right right right); #开始节点的方向
xpt=($xline $xline $xline $xline $xline); #开始的各个节点的x坐标
ypt=(5 4 3 2 1); #开始的各个节点的y坐标
speed=(0.05 0.1 0.15); spk=${spk:-1}; #速度 默认速度
draw_gui $((Lines-1)) $Cols
}
game_pause() { #暂定游戏
echo -en "\033[$Lines;$((Cols-50))H\033[33mGame paused, Use space or enter key to continue\033[0m";
while read -n 1 space; do
[[ ${space:-enter} = enter ]] && \
echo -en "\033[$Lines;$((Cols-50))H\033[33mPress <space> or enter to pause game \033[0m" && return;
[[ ${space:-enter} = q ]] && snake_exit;
done
}
# $1 节点位置
update() { #更新各个节点坐标
case ${pos[$1]} in
right) ((ypt[$1]++));;
left) ((ypt[$1]--));;
down) ((xpt[$1]++));;
up) ((xpt[$1]--));;
esac
}
ch_speed() { #更新速度
[[ $# -eq 0 ]] && spk=$(((spk+1)%3));
case $spk in
0) temp="Fast ";;
1) temp="Medium";;
2) temp="Slow ";;
esac
echo -ne "\033[$Lines;3H\033[33mSpeed: $temp\033[0m";
}
Gooooo() { #更新方向
case ${key:-enter} in
j|J) [[ ${pos[0]} != "up" ]] && pos[0]="down";;
k|K) [[ ${pos[0]} != "down" ]] && pos[0]="up";;
h|H) [[ ${pos[0]} != "right" ]] && pos[0]="left";;
l|L) [[ ${pos[0]} != "left" ]] && pos[0]="right";;
s|S) ch_speed;;
q|Q) snake_exit;;
enter) game_pause;;
esac
}
add_node() { #增加节点
snake="0$snake";
pos=(${pos[0]} ${pos[@]});
xpt=(${xpt[0]} ${xpt[@]});
ypt=(${ypt[0]} ${ypt[@]});
update 0;
local x=${xpt[0]} y=${ypt[0]}
(( ((x>=$((Lines-1)))) || ((x<=1)) || ((y>=Cols)) || ((y<=1)) )) && return 1; #撞墙
for (( i = $((${#snake}-1)); i > 0; i-- )); do
(( ${xpt[0]} == ${xpt[$i]} && ${ypt[0]} == ${ypt[$i]} )) && return 1; #crashed
done
echo -ne "\033[${xpt[0]};${ypt[0]}H\033[32m${snake[@]:0:1}\033[0m";
return 0;
}
mk_random() { #产生随机点和随机数
xrand=$((RANDOM%(Lines-3)+2));
yrand=$((RANDOM%(Cols-2)+2));
foodscore=$((RANDOM%9+1));
echo -ne "\033[$xrand;${yrand}H$foodscore";
liveflag=0;
}
new_game() { #重新开始新游戏
snake_init;
while true; do
read -t ${speed[$spk]} -n 1 key;
[[ $? -eq 0 ]] && Gooooo;
((liveflag==0)) || mk_random;
if (( sumnode > 0 )); then
((sumnode--));
add_node; (($?==0)) || return 1;
else
update 0;
echo -ne "\033[${xpt[0]};${ypt[0]}H\033[32m${snake[@]:0:1}\033[0m";
for (( i = $((${#snake}-1)); i > 0; i-- )); do
update $i;
echo -ne "\033[${xpt[$i]};${ypt[$i]}H\033[32m${snake[@]:$i:1}\033[0m";
(( ${xpt[0]} == ${xpt[$i]} && ${ypt[0]} == ${ypt[$i]} )) && return 1; #crashed
[[ ${pos[$((i-1))]} = ${pos[$i]} ]] || pos[$i]=${pos[$((i-1))]};
done
fi
local x=${xpt[0]} y=${ypt[0]}
(( ((x>=$((Lines-1)))) || ((x<=1)) || ((y>=Cols)) || ((y<=1)) )) && return 1; #撞墙
(( x==xrand && y==yrand )) && ((liveflag=1)) && ((sumnode+=foodscore)) && ((sumscore+=foodscore));
echo -ne "\033[$xscore;$((yscore-2))H$sumscore";
done
}
print_good_game() {
local x=$((xcent-4)) y=$((ycent-25))
for (( i = 0; i < 8; i++ )); do
echo -ne "\033[$((x+i));${y}H\033[45m${good_game[$i]}\033[0m";
done
echo -ne "\033[$((x+3));$((ycent+1))H\033[45m${sumscore}\033[0m";
}
print_game_start() {
snake_init;
local x=$((xcent-5)) y=$((ycent-25))
for (( i = 0; i < 10; i++ )); do
echo -ne "\033[$((x+i));${y}H\033[45m${game_start[$i]}\033[0m";
done
while read -n 1 anykey; do
[[ ${anykey:-enter} = enter ]] && break;
[[ ${anykey:-enter} = q ]] && snake_exit;
[[ ${anykey:-enter} = s ]] && ch_speed;
done
while true; do
new_game;
print_good_game;
while read -n 1 anykey; do
[[ $anykey = n ]] && break;
[[ $anykey = q ]] && snake_exit;
done
done
}
game_main() {
trap 'snake_exit;' SIGTERM SIGINT;
stty -echo; #取消回显
tput civis; #隐藏光标
tput smcup; clear; #保存屏幕并清屏
print_game_start; #开始游戏
}
game_main;