当前位置: 首页 > news >正文

贪吃蛇(C语言实现)

  贪食蛇(也叫贪吃蛇)是一款经典的小游戏。

——————————————————————

  本博客实现使用C语言在Windows环境的控制台中模拟实现贪吃蛇小游戏。

实行的基本功能:

•  贪吃蛇地图的绘制

•  蛇吃食物的功能(上、下、左、右方向键来控制蛇的方向)

•  蛇撞墙死亡

•  蛇撞自身死亡

•  计算得分

•  蛇身加速、减速

•  暂停游戏

主要框架(主要函数):

GameStrat();//游戏开始前的初始化
GameRun();//玩游戏的过程
GameEnd();//善后工作(节点的释放)

游戏流程设计:

参考代码:

snake.h

#pragma once#include <locale.h>
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <stdbool.h>#define WALL L'□'
#define BODY L'●'
#define FOOD L'★'//蛇默认的起始坐标
#define POS_X 24
#define POS_Y 5#define KEY_PRESS(VK)  ( (GetAsyncKeyState(VK) & 0x1) ? 1 : 0 )//游戏的状态
enum GAME_STATUS
{OK=1,//正常运行ESC, //按了ESC键退出,正常退出KILL_BY_WALL,//撞墙KILL_BY_SELF //撞到自身
};//蛇行走的方向
enum DIRECTION
{UP=1,DOWN,LEFT,RIGHT
};//蛇身结点的定义
typedef struct SnakeNode
{int x;int y;struct SnakeNode* next;
}SnakeNode, * pSnakeNode;//贪吃蛇
typedef struct Snake
{pSnakeNode pSnake;//维护整条蛇的指针,是指向蛇头pSnakeNode pFood;//指向食物的指针int Score;//当前累积的分数int FoodWeight;//一个食物的分数int SleepTime;//蛇休眠的时间,休眠的时间越短,蛇的速度越快,休眠的时间越长,蛇的速度越慢enum GAME_STATUS status;//游戏当前的状态enum DIRECTION dir;//蛇当前走的方向//...
}Snake, * pSnake;//定位控制台光标位置
void SetPos(int x, int y);//游戏开始前的准备
void GameStart(pSnake ps);//打印欢迎界面
void WelcomeToGame();//绘制地图
void CreateMap();//初始化贪吃蛇
void InitSnake(pSnake ps);//创建食物
void CreateFood(pSnake ps);//游戏运行的整个逻辑
void GameRun(pSnake ps);//打印帮助信息
void PrintHelpInfo();//蛇移动的函数- 每次走一步
void SnakeMove(pSnake ps);//判断蛇头的下一步要走的位置处是否是食物
int NextIsFood(pSnake ps, pSnakeNode pNext);//下一步要走的位置处就是食物,就吃掉食物
void EatFood(pSnake ps, pSnakeNode pNext);//下一步要走的位置处不是食物,不吃食物
void NotEatFood(pSnake ps, pSnakeNode pNext);//检测是否撞墙
void KillByWall(pSnake ps);//检测是否撞自己
void KillBySelf(pSnake ps);//游戏结束的资源释放
void GameEnd(pSnake ps);

snake.c

