自制贪吃蛇小游戏

        此片文章涉及到到控制台设置的相关操作,虚拟键码,宽字符输出等,有些地方大家可能会看不懂,可以阅读以下文章来进一步了解:

控制台程序设置-CSDN博客

效果展示:

QQ2024428-181932

源码已放在文章结尾

目录

一.功能实现

二.头文件的声明

三.游戏开始 -- GameStart

1.窗口设置

2.光标设置

2.1光标的隐藏

2.2光标坐标设置--SetPos

3.欢迎界面打印--WelcomeToGame

4.地图绘制--CreateMap

5.蛇身初始化--InitSnake

6.食物坐标设定--CreateFood

四.游戏运行-- GameRun

1.打印玩法说明

2.打印当前得分和食物分数

3.获取按键状态--Key

4.蛇的移动-Snakemove

4.1.计算新节点的坐标

4.2.是否撞墙--KillByWall

4.3.是否撞到自身--KillByself

5.循环进行

五.游戏结束 -- GameEnd

1.打印游戏结束的原因

2.释放空间

 六.游戏的优化

七.优化后源码


 首先我们需要对默认窗口做一下更改,如下:

一.功能实现

  •         地图绘制
  •         蛇撞墙死亡
  •         蛇撞自身死亡
  •         用↓ → ← ↑来操作蛇的方向
  •         蛇吃食物加分并记录总得分
  •         蛇的加减功能
  •         蛇的速度越快每个食物分数越高
  •         蛇每吃一个食物身体加长
  •         空格键暂停游戏,再次点击开始游戏

二.头文件的声明

我们把该项目分为三部分,分别是头文件Snake.h,源文件Snake.c,源文件test.c

以下是头文件上的声明:

#pragma
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<locale.h>
#include<windows.h>
#include<stdbool.h>
#include<time.h>
#define pos_x 24//蛇的初始横坐标
#define pos_y 5 //蛇的初始纵坐标
#define WALL L'□' //墙的形状
#define BODY L'●' //蛇身的形状
#define FOOD L'★'//食物的形状
#define Key(x) (GetAsyncKeyState(x)&1)//判断按键是否被按过
enum DIRECTION//蛇的方向
{
	UP = 1,
	DOWN,
	LEFT,
	RIGHT
};
enum GAME_STATUS//蛇的状态
{
	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 _pSnake;//蛇的坐标
	pSnakeNode _pFood;//食物的坐标
	enum DIRECTION _dir;//蛇的移动方向
	enum GAME_STATUS _status;//蛇的状态
	int _food_weight;//一个食物的分数
	int _score;//总分数
	int _sleep_time;//蛇的速度
}Snake,*pSnake;

三.游戏开始 -- GameStart

        在做准备工作中需要在主函数中进行本地化,以方便后面输出宽字符。如下:

setlocale(LC_ALL, "");

1.窗口设置

        在游戏开始之前我们需要对运行窗口进行设定,首先我们对它的标题进行设置,如下:

system("title 贪吃蛇");

         其次是窗口大小的设定,比如设置一个100行,30列的窗口,如下:

system("mode con cols=100 lines=30");

2.光标设置

2.1光标的隐藏

        为了方便玩家的体验,我们把光标隐藏,也就是把它的透明度该为fales,如下:

    HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);//获取柄
    CONSOLE_CURSOR_INFO Info;//申请CONSOLE_CURSOR_INFO类型的变量,用于储存坐标信息
    GetConsoleCursorInfo(houtput, &Info);//获取坐标信息
    Info.bVisible = false;//改变坐标透明度
    SetConsoleCursorInfo(houtput, &Info);//设置坐标

2.2光标坐标设置--SetPos

        在做打印时候需要将光标移动到合适的坐标位置,而这个操作到后面是会频繁操作的,所以我们把它封装成一个函数,如下:

void SetPos(int x, int y)//设置光标的坐标
{
	HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);//GetStdHandle获取柄,HANDLE接收柄
	COORD pos = { x,y };//坐标
	SetConsoleCursorPosition(houtput, pos);
}

3.欢迎界面打印--WelcomeToGame

        欢迎界面我们可以玩家打印一些欢迎界面和玩法说明,在此之前我们需要把光标调到适应的位置,使其把信息打印到中间位置效果更佳。如下:

        上图的窗口右下角的 请按任意键继续...是代码system("pause"); 带来的效果,它作用是暂停程序的运行,按任意键可以使程序继续运行。

4.地图绘制--CreateMap

        在地图创建中我们是用宽字符 '□'去构造的,而宽字符占两个字节。蛇身我们用宽字符'●'去构造,而后面的设计中是要判断蛇是否撞墙的,所以在打印 '□' 和 '●' 之前光标要移动到横坐标为偶数的坐标位置,或要移动到横坐标为奇数的坐标位置,这样可以保证不会出现蛇头的一半在墙里面,一半在墙外面的情况,如这样:2d0aed15edda4741ba12f6e238a5c9b1.png

        其次要保证食物的横坐标奇偶性和蛇横坐标保持一致,也是为了避免这种情况的发生。(这里我们选择让蛇,墙体,食物的横坐标都为偶数)

那么接下来打印地图就比较简单了,如下:

void CreateMap()//地图绘制
{
	for (int i = 0; i <= 56; i += 2)
		wprintf(L"%lc", WALL);
	SetPos(0, 26);
	for (int i = 0; i <= 56; i+=2)
		wprintf(L"%lc", WALL);
	for (int i = 1; i <= 26; i++)
	{
		SetPos(0, i);
		wprintf(L"%lc", WALL);
    }
	for (int i = 1; i < 26; i++)
	{
		SetPos(56, i);
		wprintf(L"%lc", WALL);
	}
}

效果如下:(当然此图并不是该代码的输出结果) 

dbe4215c39e3473b998a222966a6338a.png

5.蛇身初始化--InitSnake

        蛇在初始化状态,我们可以用5个节点来给蛇初始化并打印,当然还需要初始化蛇的移动方向,蛇的状态,食物的分数,总分数,速度(休眠时间)

void InitSnake(pSnake ps)//蛇身的初始化
{
	ps->_pSnake = NULL;//重点!!
	pSnakeNode pnew = NULL;
	for (int i = 0; i < 5; i++)
	{
		pnew = (pSnakeNode)malloc(sizeof(SnakeNode));
		assert(pnew);
		pnew->x = pos_x + i * 2;
		pnew->y = pos_y;
		pnew->next = NULL;
		if ((ps->_pSnake) == NULL)
		{
			ps->_pSnake = pnew;
		}
		else
		{
			pnew->next = ps->_pSnake;
			ps->_pSnake = pnew;
		}
	}
	pnew = ps->_pSnake;
	while (pnew)
	{
		SetPos(pnew->x, pnew->y);
		wprintf(L"%lc", BODY);
		pnew = pnew->next;
	}
	ps->_status = OK;
	ps->_food_weight = 10;
	ps->_score = 0;
	ps->_sleep_time = 200;
	ps->_dir = RIGHT;
}

