贪吃蛇——c语言版

文章目录

  • 演示效果
  • 实现的基本功能
  • 技术要点
  • 源代码
  • 实现功能
    • GameStart
      • 打印欢迎界面和功能介绍
      • 绘制地图
      • 创建蛇
      • 创建食物
    • GameRun
      • 打印提示信息
      • 蛇每走一步
    • GameEnd
    • 蛇死亡后继续游戏

演示效果

贪吃蛇1.0演示视频


在这里插入图片描述
将终端应用程序改为控制台主机

实现的基本功能

  1. 贪吃蛇地图绘制
  2. 蛇吃食物的功能(上、下、左、右⽅向键控制蛇的动作)
  3. 蛇撞墙死亡
  4. 蛇撞⾃⾝死亡
  5. 计算得分
  6. 蛇⾝加速、减速
  7. 暂停游戏

技术要点

c语言函数、枚举、结构体、动态内存管理、预处理指令、链表、Win32 API等等……

源代码

snake.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <locale.h>
#include <stdbool.h>
#include <time.h>
#include <stdbool.h>
#define KEY_PRESS(vk) ((GetAsyncKeyState(vk)&1)?1:0)
#define WALL L'□'
#define BODY L'●'
#define FOOD L'★'
#define POS_X 24
#define POS_Y 5
enum DIRECTION
{
	UP = 1,
	DOWN,
	LEFT,
	RIGHT
};
enum CONDITION
{ 
	OK,
	KILL_BY_WALL,
	KILL_BY_SELF,
	END_NORMAL
};
typedef struct SnakeNode
{
	int x;
	int y;
	struct SnakeNode* next;
}SnakeNode,* pSnakeNode;
typedef struct Snake
{
	pSnakeNode pSnakebody;//指向蛇头的节点
	pSnakeNode pFood;//指向食物的节点
	enum DIRECTION Dir;//方向
	enum CONDITION Cdt;//状态
	int Food_Weight;//食物的权重
	int Socre;//总分数
	int Sleep_Time;//睡眠时间
}Snake,* pSnake;
//初始化
void GameStart(pSnake ps);
//定位
void SetPos(short x, short y);
//打印欢迎界面和功能介绍
void  Welcome_To_Game();
//绘制地图
void CreateMap();
//创建蛇
void InitSnake(pSnake ps);
//创建食物
void CreateFood(pSnake ps);
//运行游戏
void GameRun(pSnake ps);
//打印提示信息
void PrintHelpInfo();
//蛇走的过程
void SnakeMove(pSnake ps);
//判断下一个节点是不是食物
bool NextIsFood(pSnakeNode pn,pSnake ps);
//如果是食物,就吃掉,然后创建新的食物
void EatFood(pSnakeNode pn,pSnake ps);
//如果不是食物,就把最后一个节点释放
void NotFood(pSnakeNode pn, pSnake ps);
//判断下一步是否撞墙
void KillByWall(pSnake ps);
//判断下一步是否撞到自己
void KillBySelf(pSnake ps);
//善后工作
void GameEnd(pSnake ps);

snake.c

#define   _CRT_SECURE_NO_WARNINGS 1
#include "Snake.h"
void CreateFood(pSnake ps)
{
	int x = 0;
	int y = 0;
	//食物的坐标在棋盘内
again:
	do
	{
		x = rand() % 53 + 2;
		y = rand() % 25 + 1;
	} while (x % 2 != 0);
	//食物不能和蛇身冲突
	pSnakeNode cur = ps->pSnakebody;
	while (cur)
	{
		if (cur->x == x && cur->y == y)
		{
			goto again;
		}
		cur = cur->next;
	}
	//创建食物
	pSnakeNode Food = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (Food == NULL)
	{
		perror("malloc fail");
		return;
	}
	Food->next = NULL;
	Food->x = x;
	Food->y = y;
	SetPos(x, y);
	wprintf(L"%lc", FOOD);
	ps->pFood = Food;
}
void SetPos(short x, short y)
{
	HANDLE houtput = NULL;
	houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos = { x,y };
	SetConsoleCursorPosition(houtput, pos);
}
void InitSnake(pSnake ps)
{
	ps->pSnakebody = NULL;
	pSnakeNode cur = NULL;
	for (int i = 0; i < 5; i++)
	{
		//创建蛇身节点
		cur = (pSnakeNode)malloc(sizeof(SnakeNode));
		if (cur == NULL)
		{
			perror("malloc fail");
			return;
		}
		//设置坐标
		cur->next = NULL;
		cur->x = POS_X + i * 2;
		cur->y = POS_Y;
		//头插
		if (ps->pSnakebody == NULL)
		{
			ps->pSnakebody = cur;
		}
		else
		{
			cur->next = ps->pSnakebody;
			ps->pSnakebody = cur;
		}
	}
	//打印身体
	cur = ps->pSnakebody;
	while (cur)
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	//初始化贪吃蛇的数据
	ps->Cdt = OK;
	ps->Dir = RIGHT;
	ps->Food_Weight = 10;
	ps->Socre = 0;
	ps->Sleep_Time = 200;//单位毫秒
}

