项目:贪吃蛇实现

news2025/6/3 10:31:23

头文件 snake.h

#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<locale.h>
#include<stdbool.h>
#include<time.h>

#define POS_X 24

#define POS_Y 5
#define BODY L'●' 
#define FOOD L'★'
#define KEY_PRESS(VK)  ((GetAsyncKeyState(VK)&0x1) ? 1 : 0)

enum DIRECTION
{
	UP = 1,
	DOWN,
	LEFT,
	RIGHT

};

enum GAME_STATES
{
	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_STATES _state; //游戏的状态
	int _food_weight;//食物的分数
	int _score;//总成绩
	int _sleep_time;//休息时间,时间越短速度越快
}Snake, * pSnake;

void GameStart(pSnake ps);

void WelcomGame();

void CreatMap();

void InitSnake(pSnake ps);

void CreatFood(pSnake ps);

void GameRun(pSnake ps);

void SnakeMove(pSnake ps);

int NextIsFood(pSnakeNode pn, pSnake ps);

void EatFood(pSnakeNode psn, pSnake ps);

void NoFood(pSnakeNode psn, pSnake ps);

int KillByWall(pSnake ps);

int KillBySelf(pSnake ps);

void GameOver(pSnake ps);

snake.c

#include"snake.h"

//设置光标的坐标
void SetPos(short x, short y)
{
	COORD pos = { x, y };
	HANDLE hOutput = NULL;
	//获取标准输出的句柄(⽤来标识不同设备的数值)
	hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	//设置标准输出上光标的位置为pos
	SetConsoleCursorPosition(hOutput, pos);
}
void WelcomGame()
{
	SetPos(40,14);
	wprintf(L"欢迎来到贪吃蛇小游戏\n");
	SetPos(42, 20);
	system("pause");
	system("cls");
	SetPos(25, 14);
	wprintf(L"用↑.↓.←.→ 来控制蛇的移动,F3加速F4减速\n");
	SetPos(25, 15);
	wprintf(L"加速获得的分数更多\n");
	SetPos(42, 20);
	system("pause");
	system("cls");
}
void CreatMap()
{
	int i = 0;
	//上
	for(i = 0; i < 29; i++)
	{
		wprintf(L"%lc", L'□');
	}
	//下
	SetPos(0, 26);
	for (i = 0; i < 29; i++)
	{
		wprintf(L"%lc", L'□');
	}
	//左
	for (i = 1; i <= 25; i++)
	{
		SetPos(0, i);
		wprintf(L"%lc", L'□');
	}
	//右
	for (i = 1; i <= 25; i++)
	{
		SetPos(56, i);
		wprintf(L"%lc", L'□');
	}
	
}

void InitSnake(pSnake ps)
{
	pSnakeNode cur = NULL;
	int i = 0;
	for (i = 0;i<5; i++)
	{
		cur = (pSnakeNode)malloc(sizeof(SnakeNode));
		if (cur == NULL)
		{
			perror("malloc");
			exit(1);
		}
		cur->next = NULL;
		cur->x = POS_X + 2 * i;
		cur->y = POS_Y;
		//头插法
		if (ps->_pSnake == NULL)
		{
			ps->_pSnake = cur;
		}
		else//非空
		{
			cur->next = ps->_pSnake;
			ps->_pSnake = cur;
		}

	}
	//打印蛇的身体
	cur = ps->_pSnake;
	while (cur)
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	//设置游戏初始数据
	ps->_state = OK;//游戏状态
	ps->_dir = RIGHT;//蛇的初始方向朝右
	ps->_food_weight = 10;//一个食物10分
	ps->_score = 0;//初始为0分
	ps->_sleep_time = 200;//单位ms
	
}