6.食物坐标设定--CreateFood

        食物的坐标是随机的,需要一个随机数生成函数,虽然说是随机但也有前提条件

        1.食物不能在墙上和墙以外

        2.食物的横坐标必须是偶数(地图绘制那里讲过原因,这里不在赘述)

        3.食物不能在蛇的身上

        反过来说如果产生的随机数是这两个条件中的任意一个都不能要需要重新生成。这里用 go to语句更为方便。

代码实现:

void CreateFood(pSnake ps)
{
	int x, y;
	pSnakeNode cur = NULL;
	again:
	cur = ps->_pSnake;
	do
	{
		x = rand() % 53 + 2;
		y = rand() % 25 + 1;
	} while (x % 2 != 0);
	while (cur)
	{
		if (x == cur->x && y == cur->y)
		{
			goto again;
		}
		cur = cur->next;
	}
	pSnakeNode Food = (pSnakeNode)malloc(sizeof(SnakeNode));
	assert(Food);
	Food->x = x;
	Food->y = y;
	Food->next = NULL;
	ps->_pFood = Food;
	SetPos(x, y);
	wprintf(L"%lc", FOOD);
}

这里已把srand((unsigned int)time(NULL));放在了主函数main中 

四.游戏运行-- GameRun

1.打印玩法说明

        在游戏运行过程中我们可以把玩法说明打印到右侧空白的地方,注意打印前需要调整光标的坐标位置,包括后面涉及到的所有打印

2.打印当前总得分和食物分数

        在打印食物分数和总分数过程中要注意这两项是跟着蛇的运动而改变的,需要和蛇的移动一起放在一个循环中。

3.获取按键状态--Key

        我们通过获取键盘按键状态,来相应的改变蛇的运动方向和速度

要注意几个点:

        1.蛇不能向反方向走,比如蛇的方向原本是向右的但玩家按取一个 ← 按键应该示为无效。

        2.玩家按空格键后如何让游戏暂停是个问题,我们可以用一个死循环的睡眠来实现,并且如果再次按空格键退出循环。其次如果需要把 "游戏已暂停,点击空格键继续" 打印到屏幕上的话,当游戏再次开始后此字符串的位置应用空格字符来填充,否则就会一直停留在屏幕上。

        3.蛇的速度不能无限的小或无限的大要不然玩家无法玩,应该设置一个上下限。

代码如下:

		if (Key(VK_UP) && ps->_dir != DOWN)
			ps->_dir = UP;
		else if (Key(VK_DOWN) && ps->_dir != UP)
			ps->_dir = DOWN;
		else if (Key(VK_LEFT) && ps->_dir != RIGHT)
			ps->_dir = LEFT;
		else if (Key(VK_RIGHT) && ps->_dir != LEFT)
			ps->_dir = RIGHT;
		if (Key(VK_SPACE))
		{
			while (1)
			{
				SetPos(29,13);
				printf("游戏已暂停,点击空格键继续");
				if (Key(VK_SPACE))
					break;
				Sleep(300);
			}
			SetPos(29, 13);
			int x = 26;
			while (x--)
				printf(" ");
		}
		if (Key(VK_ESCAPE))
			ps->_status = END_NORMAL;
		if (Key(VK_SHIFT))
		{
			if (ps->_sleep_time >= 80)
			{
				ps->_sleep_time -=30 ;
				ps->_food_weight += 2;
			}
		}
		if (Key(VK_CONTROL))
		{
			if (ps->_sleep_time <= 320)
			{
				ps->_sleep_time += 30;
				ps->_food_weight -= 2;
			}
		}

4.蛇的移动-Snakemove

        在写此函数的时候我们先想一个问题如何实现动态呢?有人可能会想每输出一次做一次清屏处理

        这确实是行得通的。但在此我们用另一种方法,当下一个节点无食物的时候,将下一个节点头插到原头节点上并删除尾节点然后打印出整个蛇,并且将原来的尾用空格覆盖,否则它会一直停留在屏幕上当下一个节点有食物的时候,将下一个节点头插到原头节点上但尾节点不用删不能用空格覆盖,并重新构造新的食物。效果如下:

当下一个节点无食物的时候:

3d081aee73184f0e849f78987aee6ccc.png

当下一个节点有食物的时候: 

8d76a9cd6009460db037a36d7d451e2c.png

        所以在打印之前我们需要判断下一个节点是否为食物,然后以不同的方式打印

4.1.计算新节点的坐标

        在蛇的移动过程中我们需要不断的插入头节点并删除尾节点,插入什么样的头节点是根据从玩家获取到的按键状态来决定的,比如一个正在向右移动的蛇,玩家按了 ↑ 按键,那么我们创造的下一个节点内储存的横坐标就应是原头节点的横坐标,纵坐标应是原头节点纵坐标减1。以此类推。

代码如下:

void SnakeMove(pSnake ps)
{
	pSnakeNode pnew = (pSnakeNode)malloc(sizeof(SnakeNode));
	assert(pnew);
	switch (ps->_dir)
	{
	case UP:
		pnew->y = ps->_pSnake->y - 1;
		pnew->x = ps->_pSnake->x;
		break;
	case DOWN:
		pnew->y = ps->_pSnake->y + 1;
		pnew->x = ps->_pSnake->x;
		break;
	case LEFT:
		pnew->x = ps->_pSnake->x - 2;
		pnew->y = ps->_pSnake->y;
		break;
	case RIGHT:
		pnew->x = ps->_pSnake->x + 2;
		pnew->y = ps->_pSnake->y;
		break;
	}
	pnew->next = ps->_pSnake;
	ps->_pSnake = pnew;
	if ((pnew->x == ps->_pFood->x )&& (pnew->y == ps->_pFood->y))//是食物
	{
		int i = 112;
		while (pnew)
		{
			SetPos(pnew->x, pnew->y);
			color(i++);
			wprintf(L"%lc", BODY);
			pnew = pnew->next;
			if (i == 126)
				i = 112;
			if (i == 119||i==112)
				i++;
		}
		color(112);
		ps->_score += ps->_food_weight;
		free(ps->_pFood);
		printf("\a");
		CreateFood(ps);
	}
	else//不是食物
	{
		while (pnew->next->next)
		{
			SetPos(pnew->x, pnew->y);
			color(120);
			wprintf(L"%lc", BODY);
			pnew = pnew->next;
		}
		color(112);
		SetPos(pnew->next->x, pnew->next->y);
		printf("  ");
		free(pnew->next);
		pnew->next = NULL;
	}
}

4.2.是否撞墙--KillByWall

        在判断是否撞到墙,我们只需要判断头节点坐标是否和墙体坐标相同,如果相同就把蛇的状态对应改变就可以。代码如下:

void KillByWall(pSnake ps)//判断是否撞墙
{
	if ((ps->_pSnake->y == 0) || (ps->_pSnake->y == 26)
		|| (ps->_pSnake->x == 0) || (ps->_pSnake->x == 56))
		ps->_status = KILL_BY_WALL;
}

4.3.是否撞到自身--KillByself

        判断是否撞到自身只需要判断头节点的坐标是否和蛇身体坐标相同,如果相同的话同样是把蛇的状态对应改变。代码如下:

void KillByself(pSnake ps)//判断是否撞到自己
{
	pSnakeNode pr = ps->_pSnake;
	pSnakeNode pu = ps->_pSnake->next;
	while (pu)
	{
		if (pu->x == pr->x && pu->y == pr->y)
		{
			ps->_status = KILL_BY_SELF;
			return;
		}
		pu = pu->next;
	}
}