void CreateMap()
{
	int i = 0;
	//上
	for (i = 0; i < 29; i++)
	{
		wprintf(L"%lc", WALL);
	}
	//下
	SetPos(0, 26);
	for (i = 0; i < 29; i++)
	{
		wprintf(L"%lc", WALL);
	}
	//左
	for (i = 1; i <= 25; i++)
	{
		SetPos(0, i);
		wprintf(L"%lc", WALL);
	}
	//右
	for (i = 1; i <= 25; i++)
	{
		SetPos(56, i);
		wprintf(L"%lc", WALL);
	}
	
}


void Welcome_To_Game()
{
	SetPos(40, 14);
	printf("欢迎来到贪食蛇小游戏");
	SetPos(40, 25);
	system("pause");
	system("cls");
	SetPos(25, 14);
	printf("用↑ . ↓ . ← . → 分别控制蛇的移动,F1为加速,");
	SetPos(25, 15);
	printf("F2为减速,加速将得到更高的分数");
	SetPos(40, 24);
	system("pause");
	system("cls");
}
void GameStart(pSnake ps)
{
	system("mode con cols=100 lines=30");
	system("title 贪吃蛇");
	//获取标准输出设备的句柄
	HANDLE houtput = NULL;
	houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	//定义光标信息结构体
	CONSOLE_CURSOR_INFO CursorInfo;
	//获取光标信息
	GetConsoleCursorInfo(houtput, &CursorInfo);
	//修改
	CursorInfo.bVisible = false;
	//设置
	SetConsoleCursorInfo(houtput, &CursorInfo);
	//打印欢迎界面和功能介绍
	Welcome_To_Game();
	//绘制地图
	CreateMap();
	//创建蛇
	InitSnake(ps);
	//创建食物
	CreateFood(ps);
}
//打印提示信息
void PrintHelpInfo()
{
	SetPos(60, 15);
	printf("不能穿墙,不能咬到自己");
	SetPos(60, 16);
	printf("用 ↑.↓.←.→ 分别控制蛇的移动,");
	SetPos(60, 17);
	printf("F1为加速,F2为减速,加速将得到更高的分数");
	SetPos(60, 18);
	printf("ESC:退出游戏,SPACE:暂停游戏");
	SetPos(60, 20);
	printf("我爱吃福鼎肉片@版权");
}
//暂停
void pause()
{
	while (1)
	{
		Sleep(300);
		if (KEY_PRESS(VK_SPACE))
		{
			break;
		}
	}
}
//判断下一个节点是不是食物
bool NextIsFood(pSnakeNode pn, pSnake ps)
{
	return (pn->x == ps->pFood->x && pn->y == ps->pFood->y);
}
//如果是食物,就吃掉,然后创建新的食物
void EatFood(pSnakeNode pn, pSnake ps)
{
	//头插
	ps->pFood->next = ps->pSnakebody;
	ps->pSnakebody = ps->pFood;
	//释放下一个位置的节点
	free(pn);
	pn = NULL;
	//打印
	pSnakeNode cur = ps->pSnakebody;
	while (cur)
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	ps->Socre += ps->Food_Weight;
	CreateFood(ps);
}
//如果不是食物,就把最后一个节点释放
void NotFood(pSnakeNode pn, pSnake ps)
{
	//头插
	pn->next = ps->pSnakebody;
	ps->pSnakebody = pn;
	//最后一个节点,要释放
	pSnakeNode cur = ps->pSnakebody;
	while (cur->next->next)//打印前n个
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	//释放最后一个
	SetPos(cur->next->x, cur->next->y);
	printf("  ");
	free(cur->next);
	cur->next = NULL;
}
//判断下一步是否撞墙
void KillByWall(pSnake ps)
{
	if (ps->pSnakebody->x == 56
		|| ps->pSnakebody->x == 0
		|| ps->pSnakebody->y == 0
		|| ps->pSnakebody->y == 26)
	{
		ps->Cdt = KILL_BY_WALL;
	}
}
//判断下一步是否撞到自己
void KillBySelf(pSnake ps)
{
	pSnakeNode cur = ps->pSnakebody->next;
	while (cur)
	{
		if (cur->x == ps->pSnakebody->x && cur->y == ps->pSnakebody->y)
		{
			ps->Cdt = KILL_BY_SELF;
		}
		cur = cur->next;
	}
}
//蛇走的过程
void SnakeMove(pSnake ps)
{
	//创建下一个节点
	pSnakeNode pNextNode = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (pNextNode == NULL)
	{
		perror("pNextNode malloc fail");
		return;
	}
	switch (ps->Dir)
	{
	case UP://向上
		pNextNode->x = ps->pSnakebody->x;
		pNextNode->y = ps->pSnakebody->y - 1;
		break;
	case DOWN://向下
		pNextNode->x = ps->pSnakebody->x;
		pNextNode->y = ps->pSnakebody->y + 1;
		break;
	case LEFT://向左
		pNextNode->x = ps->pSnakebody->x - 2;
		pNextNode->y = ps->pSnakebody->y;
		break;
	case RIGHT://向右
		pNextNode->x = ps->pSnakebody->x + 2;
		pNextNode->y = ps->pSnakebody->y;
		break;
	}
	//判断下一个节点是不是食物
	if (NextIsFood(pNextNode, ps))
	{
		EatFood(pNextNode, ps);
	}
	else
	{
		NotFood(pNextNode, ps);
	}
	KillByWall(ps);//下一步是墙
	KillBySelf(ps);//下一步是自己

}

