C++实现简单贪吃蛇游戏

文章目录

    • 1 开发历程
    • 2 开发思路
    • 3 使用介绍
    • 4 源文件代码
    • 5 游戏截图
    • 6 小结

1 开发历程

游戏使用C++语言开发,是博主某个下午心血来潮的结果,后面又花了点时间加了计分,记录历史得分的功能。

2 开发思路

其实贪吃蛇主要难在蛇身的移动上,想像着蛇移动的模样,不禁让人想起链表这种数据结构,蛇的头带动蛇身的第二节,第二节带动第三节,每一节的移动方向会遗传给下一节,把握住这一点,难点就迎刃而解了。

3 使用介绍

由于整个项目只有一个文件,使用g++ -o snake main.cpp命令编译源文件,就可以得到一个名为snakeexe可运行程序,接着在exe同目录下打开cmd使用下面两个命令来执行程序:

  • snake start,开始游戏,w、s、a、d四个按键(不分大小写)控制蛇的移动方向,若蛇碰到墙壁或者自身,则游戏结束,并将计分存入名为rank.txt的文件中。
  • snake rank,查看历史前五得分记录。

4 源文件代码

#include <iostream>
#include <cstring>
#include <fstream>
#include <set>
#include <windows.h>
#include <conio.h>
#include <time.h>
#define HEIGHT 15
#define WIDTH 35
#define INIT_FLUSHRATE 200
#define INIT_SCORE 0
#define BODY '@'
#define EMPTY ' '
#define FOOD '*'
#define EDGE '#'
#define RANKFILE "rank.txt"
using namespace std;
bool keyIsput = false;enum class Orient {UP, DOWN, LEFT, RIGHT};typedef struct node {int row;int col;Orient direction;struct node* next;
} Node;typedef struct {int frow;int fcol;
} Food;bool FoodInSnake(const int& r, const int& c, Node* q) {while (q != NULL) {if (q->row == r && q->col == c)return true;q = q->next;}return false;
}void printRank(){ifstream fin(RANKFILE);if(!fin){cerr << RANKFILE << " does not exit or open file error!!";exit(1);}if(fin.peek()==ifstream::traits_type::eof()){cout << "file is empty";exit(1);}for(int i=0; i<5; ++i){int tmp;if(fin.eof())break;fin >> tmp;cout << "No." << i+1 << ": " << tmp << '\n';}
}class Snake {
private:Node* snakeHead;public:static Orient tmp_1, tmp_2;Snake(int r, int c, Orient ori) {snakeHead = new Node;snakeHead->row = r;snakeHead->col = c;snakeHead->direction = ori;snakeHead->next = NULL;}Node* getHead() {return snakeHead;}void setOrient(Orient ori) {tmp_1 = snakeHead->direction;snakeHead->direction = ori;}void move() {Node* p = snakeHead;while (p != NULL) {if (p == snakeHead) {if(keyIsput==false)tmp_1 = p->direction;}else if (p != snakeHead) {tmp_2 = p->direction;p->direction = tmp_1;tmp_1 = tmp_2;}switch (p->direction) {case Orient::UP:(p->row)--; break;case Orient::DOWN:(p->row)++; break;case Orient::LEFT:(p->col)--; break;case Orient::RIGHT:(p->col)++; break;default:break;}p = p->next;}keyIsput = false;}void longer(int row, int col, Orient direction) {Node* newbody = new Node;newbody->row = row;newbody->col = col;newbody->direction = direction;newbody->next = snakeHead;snakeHead = newbody;}virtual ~Snake() {Node *p = snakeHead, *q=NULL;while (p != NULL) {q = p->next;delete p;p = q;}}
};class Board {
private:Snake* s;int playground[HEIGHT][WIDTH] = {0};Food* food;bool foodIsEaten;bool gameOver;int score;int flushRate;public:Board(int sr=HEIGHT/2, int sc=WIDTH/2, Orient sori=Orient::RIGHT):gameOver(false),foodIsEaten(false),score(INIT_SCORE),flushRate(INIT_FLUSHRATE){s = new Snake(sr, sc, sori);playground[sr][sc] = 1;food = new Food;while ((food->frow = rand() % HEIGHT) == sr);while ((food->fcol = rand() % WIDTH) == sc);playground[food->frow][food->fcol] = 2;}void refresh() {s->move();Node* shead = s->getHead();if((gameOver = isCollision(shead)))return;if (shead->row == food->frow && shead->col == food->fcol) {foodIsEaten = true;switch (shead->direction){case Orient::UP: s->longer(shead->row - 1, shead->col, shead->direction); break;case Orient::DOWN: s->longer(shead->row + 1, shead->col, shead->direction); break;case Orient::LEFT: s->longer(shead->row, shead->col - 1, shead->direction); break;case Orient::RIGHT: s->longer(shead->row, shead->col + 1, shead->direction); break;default:break;}}if (foodIsEaten)refreshFood();memset(playground, 0, sizeof(playground));Node* p = s->getHead();while (p != NULL) {playground[p->row][p->col] = 1;p = p->next;}if(!foodIsEaten)playground[food->frow][food->fcol] = 2;}void printBoard() {for (int i = 0; i < HEIGHT; ++i) {for (int j = 0; j < WIDTH; ++j)playground[i][j] == 1 ? cout << BODY : (playground[i][j]==2? cout << FOOD:cout << EMPTY);i==0?cout << EDGE << "  Your score: " << score << '\n':cout << EDGE << '\n';}for (int k = 0; k < WIDTH; ++k)cout << EDGE;}void setSnakeOrient(Orient ori) {s->setOrient(ori);}void refreshFood() {score++;if(flushRate>50)flushRate-=5;Node* p = s->getHead();while (FoodInSnake(food->frow = rand() % HEIGHT, food->fcol = rand() % WIDTH, p));foodIsEaten = false;}void keyCheck() {if (_kbhit()) {keyIsput = true;char key = _getch();switch (key){case 'w':case'W':setSnakeOrient(Orient::UP); break;case 'a':case'A':setSnakeOrient(Orient::LEFT); break;case 's':case'S':setSnakeOrient(Orient::DOWN); break;case 'd':case'D':setSnakeOrient(Orient::RIGHT); break;default:break;}}}bool isCollision(Node*& head){if(head->row<0 || head->row>=HEIGHT)return true;if(head->col<0 || head->col>=WIDTH)return true;Node* p = head;while(p!=NULL){if(p!=head && p->row==head->row && p->col==head->col)return true;p = p->next;}return false;}int getFlushRate() const{return flushRate;}bool isGameOver(){return gameOver;}void printEnd(){ifstream fin(RANKFILE);if(!fin){fin.close();ofstream fout(RANKFILE);fout << score;fout.close();}else{set<int> r;int tmp;r.insert(score);while(!fin.eof()){fin >> tmp;r.insert(tmp);}fin.close();ofstream fout(RANKFILE);for(auto i=r.rbegin();i!=r.rend();++i)++i==r.rend()?fout << *(--i):fout << *(--i) << '\n';fout.close();}cout << "Game Over!!\n";cout << "Your score is " << score << ".\n";}~Board() {delete s;delete food;}
};Orient Snake::tmp_1 = Orient::RIGHT, Snake::tmp_2 = Orient::RIGHT;int main(int argc, char* argv[]) {if(argc!=2 || (strcmp(argv[1], "start")!=0 && strcmp(argv[1], "rank")!=0)){cerr << "Usage: \"snake start\" to begin game.\n";cerr << "       \"snake rank\" to look rank(1-5).";return 1;}if(strcmp(argv[1], "rank")==0){printRank();return 0;}srand((unsigned)time(NULL));Board* gameboard = new Board();while (!gameboard->isGameOver()) {gameboard->printBoard();Sleep(gameboard->getFlushRate());system("cls");gameboard->keyCheck();gameboard->refresh();}gameboard->printEnd();delete gameboard;return 0;
}