5.循环进行

        以上的操作只是完成了蛇的一次移动,我们需要一个do while语句使它循环起来,不过为了控制蛇的速度在此之前我们需要加上一个Sleep睡眠,如下:

Sleep(ps->_sleep_time);

然后就是在考虑一下循环条件,即

                 ps->_status == OK

如下:

do
{
    ......

    Sleep(ps->_sleep_time);

} while (ps->_status == OK);

五.游戏结束 -- GameEnd

1.打印游戏结束的原因

        这个操作也是很简单我们只需要检查一下蛇的状态然后用 if 语句进行条件输出就可以。

        到这里我们可能就会发现设置蛇的状态的必要性,和用枚举类型来做该设置的优势,其次上面的循环也用到了蛇的状态。

2.释放空间

        注意我们在写程序的过程中使用的蛇身和食物都是用malloc动态申请的空间,最好呢是我们手动把它们释放掉。

void GameEnd(pSnake ps)//游戏结束善后处理
{
	SetPos(29, 13);
	if (ps->_status == KILL_BY_SELF)
	{
		color(116);
		printf("你撞到了自己,游戏结束");
	}
	if (ps->_status == KILL_BY_WALL)
	{
		color(116);
		printf("你撞到了墙,游戏结束");
	}
	free(ps->_pFood);
	while (ps->_pSnake)
	{
		pSnakeNode cur = ps->_pSnake->next;
		free(ps->_pSnake);
		ps->_pSnake = cur;
	}
}

 六.游戏的优化

        当我们学会了以上这些操作以后,我们就可以根据自己的需要来提升游戏的效果

例如:

1.给蛇,食物,墙体设置颜色。

2.把蛇的身体设置成不同的形状。

2.添加双人模式,添加食物个数。

 ... ...

        这里我来提一下双人模式的设计,比如我们想要实现的功能是:

  • 玩家1控制的蛇撞到玩家2控制蛇的身体,那么玩家1就死亡。
  • 玩家撞到自己的身体并不会死亡。
  • 任意玩家按空格键使该游戏暂停。
  • 食物的数量为10个。
  • 两玩家可以分别控制自己的蛇的速度,让博弈更激烈。

        第1,2点呢比较简单,第3点的实现我们可以把食物做成10个节点的链表,当一个食物被吃掉的时候就更新该食物对应的节点所储存的坐标并再次打印出食物

        而然难点是在于如何让蛇的速度不能互相干扰,为了解决这个问题我们可以用一个双线程来同时处理两个玩家控制的蛇相当于把它们分别放在不同时空分别运行,这样它们的时间就可以互不干扰,但它们又共用一些资源比如SetPos函数,也就是它们同时控制光标的位置,这就会导致光标的位置随着时间随意乱窜打印的并不是我们想要的结果,这样我们考虑用一个时间来处理这个问题。

七.优化后源码

Snake.h

#pragma
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<locale.h>
#include<windows.h>
#include<stdbool.h>
#include<time.h>
//蛇的初始坐标
#define pos_x 24
#define pos_y 5

//单人模式 地图坐标
#define X 58
#define Y 26

//双人模式 地图坐标
#define X2 98
#define Y2 38

#define WALL L'□'//地图边界
#define BODY L'●'//蛇身
#define FOOD L'★'//食物
#define Key(x) (GetAsyncKeyState(x)&1)//键盘敲击信息读取

CRITICAL_SECTION cs;

enum DIRECTION//蛇的方向
{
	UP = 1,
	DOWN,
	LEFT,
	RIGHT
};
enum GAME_STATUS
{
	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 _pSnake;//蛇的坐标
	pSnakeNode _pFood;//食物的坐标
	enum DIRECTION _dir;//蛇的移动方向
	enum GAME_STATUS _status;//蛇的状态
	int _food_weight;//一个食物的分数
	int _score;//分数
	int _sleep_time;//蛇的速度
}Snake, * pSnake;
typedef struct LSnake
{
	pSnake p1;
	pSnake p2;
	int x;
}LSnake,*pLSnake;

int menu();//菜单打印

void color(int x);//颜色设置

void SetPos(int x, int y);//光标位置设定

int GameStart(pSnake ps1,pSnake ps2); //游戏开始
int WelcomeToGame();//欢迎界面

void PrintHelpInfo1();//单人模式 玩法说明
void PrintHelpInfo2();//双人模式 玩法说明

void CreateMap1();//单人模式 地图绘制
void CreateMap2();//双人模式 地图绘制

void InitSnake1(pSnake ps);//单人模式 蛇身的初始化
void InitSnake2(pSnake ps);//双人模式 蛇身的初始化

void CreateFood1(pSnake ps);//单人模式 食物坐标的设定
void CreateFood2(pSnake ps1, pSnake ps2);//双人模式 食物坐标的设定
void PrintFood(pSnakeNode hfood);//打印食物

DWORD WINAPI th1(LPVOID ps);//玩家1的线程
DWORD WINAPI th2(LPVOID ps);//玩家2的线程

void GameRun1(pSnake ps);//单人模式 游戏运行主逻辑
void GameRun2(pSnake ps1, pSnake ps2);//双人模式 游戏运行主逻辑

void KillByWallp(pSnake ps1);
void KillByWall(pSnake ps);//判断是否撞墙
void KillByself(pSnake ps);//判断是否撞到自己
void KillByselfp(pSnakeNode pnew, pSnake ps);//是否撞到对方玩家身体

pSnakeNode OpFood(pSnakeNode ps, pSnakeNode hfood);//判断是否吃到食物

void SnakeMove1(pSnake ps);//单人模式 蛇的移动
void SnakeMove2(pSnake ps1, pSnake ps2);//双人模式 蛇的移动

void GameEnd(pSnake ps);//单人模式 游戏结束善后
void GameEndp(pSnake ps1, pSnake ps2);//双人模式 游戏结束善后

Snake .c