//运行游戏
void GameRun(pSnake ps)
{
	PrintHelpInfo();
	do
	{
		SetPos(60, 10);
		printf("食物分数:%2d", ps->Food_Weight);
		SetPos(60, 11);
		printf("总分数:%2d", ps->Socre);
		if (KEY_PRESS(VK_UP) && ps->Dir != DOWN)
		{
			ps->Dir = UP;
		}
		else if (KEY_PRESS(VK_DOWN) && ps->Dir != UP)
		{
			ps->Dir = DOWN;
		}
		else if (KEY_PRESS(VK_LEFT) && ps->Dir != RIGHT)
		{
			ps->Dir = LEFT;
		}
		else if (KEY_PRESS(VK_RIGHT) && ps->Dir != LEFT)
		{
			ps->Dir = RIGHT;
		}
		else if (KEY_PRESS(VK_ESCAPE))
		{
			ps->Cdt = END_NORMAL;
			break;
		}
		else if (KEY_PRESS(VK_SPACE))
		{
			pause();
		}
		else if (KEY_PRESS(VK_F1))
		{
			if (ps->Sleep_Time > 80)
			{
				ps->Sleep_Time -= 30;
				ps->Food_Weight += 2;
			}
		}
		else if (KEY_PRESS(VK_F2))
		{
			if (ps->Sleep_Time < 320)
			{
				ps->Sleep_Time += 30;
				ps->Food_Weight -= 2;
			}
		}
		//让蛇走起来
		SnakeMove(ps);
		Sleep(ps->Sleep_Time);
	} while (ps->Cdt == OK);
	
}
//善后工作
void GameEnd(pSnake ps)
{
	SetPos(20, 12);
	switch (ps->Cdt)
	{
	case END_NORMAL:
		printf("您主动结束了游戏");
		break;
	case KILL_BY_WALL:
		printf("您撞到墙死了");
		break;
	case KILL_BY_SELF:
		printf("您咬到了自己");
	}
	//释放蛇身节点
	pSnakeNode cur = ps->pSnakebody;
	while (cur)
	{
		pSnakeNode del = cur;
		cur = cur->next;
		free(del);
	}
}