void CreatFood(pSnake ps)
{
	int x = 0;
	int y = 0;
again:
	do
	{
		x = rand() % 53 + 2;
	    y = rand() % 25 + 1;
	} while (x % 2 != 0);
	

	//x y 的坐标不能和蛇的身体冲突
	pSnakeNode cur = ps->_pSnake;
	while (cur)
	{
		if (x == cur->x && y == cur->y)
		{
			goto again;
		}
		cur = cur->next;
	}

	//创建食物的节点

	pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (pFood == NULL)
	{
		perror("malloc");
		exit(1);
	}
	pFood->x = x;
	pFood->y = y;
	pFood->next = NULL;

	SetPos(x, y);
	wprintf(L"%lc", FOOD);
	ps->_pFood = pFood;
	
}

void GameStart(pSnake ps)
{
	//先设置窗口大小,光标隐藏
	system("mode con cols=100 lines=30");
	system("title 贪吃蛇");
	HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	//隐藏光标操作
    CONSOLE_CURSOR_INFO CursorInfo;
	GetConsoleCursorInfo(houtput, &CursorInfo);//获取控制台光标信息
    CursorInfo.bVisible = false; //隐藏控制台光标
	SetConsoleCursorInfo(houtput, &CursorInfo);//设置控制台光标状态

	//getchar();
	//初始化游戏
	//打印环境界面
	WelcomGame();
	//地图绘制
	CreatMap();
	//创建蛇
	InitSnake(ps);
	//创建食物
	CreatFood(ps);
}
void PrintHelpInfo()
{
	//打印提⽰信息
	SetPos(64, 14);
	wprintf(L"先按esc启动贪吃蛇\n");
	SetPos(64, 15);
	wprintf(L"不能穿墙,不能咬到自己\n");
	SetPos(64, 16);
	wprintf(L"用↑.↓.←.→ 来控制蛇的移动\n");
	SetPos(64, 17);
	wprintf(L"F3 为加速,F4为减速\n");
	SetPos(64, 18);
	wprintf(L"ESC :退出游戏.space:暂停游戏");
	SetPos(64, 20);
	wprintf(L"景风制作");
	

}

//pSnakeNode psn 是下⼀个节点的地址
//pSnake ps 维护蛇的指针
int NextIsFood(pSnakeNode psn, pSnake ps)
{
	return (psn->x == ps->_pFood->x) && (psn->y == ps->_pFood->y);
}

//pSnakeNode psn 是下⼀个节点的地址
//pSnake ps 维护蛇的指针
void EatFood(pSnakeNode psn, pSnake ps)
{
	//头插法
	psn->next = ps->_pSnake;
	ps->_pSnake = psn;
	//打印蛇
	pSnakeNode cur = ps->_pSnake;
	while (cur)
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%c", BODY);
		cur = cur->next;
	}
	ps->_score += ps->_food_weight;
	//释放⻝物节点
	free(ps->_pFood);
	//创建新的⻝物
	CreatFood(ps);

}

void NoFood(pSnakeNode psn, pSnake ps)
{
	//头插法
	psn->next = ps->_pSnake;
	ps->_pSnake = psn;
	//打印蛇
    pSnakeNode cur = ps->_pSnake;
	while (cur->next->next)
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%c", BODY);
		cur = cur->next;
	}
	//最后⼀个位置打印空格,然后释放节点
	SetPos(cur->next->x, cur->next->y);
	printf("  ");
	free(cur->next);
	cur->next = NULL;
}

void SnakeMove(pSnake ps)
{
	//创建下⼀个节点
    pSnakeNode pNextNode = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (pNextNode == NULL)
	{
		perror("SnakeMove()::malloc()");
		return;
	}
	//确定下⼀个节点的坐标,下⼀个节点的坐标根据,蛇头的坐标和⽅向确定
	switch(ps->_dir)
	{
	 case UP:
	 {
		pNextNode->x = ps->_pSnake->x;
		pNextNode->y = ps->_pSnake->y - 1;
	 }
		break;
	 case DOWN:
	 {
		pNextNode->x = ps->_pSnake->x;
	    pNextNode->y = ps->_pSnake->y + 1; 
	 }
		break;
	 case LEFT:
	 {
		pNextNode->x = ps->_pSnake->x-2;
		pNextNode->y = ps->_pSnake->y;
	 }
		break;
	 case RIGHT:
	  {
		 pNextNode->x = ps->_pSnake->x+2;
		 pNextNode->y = ps->_pSnake->y;
	  }
		 break;
	}
	//如果下⼀个位置就是食物
	if (NextIsFood(pNextNode, ps))
	{
		EatFood(pNextNode, ps);
	}
	else//如果没有食物
    {
		NoFood(pNextNode, ps);
	}
	KillByWall(ps);
	KillBySelf(ps);

}