#define _CRT_SECURE_NO_WARNINGS 1
#include"snake.h"
#define Key(x) (GetAsyncKeyState(x)&1)
void color(int x)
{
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), x);
}
void SetPos(int x, int y)//设置光标的坐标
{
	HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);//GetStdHandle获取柄,HANDLE接收柄
	COORD pos = { x,y };//坐标
	SetConsoleCursorPosition(houtput, pos);
}
int menu()
{
	SetPos(36, 10);
	printf("******** "); color(121); printf("1.单人模式 "); color(112); printf("*********");
	SetPos(36, 11);
	printf("******** "); color(124); printf("2.双人博弈 "); color(112); printf("*********");
	SetPos(38, 12);
	printf("请选择>>");
	char c, k;
	int x = 0,i=0;
	while (scanf("%c%c", &c, &k),c != '1' && c!= '2')
	{
		SetPos(36, 13+i++);
		color(116);
		printf("输入错误,请输入1或2");
		color(112);
	}
	x = c - '0';
	return x;
}
int WelcomeToGame()//欢迎界面打印
{
	SetPos(40, 10);
	printf("欢迎来到贪吃蛇游戏!");
	SetPos(80, 28);
	system("pause");
	int x = menu();
	system("cls");
	if (x == 1)
	{
		SetPos(5, 10);
		printf("请用键盘按键↑← → ↓来控制蛇的移动方向,空格键暂停,Ese键退出游戏,");
		printf("蛇吃到食物会增加长度和分数,蛇撞到自身或墙壁游戏失败,");
		printf("Tab键加速,Q键减速");
	}
	else
	{
		SetPos(5, 10);
		printf("玩家一:请用键盘按键↑← → ↓来控制蓝蛇的移动方向,Alt右键加速, Ctrl右键减速");
		SetPos(5, 12);
		printf("玩家二:请用键盘按键 W A S D 来控制绿蛇的移动方向,Alt左键加速,C键减速");
		SetPos(16, 14);
		printf("空格键暂停游戏");
	}
	SetPos(80, 28);
	system("pause");
	system("cls");
	return x;
}
void CreateMap1()//地图绘制
{
	for (int i = 0; i < X; i += 2)
	{
		wprintf(L"%lc", WALL);
	}
	SetPos(0, Y);
	for (int i = 0; i < X; i += 2)
	{
		wprintf(L"%lc", WALL);
	}
	for (int i = 1; i <= Y; i++)
	{
		SetPos(0, i);
		wprintf(L"%lc", WALL);
	}
	for (int i = 1; i < Y; i++)
	{
		SetPos(X-2, i);
		wprintf(L"%lc", WALL);
	}
}
void CreateMap2()//地图绘制
{
	for (int i = 0; i < X2; i += 2)
	{
		wprintf(L"%lc", WALL);
	}
	SetPos(0, Y2);
	for (int i = 0; i < X2; i += 2)
	{
		wprintf(L"%lc", WALL);
	}
	for (int i = 1; i <= Y2; i++)
	{
		SetPos(0, i);
		wprintf(L"%lc", WALL);
	}
	for (int i = 1; i < Y2; i++)
	{
		SetPos(X2-2, i);
		wprintf(L"%lc", WALL);
	}
}
void InitSnake1(pSnake ps)//玩家一蛇身的初始化
{
	ps->_pSnake = NULL;//重点!!
	pSnakeNode pnew = NULL;
	for (int i = 0; i < 5; i++)
	{
		pnew = (pSnakeNode)malloc(sizeof(SnakeNode));
		assert(pnew);
		pnew->x = pos_x + i * 2;
		pnew->y = pos_y;
		pnew->next = NULL;
		if ((ps->_pSnake) == NULL)
		{
			ps->_pSnake = pnew;
		}
		else
		{
			pnew->next = ps->_pSnake;
			ps->_pSnake = pnew;
		}
	}
	pnew = ps->_pSnake;
	while (pnew)
	{
		SetPos(pnew->x, pnew->y);
		wprintf(L"%lc", BODY);
		pnew = pnew->next;
	}
	ps->_status = OK;
	ps->_food_weight = 10;
	ps->_score = 0;
	ps->_sleep_time = 200;
	ps->_dir = RIGHT;
}
void InitSnake2(pSnake ps)//蛇身的初始化
{
	ps->_pSnake = NULL;//重点!!
	pSnakeNode pnew = NULL;
	for (int i = 0; i < 5; i++)
	{
		pnew = (pSnakeNode)malloc(sizeof(SnakeNode));
		assert(pnew);
		pnew->x = 24 + i * 2;
		pnew->y = 10;
		pnew->next = NULL;
		if ((ps->_pSnake) == NULL)
		{
			ps->_pSnake = pnew;
		}
		else
		{
			pnew->next = ps->_pSnake;
			ps->_pSnake = pnew;
		}
	}
	pnew = ps->_pSnake;
	while (pnew)
	{
		SetPos(pnew->x, pnew->y);
		wprintf(L"%lc", BODY);
		pnew = pnew->next;
	}
	ps->_status = OK;
	ps->_food_weight = 10;
	ps->_score = 0;
	ps->_sleep_time = 200;
	ps->_dir = RIGHT;
}
void PrintFood(pSnakeNode hfood)//打印食物
{
	pSnakeNode ps = hfood;
	int i = 112;
	while (ps)
	{
		color(i++);
		SetPos(ps->x, ps->y);
		wprintf(L"%lc", FOOD);
		ps = ps->next;
		if(i==119)
			i++;
	}
	color(112);
}
void CreateFood2(pSnake ps1,pSnake ps2)
{
	int x=0, y=0,n=10;
	pSnakeNode cur1 = NULL,cur2=NULL,Food1=NULL,hFood1=NULL;
	pSnakeNode Food2 = NULL, hFood2 = NULL;
	pSnakeNode hfood = NULL;
	while (n--)
	{
	again:
		cur1 = ps1->_pSnake;
		cur2 = ps2->_pSnake;
		do
		{
			x = rand() % (X2 - 4) + 2;
			y = rand() % (Y2 - 1) + 1;
		} while (x % 2 != 0);
		while (cur1)
		{
			if (x == cur1->x && y == cur1->y)
			{
				goto again;
			}
			cur1 = cur1->next;
		}
		while (cur2)
		{
			if (x == cur2->x && y == cur2->y)
			{
				goto again;
			}
			cur2 = cur2->next;
		}
		while (hfood)
		{
			if (x == hfood->x && y == hfood->y)
			{
				goto again;
			}
			hfood = hfood->next;
		}
		pSnakeNode pnew = (pSnakeNode)malloc(sizeof(SnakeNode));
		assert(pnew);
		pnew->x = x;
		pnew->y = y;
		pnew->next = NULL;
		if (!hFood1)
		{
			Food1 = pnew;
			hFood1 = Food1;
			hfood = Food1;
		}
		else
		{
			Food1->next = pnew;
			Food1 = Food1->next;
		}
	}
	ps1->_pFood = hFood1;
	ps2->_pFood = hFood1;
	PrintFood(hFood1);
}
void CreateFood1(pSnake ps)
{
	int x, y;
	pSnakeNode cur = NULL;
again:
	cur = ps->_pSnake;
	do
	{
		x = rand() % 53 + 2;
		y = rand() % 25 + 1;
	} while (x % 2 != 0);
	while (cur)
	{
		if (x == cur->x && y == cur->y)
		{
			goto again;
		}
		cur = cur->next;
	}
	pSnakeNode Food = (pSnakeNode)malloc(sizeof(SnakeNode));
	assert(Food);
	Food->x = x;
	Food->y = y;
	Food->next = NULL;
	ps->_pFood = Food;
	SetPos(x, y);
	wprintf(L"%lc", FOOD);
}
int GameStart(pSnake ps1, pSnake ps2)//开始游戏
{
	system("mode con cols=100 lines=35 ");
	system("title 贪吃蛇");
	HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_CURSOR_INFO Info;
	GetConsoleCursorInfo(houtput, &Info);
	Info.bVisible = false;
	SetConsoleCursorInfo(houtput, &Info);
	int x=WelcomeToGame();//欢迎界面
	if (x == 2)
	{
		system("mode con cols=150 lines=42 ");
	}
	color(116);
	if (x == 1)
		CreateMap1();//地图绘制
	else
		CreateMap2();
	color(112);
	if (x == 1)
	{
		InitSnake1(ps1);//蛇身的初始化
		CreateFood1(ps1);
	}
	else
	{
		InitSnake1(ps1);
		InitSnake2(ps2);
		CreateFood2(ps1,ps2);//食物坐标的设定
	}
	return x;
}
void PrintHelpInfo1()//打印玩法
{
	SetPos(60, 15);
	printf("请用键盘按键↑← → ↓来控制蛇的移动方向");
	SetPos(60, 16);
	printf("蛇吃到食物会增加长度和分数");
	SetPos(60, 17);
	printf("蛇撞到自身或墙壁游戏失败");
	SetPos(60, 18);
	printf("Tab键加速,Q键减速");
	SetPos(60, 19);
	printf("空格键表示暂停,Ese键退出游戏");
	SetPos(60, 1);
}
void PrintHelpInfo2()//打印玩法
{
	SetPos(X2+6, 15);
	printf("玩家1请用键盘按键↑← → ↓来控制蛇的移动方向");
	SetPos(X2 + 6, 16);
	printf("玩家2请用键盘按键 W A S D  来控制蛇的移动方向");
	SetPos(X2 + 6, 18);
	printf("蛇吃到食物会增加长度和分数");
	SetPos(X2 + 6, 19);
	printf("蛇撞到自己或另一玩家不会死亡,蛇撞墙壁游戏失败");
	SetPos(X2 + 6, 20);
	printf("Shift加速,Ctrl减速");
	SetPos(X2 + 6, 21);
	printf("空格键表示暂停,Ese键退出游戏");
	SetPos(X2 + 6, 1);
}
void SnakeMove1(pSnake ps)单人模式
{
	pSnakeNode pnew = (pSnakeNode)malloc(sizeof(SnakeNode));
	assert(pnew);
	switch (ps->_dir)
	{
	case UP:
		pnew->y = ps->_pSnake->y - 1;
		pnew->x = ps->_pSnake->x;
		break;
	case DOWN:
		pnew->y = ps->_pSnake->y + 1;
		pnew->x = ps->_pSnake->x;
		break;
	case LEFT:
		pnew->x = ps->_pSnake->x - 2;
		pnew->y = ps->_pSnake->y;
		break;
	case RIGHT:
		pnew->x = ps->_pSnake->x + 2;
		pnew->y = ps->_pSnake->y;
		break;
	}
	pnew->next = ps->_pSnake;
	ps->_pSnake = pnew;
	if ((pnew->x == ps->_pFood->x) && (pnew->y == ps->_pFood->y))
	{
		while (pnew)
		{
			SetPos(pnew->x, pnew->y);
			color(116);
			wprintf(L"%lc", BODY);
			pnew = pnew->next;
		}
		color(112);
		ps->_score += ps->_food_weight;
		free(ps->_pFood);
		printf("\a");
		CreateFood1(ps);
	}
	else
	{
		while (pnew->next->next)
		{
			SetPos(pnew->x, pnew->y);
				color(120);
			wprintf(L"%lc", BODY);
			pnew = pnew->next;
		}
		color(112);
		SetPos(pnew->next->x, pnew->next->y);
		printf("  ");
		free(pnew->next);
		pnew->next = NULL;
	}
	Sleep(ps->_sleep_time);
}
void ChangeFood(pSnake ps1,pSnake ps2,pSnakeNode ps)//改变食物位置
{
	pSnakeNode cur1 = NULL, cur2 = NULL,hfood=ps2->_pFood;
	int x = 0, y = 0;
	Again:
		cur1 = ps1->_pSnake;
		cur2 = ps2->_pSnake;
		do
		{
			x = rand() % (X2 - 4) + 2;
			y = rand() % (Y2 - 1) + 1;
		} while (x % 2 != 0);
		while (cur1)
		{
			if (x == cur1->x && y == cur1->y)
			{
				goto Again;
			}
			cur1 = cur1->next;
		}
		while (cur2)
		{
			if (x == cur2->x && y == cur2->y)
			{
				goto Again;
			}
			cur2 = cur2->next;
		}
		while (hfood)
		{
			if (x == hfood->x && y == hfood->y)
			{
				goto Again;
			}
			hfood = hfood->next;
		}
		ps->x = x, ps->y = y;
}
pSnakeNode OpFood(pSnakeNode ps, pSnakeNode hfood)
{
	pSnakeNode hf = hfood;
	while (hf)
	{
		if (ps->x == hf->x && ps->y == hf->y)
			return hf;
		hf = hf->next;
	}
	return NULL;
}
	//玩家1///