snaketest.c

#define   _CRT_SECURE_NO_WARNINGS 1
#include "Snake.h"

void test()
{
	int ch = 0;
	do
	{
		system("cls");
		Snake snake;
		GameStart(&snake);
		GameRun(&snake);
		GameEnd(&snake);
		SetPos(20, 14);
		printf("再来一局吗?(Y/N):");
		ch = getchar();
		while (getchar() != '\n');
	} while (ch == 'Y' || ch == 'y');
	SetPos(0, 27);
}
int main()
{
	//创建贪吃蛇
	setlocale(LC_ALL, "");
	srand((unsigned int)time(NULL));
	test();
	return 0;
	//初始化游戏
	//运行游戏
	//结束游戏
}

实现功能

在地图上我们打印墙体、蛇、食物都是使用宽字符,普通字符只占字节,宽字符占两个
中文也是两个宽字符,所以我们本地化所有类项即可

setlocale(LC_ALL, "");

再实现功能以前,我们可以将要实现的功能分成三大类:
GameStart(初始化游戏)
GameRun(运行游戏)
GameEnd(游戏善后工作)

GameStart

再绘制地图以前,我们需要设置控制台窗口的长宽:100列,30行
顺便设置窗口的名字为贪吃蛇

void GameStart(pSnake ps)
{
	system("mode con cols=100 lines=30");
	system("title 贪吃蛇");
}

隐藏光标并且获得句柄

void GameStart(pSnake ps)
{
	system("mode con cols=100 lines=30");
	system("title 贪吃蛇");
	//获取标准输出设备的句柄
	HANDLE houtput = NULL;
	houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	//定义光标信息结构体
	CONSOLE_CURSOR_INFO CursorInfo;
	//获取光标信息
	GetConsoleCursorInfo(houtput, &CursorInfo);
	//修改
	CursorInfo.bVisible = false;
	//设置
	SetConsoleCursorInfo(houtput, &CursorInfo);
}

修改光标位置

void SetPos(short x, short y)
{
	HANDLE houtput = NULL;
	houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos = { x,y };
	SetConsoleCursorPosition(houtput, pos);
}

打印欢迎界面和功能介绍

前面提到如何定位光标位置,在每一页打印完以后暂停,并且清理该页,才会接着打印下一页

void Welcome_To_Game()
{
	SetPos(40, 14);
	printf("欢迎来到贪食蛇小游戏");
	SetPos(40, 25);
	system("pause");
	system("cls");
	SetPos(25, 14);
	printf("用↑ . ↓ . ← . → 分别控制蛇的移动,F1为加速,");
	SetPos(25, 15);
	printf("F2为减速,加速将得到更高的分数");
	SetPos(40, 24);
	system("pause");
	system("cls");
}

绘制地图

因为在后续功能中经常要用到各种图案,我们就统一在头文件里定义好

#define WALL L'□'
#define BODY L'●'
#define FOOD L'★'
void CreateMap()
{
	int i = 0;
	//上
	for (i = 0; i < 29; i++)
	{
		wprintf(L"%lc", WALL);
	}
	//下
	SetPos(0, 26);
	for (i = 0; i < 29; i++)
	{
		wprintf(L"%lc", WALL);
	}
	//左
	for (i = 1; i <= 25; i++)
	{
		SetPos(0, i);
		wprintf(L"%lc", WALL);
	}
	//右
	for (i = 1; i <= 25; i++)
	{
		SetPos(56, i);
		wprintf(L"%lc", WALL);
	}
	
}

创建蛇

#define POS_X 24
#define POS_Y 5
void InitSnake(pSnake ps)
{
	ps->pSnakebody = NULL;
	pSnakeNode cur = NULL;
	for (int i = 0; i < 5; i++)
	{
		//创建蛇身节点
		cur = (pSnakeNode)malloc(sizeof(SnakeNode));
		if (cur == NULL)
		{
			perror("malloc fail");
			return;
		}
		//设置坐标
		cur->next = NULL;
		cur->x = POS_X + i * 2;
		cur->y = POS_Y;
		//头插
		if (ps->pSnakebody == NULL)
		{
			ps->pSnakebody = cur;
		}
		else
		{
			cur->next = ps->pSnakebody;
			ps->pSnakebody = cur;
		}
	}
	//打印身体
	cur = ps->pSnakebody;
	while (cur)
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	//初始化贪吃蛇的数据
	ps->Cdt = OK;
	ps->Dir = RIGHT;
	ps->Food_Weight = 10;
	ps->Socre = 0;
	ps->Sleep_Time = 200;//单位毫秒
}