void pause()
{
	while (1)
	{
		Sleep(300);
		if (KEY_PRESS(VK_ESCAPE))
		{
			break;
		}
	}
}
int KillByWall(pSnake ps)
{
	if ((ps->_pSnake->x == 0)
		|| (ps->_pSnake->x == 56)
		|| (ps->_pSnake->y == 0)
		|| (ps->_pSnake->y == 26))
	{
		ps->_state = KILL_BY_WALL;
		return 1;
	}
	
	return 0;
}

int KillBySelf(pSnake ps)
{
	pSnakeNode cur = ps->_pSnake->next;
	while (cur)
	{
		if ((ps->_pSnake->x == cur->x)
			&& (ps->_pSnake->y == cur->y))
		{
			ps->_state = KILL_BY_SELF;
			return 1;
		}
		cur = cur->next;
	}
	
	return 0;
}

void GameRun(pSnake ps)
{
	//打印右侧帮助信息
    PrintHelpInfo();
	do
	{
		SetPos(64, 10);
		printf("得分:% d ", ps->_score);
		printf("每个食物得分:%2d分", ps->_food_weight);
		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_SPACE))
		{
			pause();
		}
		else if (KEY_PRESS(VK_ESCAPE))
		{
			ps->_state = END_NORMAL;
			break;
		}
		else if (KEY_PRESS(VK_F3))
		{
			if (ps->_sleep_time >= 50)
			{
				ps->_sleep_time -= 30;
				ps->_food_weight += 2;//⼀个⻝物分数最⾼是20分

			}
		}
		else if (KEY_PRESS(VK_F4))
		{
			if (ps->_sleep_time < 350)
			{
				ps->_sleep_time += 30;
				ps->_food_weight -= 2;//⼀个⻝物分数最⾼是20分

			}
		}
		//蛇每次⼀定之间要休眠的时间,时间短,蛇移动速度就快
		Sleep(ps->_sleep_time);
		SnakeMove(ps);

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

}

void GameOver(pSnake ps)
{
	pSnakeNode cur = ps->_pSnake;
	SetPos(24, 12);
	switch (ps->_state)
	{
	case END_NORMAL:
		printf("您主动退出游戏\n");
			break;
	case KILL_BY_SELF:
		printf("您撞上自己了,游戏结束!\n");
		SetPos(0, 27);
			break;
	case KILL_BY_WALL:
		printf("您撞墙了,游戏结束!\n");
		SetPos(0, 27);
			break;
	}
	//释放蛇⾝的节点

	while (cur)
	{
		pSnakeNode del = cur;
		cur = cur->next;
		free(del);
	}
}

test.c

#include"snake.h"

void test()
{
	int ch = 0;
	do
	{
		system("cls");
		//创建贪吃蛇
		Snake snake = { 0 };
		//初始化游戏
		//打印环境界面
		//功能介绍
		//地图绘制
		//创建蛇
		//创建食物
		//设置游戏相关数据
		GameStart(&snake);
		//运行游戏
		GameRun(&snake);
		//结束游戏,善后工作
		GameOver(&snake);
		SetPos(20, 15);
		printf("再来一局吗(y/n)\n");
		ch = getchar();
		getchar();
		SetPos(0, 27);
	} while(ch=='y'||ch=='Y');
}

int main()
{

	setlocale(LC_ALL, "");
	srand((unsigned int)time(NULL));
	test();
	return 0;
}

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

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

相关文章

【Java基础05】面向对象01

