链表实现贪吃蛇
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>
#include <conio.h>
//蛇的状态
#define U 1 //上
#define D 2 //下
#define L 3 //左
#define R 4 //右
/*********** 全局变量 **********/
typedef struct SNAKE //蛇身的一个节点
{
int x;
int y;
struct SNAKE *next;
}snake;
int score = 0, add = 10; //总得分与每次吃食物得分
int status, sleeptime = 200; //蛇前进状态,每次运行的时间间隔
snake *head, *food; //蛇头指针, 食物指针
snake *q; //遍历蛇的时候用到的指针
int endgamestatus = 0;
/* 游戏结束的情况: 1.撞到墙 2.撞到自己 3.主动退出游戏 */
HANDLE hOut; //控制台句柄
/*********** 函数声明 **********/
void gotoxy(int x, int y); //设置光标位置
void mycolor(int c); //更改文字颜色
void createmap(); //绘制地图
void welcometogame(); //开始界面
void scoreandtips(); //游戏界面右侧得分和小提示
void initsnake(); //初始化蛇身,画蛇身
void createfood(); //创建并随机出现食物
int biteself(); //判断是否咬到了自己
void cantcrosswall(); //设置蛇撞墙的情况
void speedup(); //加速
void speeddown(); //减速
void snakemove(); //控制蛇前进方向
void keyboardcontrol(); //控制键盘按键
void lostdraw(); //游戏结束界面
void endgame(); //游戏结束
void choose(); //游戏失败之后的选择
void explation(); //游戏说明
/**********************************/
int main(void)
{
system("mode con cols=100 lines=30"); //设置控制台宽高
welcometogame();
keyboardcontrol();
endgame();
getchar();
return 0;
}
//设置光标位置
void gotoxy(int x, int y)
{
COORD c;
c.X = x;
c.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c);
}
//更改文字颜色
void mycolor(int c)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c);
return 0;
}
//绘制地图
void createmap()
{
int i, j;
for (i = 0; i < 58; i += 2) //打印上下边框
{
gotoxy(i, 0);
mycolor(5);
printf("□");
gotoxy(i, 26);
printf("□");
}
for (i = 1; i < 26; i++) //打印左右边框
{
gotoxy(0, i);
printf("□");
gotoxy(56, i);
printf("□");
}
for (i = 2; i < 56; i += 2) //打印中间网格
{
for (j = 1; j < 26; j++)
{
gotoxy(i, j);
mycolor(3);
printf("■");
}
}
}
//开始界面
void welcometogame()
{
int n;
gotoxy(43, 10);
mycolor(11);
printf("贪 吃 蛇 大 作 战");
mycolor(12);
gotoxy(25, 22);
printf("1.开始游戏");
gotoxy(45, 22);
printf("2.游戏说明");
gotoxy(65, 22);
printf("3.退出游戏");
gotoxy(40, 27);
mycolor(3);
printf("请选择 1 2 3:");
mycolor(14);
scanf("%d", &n);
switch ( n )
{
case 1:
system("cls");
createmap(); //创建食物
initsnake(); //初始化蛇身
createfood(); //创建食物
keyboardcontrol(); //按键控制
break;
case 2:
explation();
break;
case 3:
exit(0);
break;
default:
mycolor(12);
gotoxy(40, 28);
printf("请输入1-3之间的数!");
getchar();
system("cls");
welcometogame();
}
}
//游戏界面右侧得分和小提示
void scoreandtips()
{
gotoxy(64, 8);
mycolor(14);
printf("得分: %d", score);
gotoxy(64, 14);
printf("每个食物得分: %d 分", add);
gotoxy(64, 16);
printf("不能穿墙,不能咬到自己");
gotoxy(64, 18);
printf("用↑ ↓ ← →分别控制蛇的移动");
gotoxy(64, 20);
printf("F1为加速,F2为减速");
gotoxy(64, 22);
printf("space:暂停游戏");
gotoxy(64, 24);
printf("ESC: 退出游戏");
}
//初始化蛇身,画蛇身
void initsnake()
{
snake *tail;
int i;
//从蛇尾开始,头插法,以x,y设定开始的位置
tail = (snake *)malloc(sizeof(snake));
tail->x = 24;
tail->y = 5;
tail->next = NULL;
for (i = 1; i <= 3; i++) //设置蛇身,长度为3
{
head = (snake *)malloc(sizeof(snake)); //初始化蛇头
head->next = tail;
head->x = 24 + 2 * i;
head->y = 5;
tail = head; //蛇头变蛇尾,重复循环
}
while ( tail != NULL )
{
gotoxy(tail->x, tail->y);
mycolor(14);
printf("★"); //输出蛇身
tail = tail->next;
}
}
//创建并随机出现食物
void createfood()
{
snake *food1 = NULL;
srand((unsigned)time(NULL));
food1 = (snake *)malloc(sizeof(snake));
if ( !food1 )
{
exit(1);
}
//保证为偶数,使食物能与蛇头对齐,然后食物会出现在网格线上
while ( (food1->x % 2) != 0 )
{
food1->x = rand() % 52 + 2; //食物随机出现
}
food1->y = rand() % 24 + 1;
q = head;
while ( q->next == NULL )
{
//判断蛇身是否与食物生命
if (q->x == food1->x && q->y == food1->y)
{
free(food1); //如果重合,那么释放食物指针
createfood(); //重新创建食物
}
q = q->next;
}
gotoxy(food1->x, food1->y);
food = food1;
mycolor(12);
printf("●"); //输出食物
}
//判断是否咬到了自己
int biteself()
{
snake *self; //定义self为蛇身上的一个结点
self = head->next; //self是蛇头之外的蛇身上的结点
while ( self != NULL )
{
//如果self和蛇身上的结点重合
if (self->x == head->x && self->y == head->y)
{
return 1;
}
self = self->next;
}
return 0;
}
//设置蛇撞墙的情况
void cantcrosswall()
{
//如果蛇头碰到了墙壁
if (head->x == 0 || head->x == 56 || head->y == 0 || head->y == 26)
{
endgamestatus = 1; //返回第一种情况
endgame(); //出现游戏结束界面
}
}
//加速,蛇吃到食物会自动提速,并且按F1会加速
void speedup()
{
if (sleeptime >= 50)
{
sleeptime = sleeptime - 10;
add = add + 10;
}
}
//减速
void speeddown()
{
if (sleeptime < 350) //如果时间间隔小于350
{
sleeptime = sleeptime + 30; //时间间隔加上30
add = add - 5; //每吃一次食物的得分减5
}
}
//控制蛇前进方向
void snakemove()
{
snake *nexthead;
cantcrosswall();
nexthead = (snake *)malloc(sizeof(snake));
if ( !nexthead )
{
exit(1);
}
if (status == U)
{
nexthead->x = head->x; //向上前进时,x坐标不变,y坐标-1
nexthead->y = head->y - 1;
nexthead->next = head;
head = nexthead;
q = head; //指针q指向蛇头
//如果下一个有食物下一个位置的坐标和食物的坐标相同
if (nexthead->x == food->x && nexthead->y == food->y)
{
while ( q != NULL )
{
gotoxy(q->x, q->y);
mycolor(14);
printf("★"); //原来食物的位置,从●换成★,表示吃掉了
q = q->next;
}
score += add; //吃一个食物,总分加10
speedup(); //加速
createfood(); //创建食物
}
else
{
while ( q->next->next != NULL ) //如果没遇到食物
{
gotoxy(q->x, q->y);
mycolor(14);
printf("★"); //蛇正常往前走,输出当前位置的蛇身
q = q->next; //继续输出整个蛇身
}
//经过上面的循环,q指向蛇尾,蛇尾的下一位就是蛇走过去的位置
gotoxy(q->next->x, q->next->y);
mycolor(3);
printf("■");
free(q->next); //输出■后,释放指向下一位的指针
q->next = NULL;
}
}
if ( status == D )
{
nexthead->x = head->x; //向下前进时,x坐标不变,y坐标+1
nexthead->y = head->y + 1;
nexthead->next = head;
head = nexthead;
q = head; //指针q指向蛇头
//有食物
if ( nexthead->x == food->x && nexthead->y == food->y )
{
while ( q != NULL )
{
gotoxy(q->x, q->y);
mycolor(14);
printf("★"); //原来食物的位置,从●换成★,表示吃掉了
q = q->next;
}
score += add; //吃一个食物,总分加10
speedup(); //加速
createfood(); //创建食物
}
else //没有食物
{
while ( q->next->next != NULL )
{
gotoxy(q->x, q->y);
mycolor(14);
printf("★"); //蛇正常往前走,输出当前位置的蛇身
q = q->next; //继续输出整个蛇身
}
//经过上面的循环,q指向蛇尾,蛇尾的下一位就是蛇走过去的位置
gotoxy(q->next->x, q->next->y);
mycolor(3);
printf("■");
free(q->next); //输出■后,释放指向下一位的指针
q->next = NULL;
}
}
if ( status == L )
{
nexthead->x = head->x - 2; //向左前进时,x坐标-2,y坐标不变
nexthead->y = head->y;
nexthead->next = head;
head = nexthead;
q = head; //指针q指向蛇头
//如果下一个有食物下一个位置的坐标和食物的坐标相同
if ( nexthead->x == food->x && nexthead->y == food->y )
{
while ( q != NULL )
{
gotoxy(q->x, q->y);
mycolor(14);
printf("★"); //原来食物的位置,从●换成★,表示吃掉了
q = q->next;
}
score += add; //吃一个食物,总分加10
speedup(); //加速
createfood(); //创建食物
}
else
{
while ( q->next->next != NULL ) //如果没遇到食物
{
gotoxy(q->x, q->y);
mycolor(14);
printf("★"); //蛇正常往前走,输出当前位置的蛇身
q = q->next; //继续输出整个蛇身
}
//经过上面的循环,q指向蛇尾,蛇尾的下一位就是蛇走过去的位置
gotoxy(q->next->x, q->next->y);
mycolor(3);
printf("■");
free(q->next); //输出■后,释放指向下一位的指针
q->next = NULL;
}
}
if ( status == R )
{
nexthead->x = head->x + 2; //向右前进时,x坐标+2,y坐标不变
nexthead->y = head->y;
nexthead->next = head;
head = nexthead;
q = head; //指针q指向蛇头
//有食物
if ( nexthead->x == food->x && nexthead->y == food->y )
{
while ( q != NULL )
{
gotoxy(q->x, q->y);
mycolor(14);
printf("★"); //原来食物的位置,从●换成★,表示吃掉了
q = q->next;
}
score += add; //吃一个食物,总分加10
speedup(); //加速
createfood(); //创建食物
}
else //没有食物
{
while ( q->next->next != NULL )
{
gotoxy(q->x, q->y);
mycolor(14);
printf("★"); //蛇正常往前走,输出当前位置的蛇身
q = q->next; //继续输出整个蛇身
}
//经过上面的循环,q指向蛇尾,蛇尾的下一位就是蛇走过去的位置
gotoxy(q->next->x, q->next->y);
mycolor(3);
printf("■");
free(q->next); //输出■后,释放指向下一位的指针
q->next = NULL;
}
}
if (biteself() == 1) //判断是否会咬到自己
{
endgamestatus = 2;
endgame();
}
}
//控制键盘按键
void keyboardcontrol()
{
status = R; //初始蛇向右移动
while ( 1 )
{
scoreandtips();
if (GetAsyncKeyState(VK_UP) && status != D)
{
//如果蛇不是向下前进的时候,按上键,执行向上操作
status = U;
}
else if ( GetAsyncKeyState(VK_DOWN) && status != U )
{
status = D;
}
else if (GetAsyncKeyState(VK_LEFT) && status != R )
{
status = L;
}
else if (GetAsyncKeyState(VK_RIGHT) && status != L)
{
status = R;
}
if (GetAsyncKeyState(VK_SPACE)) //执行暂停
{
while ( 1 )
{
Sleep(300);
if (GetAsyncKeyState(VK_SPACE))
{
break;
}
}
}
else if (GetAsyncKeyState(VK_ESCAPE)) //按esc结束
{
endgamestatus = 3;
break;
}
else if (GetAsyncKeyState(VK_F1))
{
speedup();
}
else if (GetAsyncKeyState(VK_F2))
{
speeddown();
}
Sleep(sleeptime);
snakemove();
}
}
//游戏说明
void explation()
{
system("cls");
mycolor(3);
gotoxy(30, 8);
printf("1.不能穿墙,不能咬到自己");
mycolor(10);
gotoxy(30, 11);
printf("2. 用↑.↓.←.→分别控制蛇的移动");
mycolor(14);
gotoxy(30, 14);
printf("3. F1为加速,F2为减速");
mycolor(11);
gotoxy(30, 17);
printf("4. 按空格键暂停游戏,再按空格键继续");
mycolor(4);
gotoxy(30, 20);
printf("5. ESC: 退出游戏 SPACE: 暂停游戏");
getchar();
getchar();
system("cls");
welcometogame();
}
//游戏结束
void endgame()
{
system("cls");
if (endgamestatus == 1)
{
lostdraw();
gotoxy(43, 9);
mycolor(12);
printf("GAME OVER !");
}
else if (endgamestatus == 2)
{
gotoxy(43, 9);
mycolor(12);
printf("GAME OVER !");
}
else if (endgamestatus == 3)
{
gotoxy(40, 9);
mycolor(12);
printf("已结束游戏。");
}
gotoxy(43, 12);
mycolor(13);
printf("你的得分是 %d", score);
choose();
}
//游戏失败之后的选择
void choose()
{
int n;
gotoxy(25, 23);
mycolor(12);
printf("继续 ----- 1");
gotoxy(52, 23);
printf("离开 ----- 2");
gotoxy(45, 25);
mycolor(11);
printf("选择: ");
scanf("%d", &n);
switch ( n )
{
case 1:
system("cls");
score = 0;
sleeptime = 200;
add = 10;
welcometogame();
break;
case 2:
exit(0);
break;
default:
gotoxy(35, 27);
mycolor(12);
printf("输入错误,重新输入!");
system("pause >nul");
endgame();
choose();
break;
}
}
//游戏结束界面
void lostdraw()
{
system("cls");
int i;
gotoxy(45, 2);
mycolor(6);
printf("\\\\\\|///");
gotoxy(43, 3);
printf("\\\\");
gotoxy(47, 3);
mycolor(15);
printf(".-.-");
gotoxy(54, 3);
mycolor(6);
printf("//");
gotoxy(44, 4);
mycolor(14);
printf("(");
gotoxy(47, 4);
mycolor(15);
printf(".@.@");
gotoxy(54, 4);
mycolor(14);
printf(")");
gotoxy(17, 5);
mycolor(11);
printf("+------------------------");
gotoxy(35, 5);
mycolor(14);
printf("oOOo");
gotoxy(39, 5);
mycolor(11);
printf("----------");
gotoxy(48, 5);
mycolor(14);
printf("(_)");
gotoxy(51, 5);
mycolor(11);
printf("----------");
gotoxy(61, 5);
mycolor(14);
printf("oOOo");
gotoxy(65, 5);
mycolor(11);
printf("-----------------+");
for ( i = 6; i <= 19; i++ ) //竖边框
{
gotoxy(17, i);
printf("|");
gotoxy(82, i);
printf("|");
}
gotoxy(17, 20);
printf("+---------------------------------");
gotoxy(52, 20);
mycolor(14);
printf("☆☆☆〃");
gotoxy(60, 20);
mycolor(11);
printf("----------------------+");
}