创建食物

棋盘大小:
在这里插入图片描述
要注意食物的范围

void CreateFood(pSnake ps)
{
	int x = 0;
	int y = 0;
	//食物的坐标在棋盘内随机生成
again:
	do
	{
		x = rand() % 53 + 2;
		y = rand() % 25 + 1;
	} while (x % 2 != 0);
	//食物不能和蛇身冲突
	pSnakeNode cur = ps->pSnakebody;
	while (cur)
	{
		if (cur->x == x && cur->y == y)
		{
			goto again;
		}
		cur = cur->next;
	}
	//创建食物
	pSnakeNode Food = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (Food == NULL)
	{
		perror("malloc fail");
		return;
	}
	Food->next = NULL;
	Food->x = x;
	Food->y = y;
	SetPos(x, y);
	wprintf(L"%lc", FOOD);
	ps->pFood = Food;
}

GameRun

打印提示信息

在这里插入图片描述

//打印提示信息
void PrintHelpInfo()
{
	SetPos(60, 15);
	printf("不能穿墙,不能咬到自己");
	SetPos(60, 16);
	printf("用 ↑.↓.←.→ 分别控制蛇的移动,");
	SetPos(60, 17);
	printf("F1为加速,F2为减速,加速将得到更高的分数");
	SetPos(60, 18);
	printf("ESC:退出游戏,SPACE:暂停游戏");
	SetPos(60, 20);
	printf("我爱吃福鼎肉片@版权");
}

蛇每走一步

当蛇正在向某个方向走时,不能操控蛇走相反方向!

#define KEY_PRESS(vk) ((GetAsyncKeyState(vk)&1)?1:0)
//运行游戏
void GameRun(pSnake ps)
{
	PrintHelpInfo();
	do
	{
		SetPos(60, 10);
		printf("食物分数:%2d", ps->Food_Weight);
		SetPos(60, 11);
		printf("总分数:%2d", ps->Socre);
		if (KEY_PRESS(VK_UP) && ps->Dir != DOWN)
		{
			ps->Dir = UP;
		}
		else if (KEY_PRESS(VK_DOWN) && ps->Dir != UP)
		{
			ps->Dir = DOWN;
		}
		else if (KEY_PRESS(VK_LEFT) && ps->Dir != RIGHT)
		{
			ps->Dir = LEFT;
		}
		else if (KEY_PRESS(VK_RIGHT) && ps->Dir != LEFT)
		{
			ps->Dir = RIGHT;
		}
		else if (KEY_PRESS(VK_ESCAPE))
		{
			ps->Cdt = END_NORMAL;
			break;
		}
		else if (KEY_PRESS(VK_SPACE))
		{
			pause();
		}
		else if (KEY_PRESS(VK_F1))
		{
			if (ps->Sleep_Time > 80)
			{
				ps->Sleep_Time -= 30;
				ps->Food_Weight += 2;
			}
		}
		else if (KEY_PRESS(VK_F2))
		{
			if (ps->Sleep_Time < 320)
			{
				ps->Sleep_Time += 30;
				ps->Food_Weight -= 2;
			}
		}
		//让蛇走起来
		SnakeMove(ps);
		Sleep(ps->Sleep_Time);
	} while (ps->Cdt == OK);//状态为OK才能走
	
}

当蛇走向下一个节点时,要分为两种情况

  1. 下个节点是食物
  2. 下个节点不是食物