文章目录 1. 设计对象并使用1.1 类与对象1.2 封装1.2.1 private关键字1.2.2 this关键字成员变量和局部变量的区别 1.2.3 构造方法1.2.4 标准JavaBean类 1.3 对象内存图 本文部分参考这篇博客 1. 设计对象并使用 1.1 类与对象 public class 类名{1、成员变量(代表属性,一般是名…

设计模式:观察者模式 - 实战

一、观察者模式场景 1.1 什么是观察者模式&#xff1f; 观察者模式&#xff08;Observer Pattern&#xff09;观察者模式是一种行为型设计模式&#xff0c;用于定义一种一对多的依赖关系&#xff0c;当对象的状态发生变化时&#xff0c;所有依赖于它的对象都会自动收到通知并更…

YOLOv8 移动端升级:借助 GhostNetv2 主干网络,实现高效特征提取

文章目录 引言GhostNetv2概述GhostNet回顾GhostNetv2创新 YOLOv8主干网络改进原YOLOv8主干分析GhostNetv2主干替换方案整体架构设计关键模块实现 完整主干网络实现YOLOv8集成与训练模型集成训练技巧 性能对比与分析计算复杂度对比优势分析 部署优化建议结论与展望 引言 目标检…

国产化Word处理控件Spire.Doc教程:在 C# 中打印 Word 文档终极指南

在 C# 中以编程方式打印 Word 文档可以简化业务工作流程、自动化报告和增强文档管理系统。本指南全面探讨如何使用Spire.Doc for .NET打印 Word 文档&#xff0c;涵盖从基本打印到高级自定义技术的所有内容。我们将逐步介绍每种情况下的实际代码示例&#xff0c;确保您能够在实…

谷歌:贝叶斯框架优化LLM推理反思

&#x1f4d6;标题&#xff1a;Beyond Markovian: Reflective Exploration via Bayes-Adaptive RL for LLM Reasoning &#x1f310;来源&#xff1a;arXiv, 2505.20561 &#x1f31f;摘要 通过强化学习 (RL) 训练的大型语言模型 (LLM) 表现出强大的推理能力和紧急反射行为&a…

Qt SQL模块基础

Qt SQL模块基础 一、Qt SQL模块支持的数据库 官方帮助文档中的Qt支持的数据库驱动如下图&#xff1a; Qt SQL 模块中提供了一些常见的数据库驱动&#xff0c;包括网络型数据库&#xff0c;如Qracle、MS SQL Server、MySQL等&#xff0c;也包括简单的单机型数据库。 Qt SQL支…

[9-3] 串口发送串口发送+接收 江协科技学习笔记(26个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26中断

如何在Qt中绘制一个带有动画的弧形进度条?

如何在Qt中绘制一个弧形的进度条 在图形用户界面开发中&#xff0c;进度指示控件&#xff08;Progress Widget&#xff09;是非常常见且实用的组件。CCArcProgressWidget 是一个继承自 QWidget 的自定义控件&#xff0c;用于绘制圆弧形进度条。当然&#xff0c;笔者看了眼公开…

国产三维CAD皇冠CAD(CrownCAD)建模教程:汽车电池

在线解读『汽车电池』的三维建模流程&#xff0c;讲解3D草图、保存实体、拉伸凸台/基体、设置外观等操作技巧&#xff0c;一起和皇冠CAD&#xff08;CrownCAD&#xff09;学习制作步骤吧&#xff01; 汽车电池&#xff08;通常指铅酸蓄电池或锂离子电池&#xff09;是车辆电气系…

VMware-workstation安装教程--超详细(附带安装包)附带安装CentOS系统教程

VMware-workstation安装教程--超详细&#xff08;附带安装包&#xff09;附带安装CentOS系统教程 一、下载软件VMwware二、下载需要的镜像三、在VMware上安装系统 一、下载软件VMwware 二、下载需要的镜像 三、在VMware上安装系统 VMware 被 Broadcom&#xff08;博通&#x…

2025年- H63-Lc171--33.搜索旋转排序数组(2次二分查找,需二刷)--Java版

1.题目描述 2.思路 输入&#xff1a;旋转后的数组 nums&#xff0c;和一个整数 target 输出&#xff1a;target 在 nums 中的下标&#xff0c;如果不存在&#xff0c;返回 -1 限制&#xff1a;时间复杂度为 O(log n)&#xff0c;所以不能用遍历&#xff0c;必须使用 二分查找…

3D-激光SLAM笔记

目录 定位方案 编译tbb ros2humble安装 命令 colcon commond not found 栅格地图生成&#xff1a; evo画轨迹曲线 安装gtsam4.0.2 安装ceres-solver1.14.0 定位方案 1 方案一&#xff1a;改动最多 fasterlio 建图&#xff0c;加闭环优化&#xff0c;参考fast-lio增加关…

HomeKit 基本理解

概括 HomeKit 将用户的家庭自动化信息存储在数据库中&#xff0c;该数据库由苹果的内置iOS家庭应用程序、支持HomeKit的应用程序和其他开发人员的应用程序共享。所有这些应用程序都使用HomeKit框架作为对等程序访问数据库. Home 只是相当于 HomeKit 的表现层,其他应用在实现 …

(LeetCode 每日一题) 909. 蛇梯棋 (广度优先搜索bfs)

题目&#xff1a;909. 蛇梯棋 思路&#xff1a;广度优先搜索bfs队列&#xff0c;时间复杂度0(6*n^2)。 细节看注释 C版本&#xff1a; class Solution { public:int snakesAndLadders(vector<vector<int>>& board) {int nboard.size();// vis[i]&#xff1a;…

生成https 证书步骤

一、OpenSSL下载 OpenSSL下载地址&#xff1a; https://slproweb.com/products/Win32OpenSSL.html 如果电脑是64位的就选择64位的 二、OpenSSL安装 双击打开.exe文件 开始安装&#xff0c;一直下一步&#xff0c;不过需要注意的是默认安装路径是C盘&#xff0c;可更改到其他盘…

设计模式——适配器设计模式(结构型)

摘要 本文详细介绍了适配器设计模式&#xff0c;包括其定义、核心思想、角色、结构、实现方式、适用场景及实战示例。适配器模式是一种结构型设计模式&#xff0c;通过将一个类的接口转换成客户端期望的另一个接口&#xff0c;解决接口不兼容问题&#xff0c;提高系统灵活性和…

小黑大语言模型通过设计demo进行应用探索:langchain中chain的简单理解demo

chain简介 LangChain 中的 Chain 模块‌在开发大型语言模型&#xff08;LLM&#xff09;驱动的应用程序中起着至关重要的作用。Chain是串联LLM能力与实际业务的关键桥梁&#xff0c;通过将多个工具和模块按逻辑串联起来&#xff0c;实现复杂任务的多步骤流程编排。 案例 通过…

秒杀系统—5.第二版升级优化的技术文档三

大纲 8.秒杀系统的秒杀库存服务实现 9.秒杀系统的秒杀抢购服务实现 10.秒杀系统的秒杀下单服务实现 11.秒杀系统的页面渲染服务实现 12.秒杀系统的页面发布服务实现 8.秒杀系统的秒杀库存服务实现 (1)秒杀商品的库存在Redis中的结构 (2)库存分片并同步到Redis的实现 (3…

【STM32】HAL库 之 CAN 开发指南

基于stm32 f407vet6芯片 使用hal库开发 can 简单讲解一下can的基础使用 CubeMX配置 这里打开CAN1 并且设置好波特率和NVIC相关的配置 波特率使用波特率计算器软件 使用采样率最高的这段 填入 得到波特率1M bit/s 然后编写代码 环形缓冲区 #include "driver_buffer.h&qu…

DeepSeek R1-0528 新开源推理模型(免费且快速)

DeepSeek推出了新模型,但这不是R2! R1-0528是DeepSeek的最新模型,在发布仅数小时后就在开源社区获得了巨大关注。 这个悄然发布的模型DeepSeek R1-0528,已经开始与OpenAI的o3一较高下。 让我来详细介绍这次更新的新内容。 DeepSeek R1-0528 发布 DeepSeek在这次发布中采…