本文转载
http://www.linuxidc.com/Linux/2011-08/41375.htm本文可以改进的就是它的链表实现的方式,可以考虑内核的链表实现
#include <stdio.h>
#include
<
stdlib.h
>
#include
<
curses.h
>
#include
<
signal.h
>
#include
<
sys
/
time.h
>
#define
NUM 60
struct
direct
//
用来表示方向的
{
int
cx;
int
cy;
};
typedef
struct
node
//
链表的结点
{
int
cx;
int
cy;
struct
node
*
back;
struct
node
*
next;
}node;
void
initGame();
//
初始化游戏
int
setTicker(
int
);
//
设置计时器
void
show();
//
显示整个画面
void
showInformation();
//
显示游戏信息(前两行)
void
showSnake();
//
显示蛇的身体
void
getOrder();
//
从键盘中获取命令
void
over(
int
i);
//
完成游戏结束后的提示信息
void
creatLink();
//
(带头尾结点)双向链表以及它的操作
void
insertNode(
int
x,
int
y);
void
deleteNode();
void
deleteLink();
int
ch;
//
输入的命令
int
hour, minute, second;
//
时分秒
int
length, tTime, level;
//
(蛇的)长度,计时器,(游戏)等级
struct
direct dir, food;
//
蛇的前进方向,食物的位置
node
*
head,
*
tail;
//
链表的头尾结点
int
main()
{
initscr();
initGame();
signal(SIGALRM, show);
getOrder();
endwin();
return
0
;
}
void
initGame()
{
cbreak();
//
把终端的CBREAK模式打开
noecho();
//
关闭回显
curs_set(
0
);
//
把光标置为不可见
keypad(stdscr,
true
);
//
使用用户终端的键盘上的小键盘
srand(time(
0
));
//
设置随机数种子
//
初始化各项数据
hour
=
minute
=
second
=
tTime
=
0
;
length
=
1
;
dir.cx
=
1
;
dir.cy
=
0
;
ch
=
'
A
'
;
food.cx
=
rand()
%
COLS;
food.cy
=
rand()
%
(LINES
-
2
)
+
2
;
creatLink();
setTicker(
20
);
}
//
设置计时器(这个函数是书本上的例子,有改动)
int
setTicker(
int
n_msecs)
{
struct
itimerval new_timeset;
long
n_sec, n_usecs;
n_sec
=
n_msecs
/
1000
;
n_usecs
=
( n_msecs
%
1000
)
*
1000L
;
new_timeset.it_interval.tv_sec
=
n_sec;
new_timeset.it_interval.tv_usec
=
n_usecs;
n_msecs
=
1
;
n_sec
=
n_msecs
/
1000
;
n_usecs
=
( n_msecs
%
1000
)
*
1000L
;
new_timeset.it_value.tv_sec
=
n_sec ;
new_timeset.it_value.tv_usec
=
n_usecs ;
return
setitimer(ITIMER_REAL,
&
new_timeset, NULL);
}
void
showInformation()
{
tTime
++
;
if
(tTime
>=
1000000
)
//
tTime
=
0
;
if
(
1
!=
tTime
%
50
)
return
;
move(
0
,
3
);
//
显示时间
printw(
"
time: %d:%d:%d %c
"
, hour, minute, second);
second
++
;
if
(second
>
NUM)
{
second
=
0
;
minute
++
;
}
if
(minute
>
NUM)
{
minute
=
0
;
hour
++
;
}
//
显示长度,等级
move(
1
,
0
);
int
i;
for
(i
=
0
;i
<
COLS;i
++
)
addstr(
"
-
"
);
move(
0
, COLS
/
2
-
5
);
printw(
"
length: %d
"
, length);
move(
0
, COLS
-
10
);
level
=
length
/
3
+
1
;
printw(
"
level: %d
"
, level);
}
//
蛇的表示是用一个带头尾结点的双向链表来表示的,
//
蛇的每一次前进,都是在链表的头部增加一个节点,在尾部删除一个节点
//
如果蛇吃了一个食物,那就不用删除节点了
void
showSnake()
{
if
(
1
!=
tTime
%
(
30
-
level))
return
;
//
判断蛇的长度有没有改变
bool
lenChange
=
false
;
//
显示食物
move(food.cy, food.cx);
printw(
"
@
"
);
//
如果蛇碰到墙,则游戏结束
if
((COLS
-
1
==
head
->
next
->
cx
&&
1
==
dir.cx)
||
(
0
==
head
->
next
->
cx
&&
-
1
==
dir.cx)
||
(LINES
-
1
==
head
->
next
->
cy
&&
1
==
dir.cy)
||
(
2
==
head
->
next
->
cy
&&
-
1
==
dir.cy))
{
over(
1
);
return
;
}
//
如果蛇头砬到自己的身体,则游戏结束
if
(
'
*
'
==
mvinch(head
->
next
->
cy
+
dir.cy, head
->
next
->
cx
+
dir.cx) )
{
over(
2
);
return
;
}
insertNode(head
->
next
->
cx
+
dir.cx, head
->
next
->
cy
+
dir.cy);
//
蛇吃了一个“食物”
if
(head
->
next
->
cx
==
food.cx
&&
head
->
next
->
cy
==
food.cy)
{
lenChange
=
true
;
length
++
;
//
恭喜你,通关了
if
(length
>=
50
)
{
over(
3
);
return
;
}
//
重新设置食物的位置
food.cx
=
rand()
%
COLS;
food.cy
=
rand()
%
(LINES
-
2
)
+
2
;
}
if
(
!
lenChange)
{
move(tail
->
back
->
cy, tail
->
back
->
cx);
printw(
"
"
);
deleteNode();
}
move(head
->
next
->
cy, head
->
next
->
cx);
printw(
"
*
"
);
}
void
show()
{
signal(SIGALRM, show);
//
设置中断信号
showInformation();
showSnake();
refresh();
//
刷新真实屏幕
}
void
getOrder()
{
//
建立一个死循环,来读取来自键盘的命令
while
(
1
)
{
ch
=
getch();
if
(KEY_LEFT
==
ch)
{
dir.cx
=
-
1
;
dir.cy
=
0
;
}
else
if
(KEY_UP
==
ch)
{
dir.cx
=
0
;
dir.cy
=
-
1
;
}
else
if
(KEY_RIGHT
==
ch)
{
dir.cx
=
1
;
dir.cy
=
0
;
}
else
if
(KEY_DOWN
==
ch)
{
dir.cx
=
0
;
dir.cy
=
1
;
}
setTicker(
20
);
}
}
void
over(
int
i)
{
//
显示结束原因
move(
0
,
0
);
int
j;
for
(j
=
0
;j
<
COLS;j
++
)
addstr(
"
"
);
move(
0
,
2
);
if
(
1
==
i)
addstr(
"
Crash the wall. Game over
"
);
else
if
(
2
==
i)
addstr(
"
Crash itself. Game over
"
);
else
if
(
3
==
i)
addstr(
"
Mission Complete
"
);
setTicker(
0
);
//
关闭计时器
deleteLink();
//
释放链表的空间
}
//
创建一个双向链表
void
creatLink()
{
node
*
temp
=
(node
*
)malloc(
sizeof
(node) );
head
=
(node
*
)malloc(
sizeof
(node) );
tail
=
(node
*
)malloc(
sizeof
(node) );
temp
->
cx
=
5
;
temp
->
cy
=
10
;
head
->
back
=
tail
->
next
=
NULL;
head
->
next
=
temp;
temp
->
next
=
tail;
tail
->
back
=
temp;
temp
->
back
=
head;
}
//
在链表的头部(非头结点)插入一个结点
void
insertNode(
int
x,
int
y)
{
node
*
temp
=
(node
*
)malloc(
sizeof
(node) );
temp
->
cx
=
x;
temp
->
cy
=
y;
temp
->
next
=
head
->
next;
head
->
next
=
temp;
temp
->
back
=
head;
temp
->
next
->
back
=
temp;
}
//
删除链表的(非尾结点的)最后一个结点
void
deleteNode()
{
node
*
temp
=
tail
->
back;
node
*
bTemp
=
temp
->
back;
bTemp
->
next
=
tail;
tail
->
back
=
bTemp;
temp
->
next
=
temp
->
back
=
NULL;
free(temp);
temp
=
NULL;
}
//
删除整个链表
void
deleteLink()
{
while
(head
->
next
!=
tail)
deleteNode();
head
->
next
=
tail
->
back
=
NULL;
free(head);
free(tail);
}