5 游戏截图

在这里插入图片描述

在这里插入图片描述

6 小结

程序中使用了windows的库,所以暂时只支持win系统运行,这个游戏可以说是人人皆知,博主小时候特别喜欢这个游戏,现在动手实现了,感觉还是很不错的。再次感谢各位的阅读,希望可以帮到各位,喜欢的可以点赞支持一波,Thank you very much!!

后话:想学习C语言的,可以看看博主的C现代方法笔记的文章哦!

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

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

相关文章

AWS IoT Core 实战指南

Amazon Web Services (AWS) 提供了全球范围内的托管服务,其中包括 AWS IoT Core,专为连接和管理物联网设备而设计。这个实战指南将带你一步步了解如何使用 AWS IoT Core 来注册设备、提高安全性、进行通信以及利用设备影子功能。 设备注册 1. 创建 Thing(设备) 在 AWS I…

cocos creator 如何绑定参数到编辑器

很多cocos creator同学不知道如何绑定组件属性到编辑器上&#xff0c;今天我们来教大家如何绑定 1: 基本数据属性绑定到编辑器 这个非常简单&#xff0c;模板是属性名字: 默认的值; Is_debug: false, speed: 100, 2: 系统组件类型与节点绑定到编辑器 属性名字: { type: 组件…