DWORD WINAPI th1(LPVOID ps)
{
	pLSnake psk = (pLSnake)ps;
	pSnake pw1 = NULL, pw2 = NULL;
	pw1 = psk->p1;
	pw2 = psk->p2;
	int fup = 0;
		do
		{
			EnterCriticalSection(&cs);
				color(112);
				SetPos(X2 + 6, 8);
				printf("玩家1 绿蛇");
			LeaveCriticalSection(&cs);

			EnterCriticalSection(&cs);
				SetPos(X2 + 6, 9);
				if (fup == 1)
				{
					printf("食物分数:"); color(116); printf("%2d", pw1->_food_weight); color(112);
				}
				else if (fup == -1)
				{
					printf("食物分数:"); color(114); printf("%2d", pw1->_food_weight); color(112);
				}
				else
				{
					printf("食物分数:%2d", pw1->_food_weight); 
				}
			LeaveCriticalSection(&cs);

			EnterCriticalSection(&cs);
				color(112);
				SetPos(X2 + 6, 10);
				printf("总得分:%d", pw1->_score);
			LeaveCriticalSection(&cs);
			if (Key(VK_UP) && pw1->_dir != DOWN)
				pw1->_dir = UP;
			else if (Key(VK_DOWN) && pw1->_dir != UP)
				pw1->_dir = DOWN;
			else if (Key(VK_LEFT) && pw1->_dir != RIGHT)
				pw1->_dir = LEFT;
			else if (Key(VK_RIGHT) && pw1->_dir != LEFT)
				pw1->_dir = RIGHT;
			if (Key(VK_SPACE))
			{
				EnterCriticalSection(&cs);
					SetPos(29, 13);
					printf("游戏已暂停,点击空格键继续");
					while (1)
					{
						Sleep(200);
						if (Key(VK_SPACE))
							break;
					}
					int x = 26;
					SetPos(29, 13);
					while (x--)
					printf(" ");
				LeaveCriticalSection(&cs);
			}
			if (Key(0XA5))
			{
				if (pw1->_sleep_time >= 80)
				{
					pw1->_sleep_time -= 30;
					pw1->_food_weight += 2;
					fup = 1;
				}
			}
			if (Key(0XA3))
			{
				if (pw1->_sleep_time <= 320)
				{
					pw1->_sleep_time += 30;
					pw1->_food_weight -= 2;
					fup = -1;
				}
			}
			///
			pSnakeNode pnew = (pSnakeNode)malloc(sizeof(SnakeNode));
			assert(pnew);
			switch (pw1->_dir)
			{
			case UP:
				pnew->y = pw1->_pSnake->y - 1;
				pnew->x = pw1->_pSnake->x;
				break;
			case DOWN:
				pnew->y = pw1->_pSnake->y + 1;
				pnew->x = pw1->_pSnake->x;
				break;
			case LEFT:
				pnew->x = pw1->_pSnake->x - 2;
				pnew->y = pw1->_pSnake->y;
				break;
			case RIGHT:
				pnew->x = pw1->_pSnake->x + 2;
				pnew->y = pw1->_pSnake->y;
				break;
			}
			pnew->next = pw1->_pSnake;
			pw1->_pSnake = pnew;
			KillByselfp(pnew, pw2);
			KillByWallp(pw1);
			pSnakeNode k = OpFood(pnew, pw1->_pFood);
			int x1 = X2, y1 = Y2;
			if (k)
			{
				x1 = pnew->x + 2;
				y1 = pnew->y + 2;
				EnterCriticalSection(&cs);
					SetPos(x1, y1);
					color(116);
					printf("+%d", pw1->_food_weight);
				LeaveCriticalSection(&cs);
				int i = 112;
				while (pnew)
				{
					EnterCriticalSection(&cs);
						SetPos(pnew->x, pnew->y);
						wprintf(L"%lc", BODY);
					LeaveCriticalSection(&cs);
					color(i++);
					pnew = pnew->next;
					if (i == 126)
						i = 112;
					if (i == 119 || i == 112)
						i++;
				}
				color(112);
				printf("\a");
				ChangeFood(pw1, pw2, k);
				PrintFood(pw1->_pFood);
				pw1->_score += pw1->_food_weight;
			}
			else
			{
				while (pnew->next->next)
				{
					EnterCriticalSection(&cs);
						SetPos(pnew->x, pnew->y);
						color(114);
						wprintf(L"%lc", BODY);
					LeaveCriticalSection(&cs);
					pnew = pnew->next;
				}
				color(112);

				EnterCriticalSection(&cs);
					SetPos(pnew->next->x, pnew->next->y);
					printf("  ");
				LeaveCriticalSection(&cs);
				free(pnew->next);
				pnew->next = NULL;
			}
			Sleep(pw1->_sleep_time);

			EnterCriticalSection(&cs);
				SetPos(x1, y1);
				printf("   ");
			LeaveCriticalSection(&cs);


		} while (pw2->_status == OK && pw1->_status == OK);
		return 0;
}
	//玩家2///