//蛇走的过程
void SnakeMove(pSnake ps)
{
	//创建下一个节点
	pSnakeNode pNextNode = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (pNextNode == NULL)
	{
		perror("pNextNode malloc fail");
		return;
	}
	switch (ps->Dir)
	{
	case UP://向上
		pNextNode->x = ps->pSnakebody->x;
		pNextNode->y = ps->pSnakebody->y - 1;
		break;
	case DOWN://向下
		pNextNode->x = ps->pSnakebody->x;
		pNextNode->y = ps->pSnakebody->y + 1;
		break;
	case LEFT://向左
		pNextNode->x = ps->pSnakebody->x - 2;
		pNextNode->y = ps->pSnakebody->y;
		break;
	case RIGHT://向右
		pNextNode->x = ps->pSnakebody->x + 2;
		pNextNode->y = ps->pSnakebody->y;
		break;
	}
	//判断下一个节点是不是食物
	if (NextIsFood(pNextNode, ps))
	{
		EatFood(pNextNode, ps);
	}
	else
	{
		NotFood(pNextNode, ps);
	}
	KillByWall(ps);//下一步是墙
	KillBySelf(ps);//下一步是自己

}
  1. 下个节点是食物
    先判断一下
//判断下一个节点是不是食物
bool NextIsFood(pSnakeNode pn, pSnake ps)
{
	return (pn->x == ps->pFood->x && pn->y == ps->pFood->y);
}
//如果是食物,就吃掉,然后创建新的食物
void EatFood(pSnakeNode pn, pSnake ps)
{
	//头插
	ps->pFood->next = ps->pSnakebody;
	ps->pSnakebody = ps->pFood;
	//释放下一个位置的节点
	free(pn);
	pn = NULL;
	//打印
	pSnakeNode cur = ps->pSnakebody;
	while (cur)
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	ps->Socre += ps->Food_Weight;
	CreateFood(ps);
}

为什么释放下一个位置的节点,有些同学有疑问
因为在CreateFood函数中,已经将ps->Food指向了食物节点,所以下一个位置的节点用不上的,当然要释放掉,因此,使用下一个位置的节点,释放食物节点也是可以的。
2. 下一个节点不是食物
在这里插入图片描述

//如果不是食物,就把最后一个节点释放
void NotFood(pSnakeNode pn, pSnake ps)
{
	//头插
	pn->next = ps->pSnakebody;
	ps->pSnakebody = pn;
	//最后一个节点,要释放
	pSnakeNode cur = ps->pSnakebody;
	while (cur->next->next)//打印前n个
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	//释放最后一个
	SetPos(cur->next->x, cur->next->y);
	printf("  ");
	free(cur->next);
	cur->next = NULL;
}

除了食物,还要判断下一个是否撞墙或者咬到自己

//判断下一步是否撞墙
void KillByWall(pSnake ps)
{
	if (ps->pSnakebody->x == 56
		|| ps->pSnakebody->x == 0
		|| ps->pSnakebody->y == 0
		|| ps->pSnakebody->y == 26)
	{
		ps->Cdt = KILL_BY_WALL;
	}
}
//判断下一步是否撞到自己
void KillBySelf(pSnake ps)
{
	pSnakeNode cur = ps->pSnakebody->next;
	while (cur)
	{
		if (cur->x == ps->pSnakebody->x && cur->y == ps->pSnakebody->y)
		{
			ps->Cdt = KILL_BY_SELF;
		}
		cur = cur->next;
	}
}

GameEnd

在这里插入图片描述

//善后工作
void GameEnd(pSnake ps)
{
	SetPos(20, 12);
	switch (ps->Cdt)
	{
	case END_NORMAL:
		printf("您主动结束了游戏");
		break;
	case KILL_BY_WALL:
		printf("您撞到墙死了");
		break;
	case KILL_BY_SELF:
		printf("您咬到了自己");
	}
	//释放蛇身节点
	pSnakeNode cur = ps->pSnakebody;
	while (cur)
	{
		pSnakeNode del = cur;
		cur = cur->next;
		free(del);
	}
}

蛇死亡后继续游戏

到此还没有结束,如果玩家还想在玩一把呢,总不能关闭应用再重新点开吧

void test()
{
	int ch = 0;
	do
	{
		system("cls");
		Snake snake;
		GameStart(&snake);
		GameRun(&snake);
		GameEnd(&snake);
		SetPos(20, 14);
		printf("再来一局吗?(Y/N):");
		ch = getchar();
		while (getchar() != '\n');//如果输入yyyy一样可以读取
	} while (ch == 'Y' || ch == 'y');
	SetPos(0, 27);
}

