自制贪吃蛇小游戏

news2024/11/26 8:53:04

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

控制台程序设置-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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python | Leetcode Python题解之第55题跳跃游戏

题目&#xff1a; 题解&#xff1a; class Solution:def canJump(self, nums: List[int]) -> bool:n, rightmost len(nums), 0for i in range(n):if i < rightmost:rightmost max(rightmost, i nums[i])if rightmost > n - 1:return Truereturn False

AHB传输---等待传输

等待传输 slave在需要更多时间支持或采样数据时使用HREADYOUT信号插入等待状态。在等待传输期间&#xff0c;master对传输类型和地址的更改受到限制。 1. 在等待状态下传输类型的变化 当slave请求等待状态时&#xff0c;master不得更改传输类型&#xff0c;除非是以下状态&a…

Spring AOP是什么?可以拿它做什么?

Spring AOP&#xff08;Aspect-Oriented Programming&#xff0c;面向切面编程&#xff09;是Spring框架提供的一种重要特性&#xff0c;它通过在应用程序的横切关注点&#xff08;Cross-cutting Concerns&#xff09;中&#xff0c;将重复性的代码和逻辑分离出来&#xff0c;以…

青年夜校 | 李良济中医课堂,赋能“夜生活”,传承中医药文化

下班后的苏州年轻人都在干什么&#xff1f; 约饭看电影&#xff1f; 宅家打游戏&#xff1f; 最近&#xff0c;一种全新的“夜生活”模式开启啦&#xff01; 那就是—— 去家门口的夜校&#xff0c;学习中医和中药&#xff01; 1 家门口的夜校 解锁正确的中医养生法 4月…

Matlab实现CNN-LSTM模型,对一维时序信号进行分类

1、利用Matlab2021b训练CNN-LSTM模型&#xff0c;对采集的一维时序信号进行分类二分类或多分类 2、CNN-LSTM时序信号多分类执行结果截图 训练进度&#xff1a; 网络分析&#xff1a; 指标变化趋势&#xff1a; 代码下载方式&#xff08;代码含数据集与模型构建&#xff0c;附…

LabVIEW自动剪板机控制系统

LabVIEW自动剪板机控制系统 随着工业自动化的快速发展&#xff0c;钣金加工行业面临着生产效率和加工精度的双重挑战。传统的手动或脚踏式剪板机已无法满足现代生产的高效率和高精度要求&#xff0c;因此&#xff0c;自动剪板机控制系统的研究与开发成为了行业发展的必然趋势。…

消失了一个月,失踪人口回归!

大家好&#xff0c;我是前端队长。前端程序员&#xff0c;2023年开始玩副业。玩过AI绘画&#xff0c;公众号爆文项目&#xff0c;目前在做AI代写&#xff0c;累计变现五位数。 最近比较忙&#xff0c;而且没有意识到持续分享的重要性。 周六的时候&#xff0c;参加了武汉老徐合…

prompt提示词:AI英语词典,让AI教你学英语,通过AI实现一个网易有道英语词典

目录 英语词典提问技巧效果图&#xff1a;提示词&#xff1a; 英语词典提问技巧 随着AI工具的出现&#xff0c;学英语也可以变得很简单&#xff0c;大家可以直接通过AI 来帮助自己&#xff0c;提高记忆单词的效率&#xff0c;都可以不需要网易有道词典了&#xff0c;今天我教大…

Docker容器:数据管理与镜像的创建(主要基于Dockerfile)

目录 一、Docker 数据管理 1、数据卷&#xff08;Data Volumes&#xff09; 2、数据卷容器&#xff08;DataVolumes Containers&#xff09; 二、容器互联&#xff08;使用centos镜像&#xff09; 三、Docker 镜像的创建 1、基于现有镜像创建 2、基于本地模板创建 3、基…

不同状态空间模型的实验对比(二)

对五个下游任务进行了实验比较&#xff0c;包括单/多标签分类、视觉对象跟踪、像素级分割、图像到文本生成和人/车辆再识别。 论文&#xff1a;https://arxiv.org/abs/2404.09516 作者单位&#xff1a;安徽大学、哈尔滨工业大学、北京大学更多相关工作将在以下GitHub上不断更新…