App更换图标

App更换图标 京东淘宝的每到618或者双十一的时候&#xff0c;app图标都会贴合相关主题更换一下&#xff0c;但是那个时间段app也没有升级&#xff0c;所以说肯定是有一个配置能够更改app的图标。 查了一些文档&#xff0c;发现了如下的方法。 准备图片 准备120x120和180x18…

带着股票转户——转托管流程分享

前一阵子&#xff0c;有部分朋友说想换掉原来的券商&#xff0c;但又不想卖出股票&#xff0c;这时候就可以通过券商的“转托管”功能&#xff0c;把股票从原来的券商账户&#xff0c;转移到新的券商账户中。 转托管的好处显而易见&#xff0c;不需要卖出股票/重新买入股票&am…

什么是宏任务与微任务以及它们的执行顺序

文章目录 宏任务微任务 微任务和宏任务是指在 JavaScript 中执行异步任务的两种不同的队列。 宏任务 宏任务&#xff1a; 宏任务是指由浏览器发起的、在事件循环中执行的异步任务。常见的宏任务包括&#xff1a; setTimeoutsetIntervalI/O 操作UI 渲染 宏任务的执行顺序是在每…

Ubuntu20.04扩展磁盘后系统无法启动

z​​​​​​Ubuntu20.04虚拟机扩展磁盘后系统无法启动 - 黑夫和惊 - 博客园 (cnblogs.com) 找了半天的解决方法&#xff0c;这个人的最好用。 只不过进入BOOT那个地方&#xff0c;不需要狂按F2&#xff0c;直接在虚拟机的开机键边上的小三角&#xff0c;选择&#xff0c;“…

代码随想录刷题第四十三天| 1049. 最后一块石头的重量 II ● 494. 目标和 ● 474.一和零

代码随想录刷题第四十三天 今天为三道0-1背包问题的变种&#xff0c; 分别有三个小问题 给定一个容量为j的背包&#xff0c;尽可能装下物品&#xff0c;找到能装下物品的最大价值 dp[i][j] max(dp[i-1][j], dp[i-1][j-nums[i]]nums[i]) 给定一个容量为j的背包&#xff0c;找…

VScode/Xshell连接学校服务器

vscode连学校服务器 1.连接atrust VPN2.Xshell连接服务器2.1创建一个自己的用户 3.xftp传文件4.vscode连接服务器4.1下载remote-ssh4.2连接服务器4.3激活conda环境4.4运行代码 5. pytorch版本不兼容解决方案 1.连接atrust VPN 如果是使用的是校园网&#xff0c;可以不连接 2…

【全栈开发|Fresh框架】Fresh环境安装与快速体验Fresh全栈开发

文章目录 前言一、环境配置1. 安装Deno2. 安装idea插件 二、Hello World1.创建项目2.项目结构3. 创建一个路由4. 创建一个动态路由5. 自定义handlers1. 自定义响应头2. 随即生成uuid 6. 表单提交7. 部署到生产环境1. 将代码上传到github2. 在Deno控制面板创建一个项目 总结 前言…

面试算法100:三角形中最小路径之和

题目 在一个由数字组成的三角形中&#xff0c;第1行有1个数字&#xff0c;第2行有2个数字&#xff0c;以此类推&#xff0c;第n行有n个数字。例如&#xff0c;下图是一个包含4行数字的三角形。如果每步只能前往下一行中相邻的数字&#xff0c;请计算从三角形顶部到底部的路径经…