在这里插入图片描述
希望这篇博客对你有所帮助!!!如果有不懂或者有错的地方欢迎私信探讨!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/727221.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于TCAD与紧凑模型结合方法探究陷阱对AlGaN/GaN HEMTs功率附加效率及线性度的影响

来源&#xff1a;Investigation of Traps Impact on PAE and Linearity of AlGaN/GaN HEMTs Relying on a Combined TCAD–Compact Model Approach&#xff08;TED 24年&#xff09; 摘要 本文提出了一种新型建模方法&#xff0c;用于分析GaN HEMTs的微波功率性能。通过结合工…

【机器学习 复习】第4章 决策树算法(重点)

一、概念 1.原理看图&#xff0c;非常简单&#xff1a; &#xff08;1&#xff09;蓝的是节点&#xff0c;白的是分支&#xff08;条件&#xff0c;或者说是特征&#xff0c;属性&#xff0c;也可以直接写线上&#xff0c;看题目有没有要求&#xff09;&#xff0c; &#xff…

MySQL 离线安装客户端

1. 官方网址下载对应架构的安装包。 比如我的是centOs 7 x64。则需下载如图所示的安装包。 2. 安装 使用如下命令依次安装 devel , client-plugins, client. rpm -ivh mysql-community-*.x86_64.rpm --nodeps --force 在Linux系统中&#xff0c;rpm是一个强大的包管理工具&…

容器基本概念_从虚拟化技术_到容器化技术_开通青云服务器_并远程连接_容器安装---分布式云原生部署架构搭建007

这一部分,属于以前都会用到的,会快速过一遍,对于关键技术问题会加以说明 https://www.yuque.com/leifengyang/oncloud文档地址在这里,可以看,有些命令可以复制使用 可以看到容器的出现就是 目的就是,让你做的所有的软件,都可以一键部署启动 打包就是docker build 然后: 对于…

spring boot接入nacos 配置中心

再接入nacos配置中心时&#xff0c;需要确认几点&#xff1a; 1. spring boot 版本 (spring boot 2.x ) 2. nacos 配置中心 服务端 版本 (1.1.4) 3. nacos client 客户端版本 (1.1.4) 方式一 1. 启动 nacos 服务端&#xff0c;这里不做解释 在配置中心中加入几个配置 2. 在…

DNS部署与安全

一、DNS 英文全称&#xff1a;Domain Name Service 含义&#xff1a;域名服务 作用&#xff1a;为客户机提供域名解析服务 二、域名组成 域名组成概述 &#xff08;1&#xff09;如"www.sina.com.cn”是一个域名&#xff0c;从严格意义上讲&#xff0c;“sina.com.cn”…

深度解读爆火国产大模型Kimi(附教程,建议收藏!)_学习kimi

如果要问目前最强的大模型是谁&#xff0c;答案毫无疑问还是GPT4。但如果要问最近最火的大模型是谁&#xff0c;国产Kimi表示舍我其谁。 这个由一家初创还不到1年的AI企业做出来的现象级大模型智能助手&#xff0c;体验过的用户都表示惊艳到了&#xff0c;投过的一级机构继续加…

DS1339C串行实时时钟-国产兼容RS4C1339

RS4C1339串行实时时钟是一种低功耗的时钟/日期设备&#xff0c;具有两个可编程的一天时间报警器和一个可编程方波输出。地址和数据通过2线双向总线串行传输。时钟/日期提供秒、分钟、小时、天、日期、月份和年份信息。对于少于31天的月份&#xff0c;月末的日期会自动调整&…

2024年全球架构师峰会(ArchSummit深圳站)

前言 ArchSummit全球架构师峰会是极客邦科技旗下InfoQ中国团队推出的重点面向高端技术管理者、架构师的技术会议&#xff0c;54%参会者拥有8年以上工作经验。 ArchSummit聚焦业界强大的技术成果&#xff0c;秉承“实践第一、案例为主”的原则&#xff0c;展示先进技术在行业中的…

Java面试八股之JVM永久代会发生垃圾回收吗

JVM永久代会发生垃圾回收吗 JVM的永久代&#xff08;PermGen&#xff09;在Java 8之前是存在的一部分&#xff0c;主要用于存储类的元数据、常量池、静态变量等。在这些版本中&#xff0c;永久代确实会发生垃圾回收&#xff0c;尤其是在永久代空间不足或超过某个阈值时&#x…