DWORD WINAPI th2(LPVOID ps)
{
	pLSnake psk = (pLSnake)ps;
	pSnake pw1 = NULL, pw2 = NULL;
	pw1 = psk->p1;
	pw2 = psk->p2;
	int fp = 0;
		do {

			EnterCriticalSection(&cs);
				color(112);
				SetPos(X2 + 6, 12);
				printf("玩家2 蓝蛇");
			LeaveCriticalSection(&cs);

			EnterCriticalSection(&cs);
				SetPos(X2 + 6, 13);
				if (fp == 1)
				{
					printf("食物分数:"); color(116); printf("%2d", pw2->_food_weight); color(112);
				}
				else if (fp == -1)
				{
					printf("食物分数:"); color(114); printf("%2d", pw2->_food_weight); color(112);
				}
				else
				{
					printf("食物分数:%2d", pw2->_food_weight); 
				}
			LeaveCriticalSection(&cs);

			EnterCriticalSection(&cs);
				color(112);
				SetPos(X2 + 6, 14);
				printf("总得分:%2d", pw2->_score);
			LeaveCriticalSection(&cs);

			if (Key(0x57) && pw2->_dir != DOWN)
				pw2->_dir = UP;
			else if (Key(0x53) && pw2->_dir != UP)
				pw2->_dir = DOWN;
			else if (Key(0x41) && pw2->_dir != RIGHT)
				pw2->_dir = LEFT;
			else if (Key(0x44) && pw2->_dir != LEFT)
				pw2->_dir = RIGHT;
			if (Key(0xA4))
			{
				if (pw2->_sleep_time >= 80)
				{
					pw2->_sleep_time -= 30;
					pw2->_food_weight += 2;
					fp = 1;
				}
			}
			if (Key(0x43))
			{
				if (pw2->_sleep_time <= 320)
				{
					pw2->_sleep_time += 30;
					pw2->_food_weight -= 2;
					fp = -1;
				}
			}
			pSnakeNode pnew = (pSnakeNode)malloc(sizeof(SnakeNode));
			assert(pnew);
			switch (pw2->_dir)
			{
			case UP:
				pnew->y = pw2->_pSnake->y - 1;
				pnew->x = pw2->_pSnake->x;
				break;
			case DOWN:
				pnew->y = pw2->_pSnake->y + 1;
				pnew->x = pw2->_pSnake->x;
				break;
			case LEFT:
				pnew->x = pw2->_pSnake->x - 2;
				pnew->y = pw2->_pSnake->y;
				break;
			case RIGHT:
				pnew->x = pw2->_pSnake->x + 2;
				pnew->y = pw2->_pSnake->y;
				break;
			}
			pnew->next = pw2->_pSnake;
			pw2->_pSnake = pnew;

			KillByselfp(pnew, pw1);

			KillByWallp(pw2);

			pSnakeNode k = OpFood(pnew, pw2->_pFood);
			int x2 = X2, y2 = Y2;
			if (k)
			{
				x2 = pnew->x + 2;
				y2 = pnew->y + 2;
				EnterCriticalSection(&cs);
					SetPos(x2, y2);
					color(116);
					printf("+%d", pw2->_food_weight);
				LeaveCriticalSection(&cs);
				int i = 112;
				while (pnew)
				{
					EnterCriticalSection(&cs);
						SetPos(pnew->x, pnew->y);
						color(i++);
						wprintf(L"%lc", BODY);
					LeaveCriticalSection(&cs);
					pnew = pnew->next;
					if (i == 126)
						i = 112;
					if (i == 119 || i == 112)
						i++;
				}
				color(112);
				printf("\a");
				ChangeFood(pw1, pw2, k);
				PrintFood(pw2->_pFood);
				pw2->_score += pw2->_food_weight;
			}
			else
			{
				while (pnew->next->next)
				{
					EnterCriticalSection(&cs);
						SetPos(pnew->x, pnew->y);
						color(121);
						wprintf(L"%lc", BODY);
					LeaveCriticalSection(&cs);
					pnew = pnew->next;
				}
				EnterCriticalSection(&cs);
					SetPos(pnew->next->x, pnew->next->y);
					printf("  ");
				LeaveCriticalSection(&cs);
				free(pnew->next);
				pnew->next = NULL;
			}
			Sleep(pw2->_sleep_time);
			EnterCriticalSection(&cs);
				SetPos(x2, y2);
				printf("   ");
			LeaveCriticalSection(&cs);
		} while (pw2->_status == OK&&pw1->_status==OK);
	return 0;  // 可返回任意值
}
void KillByWall(pSnake ps)//判断是否撞墙
{
	if ((ps->_pSnake->y == 0) || (ps->_pSnake->y == Y)
		|| (ps->_pSnake->x == 0) || (ps->_pSnake->x == X-2))
		ps->_status = KILL_BY_WALL;
}
void KillByWallp(pSnake ps)//判断是否撞墙
{
	if ((ps->_pSnake->y == 0) || (ps->_pSnake->y == Y2)
		|| (ps->_pSnake->x == 0) || (ps->_pSnake->x == X2 - 2))
		ps->_status = KILL_BY_WALL;
}
void KillByself(pSnake ps)//判断是否撞到自己
{
	pSnakeNode pr = ps->_pSnake;
	pSnakeNode pu = ps->_pSnake->next;
	while (pu)
	{
		if (pu->x == pr->x && pu->y == pr->y)
		{
			ps->_status = KILL_BY_SELF;
			return;
		}
		pu = pu->next;
	}
}
void KillByselfp(pSnakeNode pnew, pSnake ps)//判断是否撞到对方
{
	pSnakeNode pu = ps->_pSnake->next;
	while (pu)
	{
		if (pnew->x == pu->x && pnew->y == pu->y)
		{
			ps->_status = KILL_BY_SELF;
			return;
		}
		pu = pu->next;
	}
}
void GameRun1(pSnake ps)//游戏运行
{
	PrintHelpInfo1();
	int fuk = 0;
	do
	{
		SetPos(64, 12);
		printf("总得分:%d", ps->_score);
		SetPos(64, 13);
		if (fuk == 1)
		{
			printf("食物分数:"); color(116); printf("%2d", ps->_food_weight); color(112);
		}
		else if (fuk == -1)
		{
			printf("食物分数:"); color(114); printf("%2d", ps->_food_weight); color(112);
		}
		else
		{
			printf("食物分数:%2d", ps->_food_weight);
		}
		if (Key(VK_UP) && ps->_dir != DOWN)
			ps->_dir = UP;
		else if (Key(VK_DOWN) && ps->_dir != UP)
			ps->_dir = DOWN;
		else if (Key(VK_LEFT) && ps->_dir != RIGHT)
			ps->_dir = LEFT;
		else if (Key(VK_RIGHT) && ps->_dir != LEFT)
			ps->_dir = RIGHT;
		if (Key(VK_SPACE))
		{
			while (1)
			{
				SetPos(29, 13);
				printf("游戏已暂停,点击空格键继续");
				if (Key(VK_SPACE))
					break;
				Sleep(300);
			}
			SetPos(29, 13);
			int x = 26;
			while (x--)
				printf(" ");
		}
		if (Key(VK_ESCAPE))
			ps->_status = END_NORMAL;
		if (Key(0x09))
		{
			if (ps->_sleep_time >= 80)//if (ps->_sleep_time >= 30)
			{
				ps->_sleep_time -= 30;
				ps->_food_weight += 2;
				fuk = 1;
			}
		}
		if (Key(0x51))
		{
			if (ps->_sleep_time <= 320)
			{
				ps->_sleep_time += 30;
				ps->_food_weight -= 2;
				fuk = -1;
			}
		}
		SnakeMove1(ps);
		KillByself(ps);
		KillByWall(ps);
	} while (ps->_status == OK);
}
void GameRun2(pSnake pu1, pSnake pu2)
{
	LSnake kp;
	pLSnake psk = &kp;
	psk->p1 = pu1;
	psk->p2 = pu2;
	HANDLE thp1 = NULL, thp2 = NULL;
	// 初始化临界区
	InitializeCriticalSection(&cs);

	// 创建线程
	thp1 = CreateThread(NULL, 0, th1, (LPVOID)psk, 0, NULL);
	thp2 = CreateThread(NULL, 0, th2, (LPVOID)psk, 0, NULL);
	assert(thp1);
	assert(thp2);

	// 等待线程结束
	WaitForSingleObject(thp1, INFINITE);
	WaitForSingleObject(thp2, INFINITE);

	// 销毁临界区
	DeleteCriticalSection(&cs);

	// 关闭线程句柄
	CloseHandle(thp1);
	CloseHandle(thp2);
}
void GameEnd(pSnake ps)//游戏结束善后处理
{
	SetPos(29, 13);
	if (ps->_status == KILL_BY_SELF)
	{
		color(116);
		printf("你撞到了自己,游戏结束");
	}
	if (ps->_status == KILL_BY_WALL)
	{
		color(116);
		printf("你撞到了墙,游戏结束");
	}
	free(ps->_pFood);
	while (ps->_pSnake)
	{
		pSnakeNode cur = ps->_pSnake->next;
		free(ps->_pSnake);
		ps->_pSnake = cur;
	}
}
void GameEndp(pSnake ps1, pSnake ps2)
{
	SetPos(29, 13);
	if (ps1->_status == KILL_BY_WALL)
	{
		color(116);
		printf("玩家1撞到了墙,玩家2获胜");
	}
	while (ps1->_pSnake)
	{
		pSnakeNode cur = ps1->_pSnake->next;
		free(ps1->_pSnake);
		ps1->_pSnake = cur;
	}
	SetPos(29, 14);
	if (ps2->_status == KILL_BY_WALL)
	{
		color(116);
		printf("玩家2撞到了墙,玩家1获胜");
	}
	SetPos(29, 15);
	if (ps2->_status == KILL_BY_SELF)
	{
		color(116);
		printf("玩家2死亡,玩家1获胜");
	}
	SetPos(29, 15);
	if (ps1->_status == KILL_BY_SELF)
	{
		color(116);
		printf("玩家1死亡,玩家2获胜");
	}
	free(ps2->_pFood);
	while (ps2->_pSnake)
	{
		pSnakeNode cur = ps2->_pSnake->next;
		free(ps2->_pSnake);
		ps2->_pSnake = cur;
	}
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"Snake.h"
void test()
{
	Snake ps1,ps2;
	ps1._pFood = NULL, ps2._pFood = NULL;
	ps1._pSnake = NULL, ps2._pSnake = NULL;
	setlocale(LC_ALL, "");
	srand((unsigned int)time(NULL));
	int x = 0;
	do
	{
		x = GameStart(&ps1,&ps2);
		if (x == 1)
		{
			GameRun1(&ps1);
			GameEnd(&ps1);
		}
		else
		{
			GameRun2(&ps1, &ps2);
			GameEndp(&ps1,&ps2);
		}
		SetPos(27, 16);
		printf("M键重新开始游戏,Esc键退出");
		color(112);
		while (1)
		{
			if (Key(VK_ESCAPE))
				return;
			if (Key(0x4D))
				break;
			Sleep(23);
		}
	} while (1);
	if (x == 1)
		SetPos(0, Y + 1);
	else
		SetPos(0, Y2 + 1);
}
int main()
{
	test();
	color(127);
	return 0;
}

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

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

相关文章

【while循环】

目录 什么是循环 while语句的执行过程 编程求1*2*3*...*n 所有不超过1000的数中含有数字3的自然数 求数 求数II 编程求1平方2平方...n平方 什么是循环 循环就是重复做同样的事儿使用while语句循环输出1到100 int i 1; while( i < 100 ){cout <<…

ES练习项目-酒店搜索

目录 1 需求分析2 酒店搜索和分页2.1 请求和响应分析2.2 定义实体类&#xff0c;接收请求参数的JSON对象2.3 编写controller&#xff0c;接收页面的请求2.4 编写业务实现&#xff0c;利用RestHighLevelClient实现搜索、分页 3. 酒店结果过滤3.1 请求和响应分析3.2 修改请求参数…

java-stream流案例

需求 代码 Vote类 // 1. 定义一个投票类 public class Vote {private String name;private ArrayList<String> voteList;public Vote(String name, ArrayList<String> voteList) {this.name name;this.voteList voteList;}public String getName() {return nam…

比较LLM和RAG技术:塑造AI的未来

在人工智能&#xff08;AI&#xff09;的动态领域中&#xff0c;两项突破性技术——大型语言模型&#xff08;LLM&#xff09;和检索增强生成&#xff08;RAG&#xff09;因其在理解和生成类人文本方面的变革潜力而脱颖而出。本文开始了LLM和RAG之间的比较之旅&#xff0c;阐明…

ROS2专栏(三) | 理解ROS2的动作

​ 1. 创建一个动作 目标&#xff1a; 在ROS 2软件包中定义一个动作。 1.1 新建包 设置一个 workspace 并创建一个名为 action_tutorials_interfaces 的包&#xff1a; mkdir -p ros2_ws/src #you can reuse existing workspace with this naming convention cd ros2_ws/s…

C++:拷贝构造函数与赋值的区别

目录 拷贝构造函数 拷贝构造函数的使用方法 拷贝构造函数与赋值运算符的区别 谈深拷贝和浅拷贝 浅拷贝 注意: 深拷贝 拷贝构造函数 拷贝构造函数的也是一种构造函数,它的作用是将一个类的成员拷贝到另一个类中,类似于赋值。拷贝构造函数分为深拷贝和浅拷贝。 先来定义一…

【MySQL 5.7安装时候 出现2503报错,解决方案】

MySQL5.7 安装遇 2503问题如何解决 1.能正常安装就点这里2.出现2503问题就看这2.1先看问题2.1.1在官网下载好安装包后&#xff0c;首先先确认安装包是否完整&#xff0c;排除安装包损坏的问题2.1.2 安装时候出现这个2503问题 2.2上解决方案2.2.1 打开任务管理器2.2.2 解决 1.能…

网盘—上传文件

本文主要讲解网盘里面关于文件操作部分的上传文件&#xff0c;具体步骤如下 目录 1、实施步骤&#xff1a; 2、代码实现 2.1、添加上传文件协议 2.2、添加上传文件槽函数 2.3、添加槽函数定义 2.4、关联上传槽函数 2.5、服务器端 2.6、在服务器端添加上传文件请求的ca…

4G远程温湿度传感器在农业中的应用—福建蜂窝物联网科技有限公司

解决方案 农业四情监测预警解决方案 农业四情指的是田间的虫情、作物的苗情、气候的灾情和土壤墒情。“四情”监测预警系统的组成包括管式土壤墒情监测站、虫情测报灯、气象站、农情监测摄像机&#xff0c;可实时监测基地状况,可以提高监测的效率和准确性&#xff0c;为农业生…

分布式系统事务一致性解决方案(基于事务消息)

参考&#xff1a;https://rocketmq.apache.org/zh/docs/featureBehavior/04transactionmessage/ 文章目录 概要错误的方案方案一&#xff1a;业务方自己实现方案二&#xff1a;RocketMQ 事务消息什么是事务消息事务消息处理流程事务消息生命周期使用限制使用示例使用建议 概要 …

进迭时空宣布开源RISC-V芯片的AI核心技术

仟江水商业电讯&#xff08;4月29日 北京 委托发布&#xff09;4月29日&#xff0c;在“创芯生生不息——进迭时空2024年度产品发布会”上&#xff0c;进迭时空CEO、创始人&#xff0c;陈志坚博士宣布将开源进迭时空在自研RISC-V AI CPU上的核心技术&#xff0c;包括AI扩展指令…

数据科学导论续

一、大数据采集的流程和方法 大数据采集的流程和方法 系统日志采集方法 很多互联网企业都有自己的海量数据采集工具&#xff0c;多用于系统日志采集&#xff0c;例如&#xff1a; Flume&#xff1a;分布式日志收集系统&#xff0c;最初由Cloudera开发&#xff0c;现是Apache的…

SPSS之判别分析

SPSS的判别分析过程中默认使用的是Fisher判别法和Bayes判别法&#xff0c;并以前者为主&#xff0c;在指定选项后也可以给出Bayes判别法的结果。 SPSS中判别分析在【分析】—【分类】—【判别】中完成。选定类别变量放入【分组变量】框中&#xff0c;单击定义范围(D)按钮给出类…

《Fundamentals of Power Electronics》——Buck、Boost、Buck-Boost三个电路的CCM-DCM工作特性总结

Buck、Boost、Buck-Boost这三个电路的CCM-DCM工作特性总结如下表所示&#xff1a; Buck、Boost、Buck-Boost这三个电路工作在DCM模式下电压传输比的对比图如下所示&#xff1a; 由上图可知&#xff0c;Buck-Boost电路的工作特性是一条斜率为的直线&#xff0c;Buck电路和Boost电…

IDEA 中的奇技淫巧

IDEA 中的奇技淫巧 书签 在使用ctrlalt方向键跳转时&#xff0c;或者追踪代码时&#xff0c;经常遇到的情况是层级太多&#xff0c;找不到代码的初始位置&#xff0c;入口。可以通过书签的形式去打上一个标记&#xff0c;后续可以直接跳转到书签位置。 标记书签&#xff1a;c…

Qt窗口

QMainWindow Qt 窗⼝ 是通过 QMainWindow类 来实现的。 QMainWindow 是⼀个为⽤⼾提供主窗⼝程序的类&#xff0c;继承⾃ QWidget 类&#xff0c;并且提供了⼀个预定义的 布局。QMainWindow 包含 ⼀个菜单栏&#xff08;menu bar&#xff09;、多个⼯具栏(tool bars)、多个浮动…

Python并发编程:揭开多线程与异步编程的神秘面纱

第一章&#xff1a;并发编程导论 1.1 并发与并行概念解析 1.1.1 并发性与并行性的区别 想象一下繁忙的厨房中多位厨师同时准备不同的菜肴——即使他们共享有限的空间和资源&#xff0c;也能协同工作&#xff0c;这就是并发性的一个生动比喻。并发性意味着多个任务在同一时间…

getchar和putchar的用法

getchar() 和 putchar() 是一对字符输入/输出函数.他们通常比scanf() 和printf() 函数更快更便捷。 getchar()不带任何参数&#xff0c;其实getchar() 和putchar()与scanf() 和printf()功能相似。 接下来博主简单的跟大家解释一下。 1.getchar 通常把输入的字符赋予一个字符变…

uReport2 报表设计

最近刚好用到这个报表工具&#xff0c;刚开始接触都还不会用&#xff0c;学习了一下&#xff0c;在这边做个记录。 数据源 目前报表框架支持和使用的数据源连接有两种方式&#xff1a;添加数据库连接 和添加内置数据源连接。 进入报表设计 http://IP:端口/context-path/urepor…

计算机网络之传输层TCP\UDP协议

UDP协议 用户数据报协议UDP概述 UDP只在IP数据报服务之上增加了很少功能&#xff0c;即复用分用和差错检测功能 UDP的主要特点&#xff1a; UDP是无连接的&#xff0c;减少开销和发送数据之前的时延 UDP使用最大努力交付&#xff0c;即不保证可靠交付&#xff0c;可靠性由U…