强烈推荐!这8款在线画图工具好用极了

即时设计 即时设计作为一种简单的绘图工具&#xff0c;为创作者提供了一个方便而强大的创作平台&#xff0c;具有丰富的绘图工具、实时合作、矢量绘图和组件设计系统等功能。即时设计可以满足不同的创作需求&#xff0c;使创意自由流动。 强大的矢量编辑工具 即时设计提供了…

苹果电脑Markdown文本编辑Typora mac功能介绍

Typora mac是一款跨平台的Markdown编辑器&#xff0c;支持Windows、MacOS和Linux操作系统。它具有实时预览功能&#xff0c;能够自动将Markdown文本转换为漂亮的排版效果&#xff0c;让用户专注于写作内容而不必关心格式调整。Typora Mac版除了支持常见的Markdown语法外&#x…

C++每日一练(14):对称矩阵的判定

题目描述 输入矩阵的行数&#xff0c;再依次输入矩阵的每行元素&#xff0c;判断该矩阵是否为对称矩阵&#xff0c;若矩阵对称输出“yes"&#xff0c;不对称输出”no“。 输入 第一行输入一个正整数N&#xff08;N<20&#xff09;&#xff0c;表示矩阵的行数&#xff0…

网络通信(12)-C#TCP客户端封装帮助类实例

本文使用Socket在C#语言环境下完成TCP客户端封装帮助类的实例。 实例完成的功能: 客户端与服务器连接,实现实时刷新状态。 客户端接收服务器的数据。 客户端发送给服务器的数据。 客户端实时判定状态,断开连接后自动重连。 客户端与服务器端发送心跳包。 在VS中创建C…

IntelliJ IDEA 如何编译 Maven 工程项目

在当今的Java开发领域&#xff0c;Maven已经成为项目构建和依赖管理的标准工具。IntelliJ IDEA作为一款集成度高的Java开发环境&#xff0c;提供了许多强大的功能来简化和优化Maven项目的构建流程。本文将深入介绍如何使用IntelliJ IDEA编译Maven工程的详细步骤以及一些高级技巧…

Wargames与bash知识11

Wargames与bash知识11 bandit19 关卡提示&#xff1a; 要获得对下一级别的访问权限&#xff0c;您应该使用家目录中的setuid二进制文件。在不带参数的情况下执行它&#xff0c;以了解如何使用。在使用setuid二进制文件后&#xff0c;可以在通常的位置&#xff08;/etc/bandit…

Lumerical Monitors------ Global properties

Lumerical Monitors------ Global properties Global properties 全局属性 Global properties 全局属性 在 Lumerical 中&#xff0c;这里以 FDTD 工程文件举例&#xff0c;所有的 monitors 都可以通过上方选项卡中的 monitor 标签页添加。 注意上面有一个 Global properties…

【WinForm.NET开发】自定义控件

本文内容 基控件类创建自己的控件用户控件扩展控件 可使用 Windows 窗体开发和实现新的控件。 可以创建新的用户控件&#xff0c;通过继承来修改现有控件&#xff0c;或编写可自行绘制的自定义控件。 本文重点介绍各种可继承控件之间的差异&#xff0c;并提供有关如何为项目选…

MS3814:DVI/HDMI TMDS FR-4 和电缆均衡器/驱动器

产品简述 MS3814 是一款 TMDS 均衡 / 驱动器芯片&#xff0c;用于补偿 FR-4 和 电缆到 DVI/HDMI 连接器的损耗。提供完全满足 DVI/HDMI TMDS 要求的输出。芯片还可用于 DVI/HDMI 电缆以延长传输距离&#xff0c;提 高连接器接收侧电缆通道的抖动余量。片上 TMDS…

Prometheus 与 VictoriaMetrics对比

公众号「架构成长指南」&#xff0c;专注于生产实践、云原生、分布式系统、大数据技术分享 时序数据库有很多&#xff0c;比如Prometheus、M3DB、TimescaleDB、OpenTSDB、InfluxDB等等。Prometheus和VictoriaMetrics是开源的时间序列数据库&#xff0c;在复杂的环境中提供了强大…