【C语言】手写学生管理系统丨附源码+教程

最近感觉大家好多在忙C语言课设~ 我来贡献一下&#xff0c;如果对你有帮助的话谢谢大家的点赞收藏喔&#xff01; 1. 项目分析 小白的神级项目&#xff0c;99%的程序员&#xff0c;都做过这个项目&#xff01; 掌握这个项目&#xff0c;就基本掌握 C 语言了&#xff01; 跳…

JUC并发编程-第二天:线程高级部分

线程高级部分 线程不安全原子性可见性有序性&#xff08;指令重排&#xff09; 线程不安全 多线程下并发同时对共享数据进行读写&#xff0c;会造成数据混乱线程不安全 当多线程下并发访问临界资源时&#xff0c;如果破坏其原子性、可见性、有序性&#xff0c;可能会造成数据不…

最小生成树prim算法详解

prim算法解决的是最小生成树问题&#xff0c;即在一个给定的无向图G中求一棵生成树T&#xff0c;使得这棵树拥有图G中的所有顶点&#xff0c;且所有边都是来自图G中的边&#xff0c;并且满足整棵树的边权之和最小。 prim算法的基本思想是对图G设置集合S来存放已被访问的顶点&a…

实验2:RIPv2的配置

由于RIPv1是有类别的路由协议,路由更新不携带子网信息,不支持不连续子网、VLSM、手工汇总和验证等&#xff0c;本书重点讨论RIPv2。 1、实验目的 通过本实验可以掌握&#xff1a; RIPv1和 RIPv2的区别。在路由器上启动RIPv2路由进程。激活参与RIPv2路由协议的接口。auto-sum…

STM32学习笔记(五)--TIM输出比较PWM详解

&#xff08;1&#xff09;配置步骤1.配置RCC外设时钟 开启GPIO以及TIM外设2.配置时基单元的时钟 包含时钟源选择配置初始化时基单元3.配置输出比较单元 包含CCR的值 输出比较模式 极性选择 输出使能等4.配置GPIO口 初始化为复用式推挽输出的配置5.运行控制 启动计数器 输出PWM…

C++多重继承,虚基类与友元

一.多重继承 就是一个类继承多个基类&#xff1b; class <派生类名>&#xff1a;<派生方式1><基类名1>,<派生方式n><基类名n> class Derived:public:Base1,public:Base2 上述形式&#xff1a;基类之间由逗号隔开&#xff0c;且必须指明继承方式…

HNU-计算机系统(CSAPP)实验四 BufLab

【实验目的】 1.通过本次实验熟悉IA-32调用约定和堆栈组织&#xff1b; 2.学习缓冲区溢出攻击原理&#xff0c;对实验室目录中的一个可执行文件应用一系列的缓冲区溢出攻击&#xff1b; 3.通过实验获得使用通常用于利用操作系统和网络服务器中的安全弱点的常用方法之一的第一…

企业如何做好供应链管理工作?8个步骤及应用详解!

供应链就是采购把东西买进来&#xff0c;生产去加工增值&#xff0c;物流去配送给客户&#xff0c;环环相扣&#xff0c;就形成了供应链。它是将供应商&#xff0c;制造商&#xff0c;分销商直到最终用户连成一个整体的功能网链结构。 而供应链管理就是做好每个环节的管理&…

4. Revit API UI: Ribbon(界面)

4. Revit API UI: Ribbon&#xff08;界面&#xff09; 第二篇中&#xff0c;我们提到了IExternalApplication&#xff0c;该接口需要实现两个方法&#xff1a;Revit启动时调用的OnStartup 方法&#xff0c;和Revit关闭时调研的OnShutdown 方法。文中还给了个例子&#xff0c;…

RTSP/Onvif安防监控平台EasyNVR抓包命令tcpdump使用不了的解决方法

安防视频监控汇聚EasyNVR智能安防视频监控平台&#xff0c;是基于RTSP/Onvif协议的安防视频平台&#xff0c;可支持将接入的视频流进行全平台、全终端分发&#xff0c;分发的视频流包括RTSP、RTMP、HTTP-FLV、WS-FLV、HLS、WebRTC等格式。平台可提供的视频能力包括&#xff1a;…