JavaScript 的基本术语大全

文章目录 1、概述2、基本术语2.1、有效负载 (Payload)2.2、ReadableStream2.3、模块系统2.4、DOM (Document Object Model)2.5、事件 (Events)2.6、活动委托 (Event Delegation)2.7、内容安全策略 (CSP)2.8、渐进增强和优雅降级2.9、JSON (JavaScript Object Notation)2.10、AJ…

支付宝沙盒(java使用支付宝)springboot

目录 前言 注册账号&#xff08;直接搜索支付宝沙盒&#xff09; ​编辑 具体代码编写 Application配置(按自己需求添加) config&#xff08;这里需要亲自添加appid&#xff0c;privateKey&#xff0c;publicKey&#xff09; controller类 Service类 ServiceImpl类 运…

OpenNJet产品体验丨从零部署一个炫酷的Web服务器

本文记录了使用OpenNJet从零部署一个Web服务器的心得体会。 OpenNJet官方网站&#xff1a;https://njet.org.cn/ 一、基本信息 产品名称 OpenNJet 体验版本 2.1.0 体验设备 VMware16Ubuntu18.04 体验时间 2024.4.23 体验耗时 1.5 h 二、产品信息 产品简介&#x…

【13-支持向量机(SVM):Scikit-learn中的分类与回归】

文章目录 前言理解SVM核心概念SVM的优势SVM的劣势Scikit-learn中的SVM实现安装与导入数据准备SVM分类SVM回归调优与最佳实践总结前言 支持向量机(SVM)是一种强大的机器学习算法,用于解决分类、回归和异常检测问题。它的核心思想是找到一个最优超平面,使得不同类别之间的边界…

一文了解云原生应用引擎的领跑者:OpenNJet

一文了解云原生应用引擎的领跑者&#xff1a;OpenNJet 1. 什么是应用引擎2. NGINX 架构与 NJet架构的区别3. OpenNJet 编译与安装步骤3.1 配置编译环境-CentOS 编译环境配置3.2 编译代码 4. OpenNJet 的基本使用4.1 系统目录结构及功能说明4.2 基础命令 5. 快速上手-如何通过 O…

4.Docker本地镜像发布至阿里云仓库、私有仓库、DockerHub

文章目录 0、镜像的生成方法1、本地镜像发布到阿里云仓库2、本地镜像发布到私有仓库3、本地镜像发布到Docker Hub仓库 Docker仓库是集中存放镜像的地方&#xff0c;分为公共仓库和私有仓库。 注册服务器是存放仓库的具体服务器&#xff0c;一个注册服务器上可以有多个仓库&…

IP纯净度对跨境电商有什么直接影响?

IP纯净度对跨境电商具有直接且深远的影响。在跨境电商的运作中&#xff0c;IP地址扮演着至关重要的角色&#xff0c;而IP纯净度则直接关系到跨境电商的网络安全性、访问效果以及业务竞争力。 第一点&#xff0c;纯净的IP地址对于提升跨境电商的网络安全性具有关键作用&#xf…

AI项目二十:基于YOLOv8实例分割的DeepSORT多目标跟踪

若该文为原创文章&#xff0c;转载请注明原文出处。 前面提及目标跟踪使用的方法有很多&#xff0c;更多的是Deepsort方法。 本篇博客记录YOLOv8的实例分割deepsort视觉跟踪算法。结合YOLOv8的目标检测分割和deepsort的特征跟踪&#xff0c;该算法在复杂环境下确保了目标的准…

信创 | 信创产品行业有哪些?已取得了哪些进展?

信创产业是一条庞大的产业链&#xff0c;涉及IT基础设施产品&#xff08;如CPU芯片、服务器、存储、交换机、路由器等&#xff09;&#xff0c;以及基础软件、应用软件、网络安全等领域。信创产业的核心目标是建立自主可控的信息技术底层架构和标准&#xff0c;全面推进国产替代…