#define _CRT_SECURE_NO_WARNINGS 1#include "snake.h"void SetPos(int x,int y)
{//获得设备句柄HANDLE hanlde = GetStdHandle(STD_OUTPUT_HANDLE);//根据句柄设置光标的位置COORD pos = { x, y };SetConsoleCursorPosition(hanlde, pos);
}void WelcomeToGame()
{//欢迎信息SetPos(35, 10);printf("欢迎来到贪吃蛇小游戏\n");SetPos(38, 20);system("pause");system("cls");//功能介绍信息SetPos(15, 10);printf("用 ↑ . ↓ . ← . → 来控制蛇的移动,F3是加速,F4是减速");SetPos(15, 11);printf("加速能得到更高的分数");SetPos(38, 20);system("pause");system("cls");
}void CreateMap()
{int i = 0;//上SetPos(0, 0);for (i = 0; i <= 56; i += 2){wprintf(L"%lc", WALL);}//下SetPos(0, 26);for (i = 0; i <= 56; i += 2){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 InitSnake(pSnake ps)
{//创建5个蛇身的结点pSnakeNode cur = NULL;int i = 0;for (i = 0; i < 5; i++){cur = (pSnakeNode)malloc(sizeof(SnakeNode));if (cur == NULL){perror("InitSnake():malloc()");return;}cur->x = POS_X + 2 * i;cur->y = POS_Y;cur->next = NULL;//头插法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->dir = RIGHT;ps->FoodWeight = 10;ps->pFood = NULL;ps->Score = 0;ps->SleepTime = 200;ps->status = OK;
}void CreateFood(pSnake ps)
{int x = 0;int y = 0;again:do{x = rand() % 53 + 2;y = rand() % 24 + 1;} while (x % 2 != 0);//坐标和蛇的身体的每个节点的做坐标比较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("CreateFood()::malloc()");return;}pFood->x = x;pFood->y = y;ps->pFood = pFood;SetPos(x, y);wprintf(L"%lc", FOOD);}void GameStart(pSnake ps)
{//设置控制台的信息,窗口大小,窗口名system("mode con cols=100 lines=30");system("title 贪吃蛇");//隐藏光标HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);CONSOLE_CURSOR_INFO CursorInfo;GetConsoleCursorInfo(handle, &CursorInfo);//获取控制台光标信息CursorInfo.bVisible = false;SetConsoleCursorInfo(handle, &CursorInfo);//打印欢迎信息WelcomeToGame();//绘制地图CreateMap();//初始化蛇InitSnake(ps);//创建食物CreateFood(ps);
}void PrintHelpInfo()
{SetPos(62, 15);printf("1.不能穿墙,不能咬到自己");SetPos(62, 16);printf("2.用 ↑.↓.←.→ 来控制蛇的移动"); SetPos(62, 17);printf("3.F3是加速,F4是减速");SetPos(62, 19);printf("版权@比特就业课");
}void pause()
{while (1){Sleep(100);if (KEY_PRESS(VK_SPACE)){break;}}
}int NextIsFood(pSnake ps, pSnakeNode pNext)
{if (ps->pFood->x == pNext->x && ps->pFood->y == pNext->y)return 1;//下一个坐标处是食物elsereturn 0;
}void EatFood(pSnake ps, pSnakeNode pNext)
{pNext->next = ps->pSnake;ps->pSnake = pNext;//打印蛇pSnakeNode cur = ps->pSnake;while (cur){SetPos(cur->x, cur->y);wprintf(L"%lc", BODY);cur = cur->next;}ps->Score += ps->FoodWeight;//释放旧的食物free(ps->pFood);//新建食物CreateFood(ps);
}void NotEatFood(pSnake ps, pSnakeNode pNext)
{//头插法pNext->next = ps->pSnake;ps->pSnake = pNext;//释放尾结点pSnakeNode cur = ps->pSnake;while (cur->next->next){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->pSnake->x == 0 ||ps->pSnake->x == 56 ||ps->pSnake->y == 0 ||ps->pSnake->y == 26){ps->status = KILL_BY_WALL;}
}//检测是否撞自己
void KillBySelf(pSnake ps)
{pSnakeNode cur = ps->pSnake->next;//从第二个节点开始while (cur){if (cur->x == ps->pSnake->x && cur->y == ps->pSnake->y){ps->status = KILL_BY_SELF;return;}cur = cur->next;}
}void SnakeMove(pSnake ps)
{pSnakeNode pNext = (pSnakeNode)malloc(sizeof(SnakeNode));if (pNext == NULL){perror("SnakeMove()::malloc()");return;}pNext->next = NULL;switch (ps->dir){case UP:pNext->x = ps->pSnake->x;pNext->y = ps->pSnake->y - 1;break;case DOWN:pNext->x = ps->pSnake->x;pNext->y = ps->pSnake->y + 1;break;case LEFT:pNext->x = ps->pSnake->x-2;pNext->y = ps->pSnake->y;break;case RIGHT:pNext->x = ps->pSnake->x+2;pNext->y = ps->pSnake->y;break;}//下一个坐标处是否是食物if (NextIsFood(ps, pNext)){//是食物就吃掉EatFood(ps, pNext);}else{//不是食物就正常一步NotEatFood(ps, pNext);}//检测撞墙KillByWall(ps);//检测撞到自己KillBySelf(ps);
}void GameRun(pSnake ps)
{//打印帮助信息PrintHelpInfo();do{//当前的分数情况SetPos(62, 10);printf("总分:%5d\n", ps->Score);SetPos(62, 11);printf("食物的分值:%02d\n", ps->FoodWeight);//检测按键//上、下、左、右、ESC、空格、F3、F4if (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->status = ESC;break;}else if (KEY_PRESS(VK_SPACE)){//游戏要暂定pause();//暂定和回复暂定}else if(KEY_PRESS(VK_F3)){if (ps->SleepTime >= 80){ps->SleepTime -= 30;ps->FoodWeight += 2;}}else if (KEY_PRESS(VK_F4)){if (ps->FoodWeight > 2){ps->SleepTime += 30;ps->FoodWeight -= 2;}}//走一步SnakeMove(ps);//睡眠一下Sleep(ps->SleepTime);} while (ps->status == OK);
}void GameEnd(pSnake ps)
{SetPos(15, 12);switch (ps->status){case ESC:printf("主动退出游戏,正常退出\n");break;case KILL_BY_WALL:printf("很遗憾,撞墙了,游戏结束\n");break;case KILL_BY_SELF:printf("很遗憾,咬到自己了,游戏结束\n");break;}//释放贪吃蛇的链表资源pSnakeNode cur = ps->pSnake;pSnakeNode del = NULL;while (cur){del = cur;cur = cur->next;free(del);}free(ps->pFood);ps = NULL;
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1#include "snake.h"void test()
{//创建贪食蛇int ch = 0;do{Snake snake = { 0 };GameStart(&snake);//游戏开始前的初始化GameRun(&snake);//玩游戏的过程GameEnd(&snake);//善后的工作SetPos(20, 15);printf("再来一局吗?(Y/N):");ch = getchar();getchar();// 清理\n} while (ch == 'Y' || ch =='y');
}int main()
{//修改适配本地中文环境setlocale(LC_ALL, "");test();//贪吃蛇游戏的测试SetPos(0, 27);return 0;
}

这个博客如果对你有帮助,给博主一个免费的点赞就是最大的帮助

欢迎各位点赞,收藏和关注哦

如果有疑问或有不同见解,欢迎在评论区留言哦

后续我会一直分享双一流211西北大学软件(C,数据结构,C++,Linux,MySQL)的学习干货以及重要代码的分享

相关文章:

贪吃蛇(C语言实现)

贪食蛇&#xff08;也叫贪吃蛇&#xff09;是一款经典的小游戏。 —————————————————————— 本博客实现使用C语言在Windows环境的控制台中模拟实现贪吃蛇小游戏。 实行的基本功能&#xff1a; • 贪吃蛇地图的绘制 • 蛇吃食物的功能&#xff08;上、…...

使用 mysqldump 迁移 MySQL 表 OceanBase

使用 mysqldump 迁移 MySQL 表 OceanBase 一、什么是mysqldump二、使用mysqldump导出MySQL数据三、将数据导入到OceanBase四、注意 一、什么是mysqldump mysqldump 是 MySQL 数据库管理系统中的一个工具&#xff0c;用于将数据库中的数据导出为文本文件。它可以将整个数据库、…...

谷粒学院--在线教育实战项目【一】

谷粒学院--在线教育实战项目【一】 一、项目概述1.1.项目来源1.2.功能简介1.3.技术架构 二、Mybatis-Plus概述2.1.简介2.2.特性 三、Mybatis-Plus入门3.1.创建数据库3.2.创建 User 表3.3.初始化一个SpringBoot工程3.4.在Pom文件中引入SpringBoot和Mybatis-Plus相关依赖3.5.第一…...

Power Design【数据库设计】

Power Design【数据库设计】 前言版权推荐Power Design【数据库设计】推荐11. PowerDesigner的使用11.1 开始界面11.2 概念数据模型11.3 物理数据模型11.4 概念模型转为物理模型11.5 物理模型转为概念模型11.6 物理模型导出SQL语句补充:sqlyog导入sql文件 最后 前言 2024-3-11…...

Spring Boot中Excel数据导入导出的高效实现

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…...

采购代购系统独立站,接口采集商品上货

采购代购系统独立站的建设与商品上货接口的采集是一个综合性的项目&#xff0c;涉及前端开发、后端开发、数据库设计以及API接口的对接等多个环节。以下是一个大致的步骤和考虑因素&#xff1a; 一、系统规划与需求分析 明确业务需求&#xff1a;确定代购系统的核心功能&…...

Redis精讲

redis持久化 RDB方式 Redis Database Backup file (redis数据备份文件), 也被叫做redis数据快照. 简单来说就是把内存中的所有数据记录到磁盘中. 快照文件称为RDB文件, 默认是保存在当前运行目录. [rootcentos-zyw ~]# docker exec -it redis redis-cli 127.0.0.1:6379> sav…...

ELFK 分布式日志收集系统

ELFK的组成&#xff1a; Elasticsearch: 它是一个分布式的搜索和分析引擎&#xff0c;它可以用来存储和索引大量的日志数据&#xff0c;并提供强大的搜索和分析功能。 &#xff08;java语言开发&#xff0c;&#xff09;logstash: 是一个用于日志收集&#xff0c;处理和传输的…...

excel批量数据导入时用poi将数据转化成指定实体工具类

1.实现目标 excel进行批量数据导入时&#xff0c;将批量数据转化成指定的实体集合用于数据操作&#xff0c;实现思路&#xff1a;使用注解将属性与表格中的标题进行同名绑定来赋值。 2.代码实现 2.1 目录截图如下 2.2 代码实现 package poi.constants;/*** description: 用…...

【软件工程导论】——软工学绪论及传统软件工程(学习笔记)

&#x1f4d6; 前言&#xff1a;随着软件产业的发展&#xff0c;计算机应用逐步渗透到社会生活的各个角落&#xff0c;使各行各业都发生了很大的变化。这同时也促使人们对软件的品种、数量、功能和质量等提出了越来越高的要求。然而&#xff0c;软件的规模越大、越复杂&#xf…...

C语言编译成库文件的要求

keil编译成库文件 在Keil中&#xff0c;将C语言源文件编译成库文件通常需要进行以下步骤&#xff1a; 创建一个新的Keil项目&#xff0c;并将所需的C语言源文件添加到该项目中。 在项目设置中配置编译选项&#xff0c;确保生成的目标文件符合库文件的标准格式。 编译项目&…...

Python的模块应用和文件I/O

Python 解释 Python是一种高级编程语言&#xff0c;以其简洁、易读和易用而闻名。它是一种通用的、解释型的编程语言&#xff0c;适用于广泛的应用领域&#xff0c;包括软件开发、数据分析、人工智能等。python是一种解释型&#xff0c;面向对象、动态数据类型的高级程序设计…...

设计模式之依赖倒转原则

目录 1、 基本介绍 2、 应用实例 3、 依赖关系传递的三种方式 (1) 接口传递 (2) 构造方法传递 (3) setter方式传递 4、 注意事项和细节 1、 基本介绍 依赖倒转原则(Dependence Inversion Principle)是指&#xff1a; 高层模块不应该依赖低层模块&#xff0c;二者都应该依…...

Springboot启动后想要做某些事可以通过什么方法实现?

在Spring Boot应用中&#xff0c;如果你想在应用启动完成后执行一些特定的操作&#xff08;例如缓存预热&#xff09;&#xff0c;可以实现CommandLineRunner或ApplicationRunner接口。这两个接口都提供了一个run方法&#xff0c;在Spring Boot应用上下文初始化完成后会被自动调…...

网络原理初识(2)

目录 一、协议分层 1、分层的作用 2、OSI七层模型 3、TCP / IP五层&#xff08;或四层&#xff09;模型 4、网络设备所在分层 5、网络分层对应 二、封装和分用 发送过程&#xff08;封装&#xff09; 1、应用层(应用程序) QQ 2、传输层 3、网络层 4、数据链路层 5、物理…...

【C++】每日一题 92 反转链表

给你单链表的头指针 head 和两个整数 left 和 right &#xff0c;其中 left < right 。请你反转从位置 left 到位置 right 的链表节点&#xff0c;返回 反转后的链表 。 class ListNode { public:int val;ListNode* next;ListNode(int _val) {val _val;next nullptr;} };…...

算法D39 | 动态规划2 | 62.不同路径 63. 不同路径 II

今天开始逐渐有 dp的感觉了&#xff0c;题目不多&#xff0c;就两个 不同路径&#xff0c;可以好好研究一下 62.不同路径 本题大家掌握动态规划的方法就可以。 数论方法 有点非主流&#xff0c;很难想到。 代码随想录 视频讲解&#xff1a;动态规划中如何初始化很重要&#x…...

面试官:如何在 Spring Boot 启动的时候提前运行一些特定的代码

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:如何在 Spring Boot 启动的时候提前运行一些特定的代码 在Spring Boot启动的时候提前运行一些特定的代码可以通过实现ApplicationRunner接口、Com…...

力扣最热100题——56.合并区间

吾日三省吾身 还记得梦想吗 正在努力实现它吗 可以坚持下去吗 目录 吾日三省吾身 力扣题号&#xff1a;56. 合并区间 - 力扣&#xff08;LeetCode&#xff09; 题目描述 Java解法一&#xff1a;排序然后原地操作 具体代码如下 Java解法二&#xff1a;new一个list&#xf…...

docker学习(十四)docker搭建私服

docker私服搭建&#xff0c;配置域名访问&#xff0c;设置访问密码 启动registry docker run -d \-p 5000:5000 \-v /opt/data/registry:/var/lib/registry \registrydocker pull hello-world docker tag hello-world 127.0.0.1:5000/hello-world docker push 127.0.0.1:5000…...

密评实战指南—从算法验证到电子签章的全流程解析

1. 密评实战入门&#xff1a;为什么需要密码应用安全性评估 最近帮某政务系统做上线前的安全检测时&#xff0c;发现他们的登录接口居然用MD5存储密码。这让我想起三年前某大型数据泄露事件&#xff0c;根源就是用了不安全的加密算法。密码应用安全性评估&#xff08;简称密评…...

别再被湍流模型搞晕了!用Python从零实现一个超简单的DNS求解器(附完整代码)

用Python从零实现极简DNS求解器&#xff1a;让Navier-Stokes方程看得见摸得着 当第一次听说"直接数值模拟"(DNS)时&#xff0c;我盯着那组复杂的Navier-Stokes方程看了整整一个下午——那些偏微分符号像天书一样令人望而生畏。直到有一天&#xff0c;我决定用Python把…...

实测对比:CST仿真3.5GHz波导魔T的5种边界条件设置方案

实测对比&#xff1a;CST仿真3.5GHz波导魔T的5种边界条件设置方案 在射频工程领域&#xff0c;波导魔T作为关键的无源器件&#xff0c;其性能直接影响整个系统的信号质量。特别是在5G基站滤波器等应用中&#xff0c;3.4-4GHz频段的特性控制尤为关键。本文将深入探讨五种不同边界…...

数字万用表的二极管档和电阻档,测LED到底该用哪个?实测对比给你看

数字万用表的二极管档和电阻档&#xff0c;测LED到底该用哪个&#xff1f;实测对比给你看 当你面对一个未知好坏的LED&#xff0c;手头只有一块数字万用表时&#xff0c;可能会纠结该选择哪个档位进行测量。是二极管档&#xff1f;电阻档&#xff1f;还是传统的电压档&#xff…...

第3篇:ChatGPT引爆的AIGC革命——内容创作的新纪元(概念入门)

文章目录背景引入&#xff1a;当我的“周报”被AI抢了饭碗核心概念&#xff1a;什么是AIGC&#xff1f;类比解释&#xff1a;从“图书馆管理员”到“小说家”简单示例&#xff1a;看AIGC如何工作为什么说这是“新纪元”&#xff1f;小结&#xff1a;拥抱变化&#xff0c;聚焦“…...

2026年OpenClaw怎么部署?5分钟腾讯云保姆级安装及百炼Coding Plan方法

2026年OpenClaw怎么部署&#xff1f;5分钟腾讯云保姆级安装及百炼Coding Plan方法。本文面向零基础用户&#xff0c;完整说明在轻量服务器与本地Windows11、macOS、Linux系统中部署OpenClaw&#xff08;Clawdbot&#xff09;的流程&#xff0c;包含环境配置、服务启动、Skills集…...

如何快速上手TrafficMonitor插件:打造个性化桌面监控工具的完整指南

如何快速上手TrafficMonitor插件&#xff1a;打造个性化桌面监控工具的完整指南 【免费下载链接】TrafficMonitorPlugins 用于TrafficMonitor的插件 项目地址: https://gitcode.com/gh_mirrors/tr/TrafficMonitorPlugins TrafficMonitor插件系统为这款强大的桌面监控工具…...

Windows 11系统优化革命:用Win11Debloat实现智能性能提升与隐私保护

Windows 11系统优化革命&#xff1a;用Win11Debloat实现智能性能提升与隐私保护 【免费下载链接】Win11Debloat A simple, lightweight PowerShell script that allows you to remove pre-installed apps, disable telemetry, as well as perform various other changes to dec…...

从卡尺到三坐标:不同测量场景下的GRR实战避坑指南(附Excel模板)

从卡尺到三坐标&#xff1a;不同测量场景下的GRR实战避坑指南&#xff08;附Excel模板&#xff09; 在精密制造的世界里&#xff0c;测量误差可能比生产缺陷更致命。想象一下&#xff1a;当三坐标测量机&#xff08;CMM&#xff09;的报告显示某个关键尺寸超差时&#xff0c;究…...

EmbeddingGemma-300m效果展示:Ollama实现专利技术趋势分析

EmbeddingGemma-300m效果展示&#xff1a;Ollama实现专利技术趋势分析 1. 当专利工程师遇上轻量级嵌入模型 专利文档的世界里&#xff0c;技术术语像密码一样密集排列。一份典型的通信领域专利摘要&#xff0c;可能同时出现“可重构智能表面”、“波束赋形算法”、“信道状态…...