2
* Snake
3
* author: dave_cn
4
* date : 2010/7/14
5
* info :
6
* @ ...... food
7
*/
8
#include
<
stdio.h
>
9
#include
<
stdlib.h
>
10
#include
<
string
.h
>
11
#include
<
sys
/
time.h
>
12
#include
<
sys
/
types.h
>
13
#include
<
unistd.h
>
14
#include
<
ncurses.h
>
15
16
#define
TBool int
17
#define
True 1
18
#define
False 0
19
#define
SHAPE_FOOD '@'
20
#define
SHAPE_SNAKE '*'
21
#define
GAMEWIN_YLEN 15
22
#define
GAMEWIN_XLEN 60
23
#define
LOGWIN_YLEN 7
24
#define
LOGWIN_XLEN (GAMEWIN_XLEN)
25
#define
LOGBUF_NUM (LOGWIN_YLEN-2)
26
#define
LOGBUF_LEN (GAMEWIN_XLEN-2)
27
#define
MAXLEVEL 12
28
29
#define
GetSnakeTail(s) ((s)->head->front)
30
31
WINDOW
*
logwin;
32
#define
INITRUNLOG() logwin = newlogw()
33
#define
RUNLOG(str) runlog(logwin, str)
34
#define
DESTROYRUNLOG() delwin(logwin)
35
36
int
g_level;
37
38
enum
TDirection {
39
DIR_UP,
40
DIR_DOWN,
41
DIR_LEFT,
42
DIR_RIGHT
43
};
44
45
struct
TFood {
46
int
y;
47
int
x;
48
};
49
50
struct
TSnakeNode {
51
int
y;
52
int
x;
53
struct
TSnakeNode
*
front;
54
};
55
56
struct
TSnake {
57
int
length;
58
struct
TSnakeNode
*
head;
59
enum
TDirection dir;
60
};
61
62
int
refreshgamew(WINDOW
*
win,
struct
TSnake
*
psnake);
63
void
movesnake(
struct
TSnake
*
psnake);
64
int
checksnake(
struct
TFood
*
pfood,
struct
TSnake
*
psnake);
65
void
snakegrowup(
struct
TFood
*
pfood,
struct
TSnake
*
psnake);
66
void
gameover(WINDOW
*
win,
char
*
str);
67
struct
TSnakeNode
*
newsnakenode(
struct
TSnakeNode
**
ppsnode,
int
y,
int
x);
68
WINDOW
*
newgamew();
69
struct
TSnake
*
initsnake();
70
void
destroysnake(
struct
TSnake
*
psnake);
71
void
drawsnakew(WINDOW
*
win,
struct
TSnake
*
psnake);
72
void
drawfoodw(WINDOW
*
win,
struct
TFood
*
pfood,
struct
TSnake
*
psnake);
73
TBool checkfood(
struct
TFood
*
pfood,
struct
TSnake
*
psnake);
74
WINDOW
*
newlogw();
75
void
runlog(WINDOW
*
win,
char
*
str);
76
void
cleanline(WINDOW
*
win,
int
y,
int
x);
77
78
int
main()
79
{
80
initscr();
81
raw();
82
noecho();
83
keypad(stdscr, TRUE);
84
curs_set(
0
);
85
refresh();
86
87
g_level
=
1
;
88
INITRUNLOG();
89
RUNLOG(
"
Press 'q' or 'Q' to quit.
"
);
90
RUNLOG(
"
Press 'w/s/a/d' or 'W/S/A/D' to move the snake.
"
);
91
RUNLOG(
"
Info:
"
);
92
93
WINDOW
*
gwin
=
newgamew();
94
struct
TSnake
*
psnake
=
initsnake();
95
drawsnakew(gwin, psnake);
96
97
while
(refreshgamew(gwin, psnake)
>=
0
) ;
98
99
getch();
100
101
destroysnake(psnake);
102
delwin(gwin);
103
DESTROYRUNLOG();
104
endwin();
105
106
return
0
;
107
}
108
109
int
refreshgamew(WINDOW
*
win,
struct
TSnake
*
psnake)
110
{
111
static
TBool ffood
=
False;
112
struct
TFood pfood;
113
114
if
(
!
ffood) {
115
drawfoodw(win,
&
pfood, psnake);
116
ffood
=
True;
117
}
118
119
int
key
=
-
1
;
120
121
fd_set
set
;
122
FD_ZERO(
&
set
);
123
FD_SET(
0
,
&
set
);
124
125
struct
timeval timeout;
126
timeout.tv_sec
=
0
;
127
timeout.tv_usec
=
(
6
-
(
int
)(g_level
/
3
))
*
100
*
1000
;
128
129
if
(select(
1
,
&
set
, NULL, NULL,
&
timeout)
<
0
)
130
return
-
1
;
131
132
if
(FD_ISSET(
0
,
&
set
)) {
133
while
((key
=
getch())
==
-
1
) ;
134
135
switch
(key) {
136
case
'
w
'
:
137
case
'
W
'
:
138
(psnake
->
dir
==
DIR_DOWN)
?
: (psnake
->
dir
=
DIR_UP);
139
break
;
140
141
case
'
s
'
:
142
case
'
S
'
:
143
(psnake
->
dir
==
DIR_UP)
?
: (psnake
->
dir
=
DIR_DOWN);
144
break
;
145
146
case
'
a
'
:
147
case
'
A
'
:
148
(psnake
->
dir
==
DIR_RIGHT)
?
: (psnake
->
dir
=
DIR_LEFT);
149
break
;
150
151
case
'
d
'
:
152
case
'
D
'
:
153
(psnake
->
dir
==
DIR_LEFT)
?
: (psnake
->
dir
=
DIR_RIGHT);
154
break
;
155
156
case
'
q
'
:
157
case
'
Q
'
:
158
RUNLOG(
"
Quit Game!
"
);
159
gameover(win,
"
Quit Game!
"
);
160
return
-
1
;
161
162
default
:
163
break
;
164
}
165
}
166
167
movesnake(psnake);
168
drawsnakew(win, psnake);
169
switch
(checksnake(
&
pfood, psnake)) {
170
case
0
:
171
break
;
172
173
case
1
:
174
ffood
=
False;
175
if
(
++
g_level
>
MAXLEVEL) {
176
RUNLOG(
"
Win!!!
"
);
177
gameover(win,
"
Win!!!
"
);
178
return
-
1
;
179
}
180
mvwprintw(win, GAMEWIN_YLEN
-
1
,
2
,
"
Level: %d
"
, g_level);
181
mvwprintw(win, GAMEWIN_YLEN
-
1
,
30
,
"
Speed: %d
"
, (
int
)(g_level
/
3
));
182
wrefresh(win);
183
RUNLOG(
"
Level UP!
"
);
184
snakegrowup(
&
pfood, psnake);
185
break
;
186
187
default
:
188
RUNLOG(
"
Game over!
"
);
189
gameover(win,
"
Game over!
"
);
190
return
-
1
;
191
}
192
193
return
1
;
194
}
195
196
/*
*
197
* stuct TSnake是一个倒置的首尾相连的链表,head->front指向snake的尾部
198
* 如: [a]
199
* | ^ snake移动的时候,只用head指向d,
200
* `--------------' 并且修改d的(y,x)为snake头移动到的位置.
201
*/
202
void
movesnake(
struct
TSnake
*
psnake)
203
{
204
int
hy
=
psnake
->
head
->
y;
205
int
hx
=
psnake
->
head
->
x;
206
207
psnake
->
head
=
GetSnakeTail(psnake);
208
209
switch
(psnake
->
dir) {
210
case
DIR_UP:
211
psnake
->
head
->
y
=
hy
-
1
;
212
psnake
->
head
->
x
=
hx;
213
break
;
214
215
case
DIR_DOWN:
216
psnake
->
head
->
y
=
hy
+
1
;
217
psnake
->
head
->
x
=
hx;
218
break
;
219
220
case
DIR_LEFT:
221
psnake
->
head
->
y
=
hy;
222
psnake
->
head
->
x
=
hx
-
1
;
223
break
;
224
225
case
DIR_RIGHT:
226
psnake
->
head
->
y
=
hy;
227
psnake
->
head
->
x
=
hx
+
1
;
228
break
;
229
230
default
:
231
break
;
232
}
233
}
234
235
int
checksnake(
struct
TFood
*
pfood,
struct
TSnake
*
psnake)
236
{
237
if
( psnake
->
head
->
y
<=
0
||
psnake
->
head
->
y
>=
GAMEWIN_YLEN
238
||
psnake
->
head
->
x
<=
0
||
psnake
->
head
->
x
>=
GAMEWIN_XLEN)
239
{
240
return
-
1
;
241
}
242
243
struct
TSnakeNode
*
pnode
=
GetSnakeTail(psnake);
244
int
i
=
0
;
245
for
(; i
<
psnake
->
length
-
1
;
++
i, pnode
=
pnode
->
front)
246
if
(psnake
->
head
->
y
==
pnode
->
y
&&
psnake
->
head
->
x
==
pnode
->
x)
247
return
-
1
;
248
249
if
(psnake
->
head
->
y
==
pfood
->
y
&&
psnake
->
head
->
x
==
pfood
->
x)
250
return
1
;
251
252
return
0
;
253
}
254
255
void
snakegrowup(
struct
TFood
*
pfood,
struct
TSnake
*
psnake)
256
{
257
struct
TSnakeNode
*
pnode
=
(
struct
TSnakeNode
*
)malloc(
sizeof
(
struct
TSnakeNode));
258
259
switch
(psnake
->
dir) {
260
case
DIR_UP:
261
pnode
->
y
=
psnake
->
head
->
y
-
1
;
262
pnode
->
x
=
psnake
->
head
->
x;
263
break
;
264
265
case
DIR_DOWN:
266
pnode
->
y
=
psnake
->
head
->
y
+
1
;
267
pnode
->
x
=
psnake
->
head
->
x;
268
break