C++贪吃蛇(控制台版)

C++自学精简实践教程 目录(必读)

目录

主要考察

需求

输入文件

运行效果

实现思路

枚举类型 enum class

启动代码

输入文件data.txt 的内容

参考答案

学生实现的效果


主要考察

模块划分

文本文件读取

UI与业务分离

控制台交互

数据抽象

需求

用户输入字母表示方向,实现贪吃蛇游戏。

规则:碰到边缘和碰到蛇自己都算游戏结束。

输入文件

第一行,包括两个整数,表示游戏棋盘大小。分别表示行数和列数。

后面的内容是一个行数乘以列数的二维数组。

数组的元素为0表示这里没有食物,也没有蛇的身体。

数组的元素为 @ 表示蛇的头。

数组元素为 # 表示蛇的身体。

程序启动一开始运行的时候,蛇没有身体,只有头。

运行效果

实现思路

正式实现代码Snake.cpp只有180行不到。

枚举类型 enum class

enum class 通常用来提供字面值常量。也就是一些固定值。比如,表示方向的东、南、西、北。表示空间的上、下、左、右、前、后。

启动代码

#include <list>
#include <utility>
#include <fstream>
#include <sstream>
#include <iostream>
#include <random>//随机数
#include <chrono>//日期时间
using namespace std;

class Snake
{
	// 游戏的任意位置 只有三种情况:什么也没有;蛇的身体;食物
	enum class MatrixValueEnum
	{
		NOTHING = '0', SNAKE_BODY = '#', FOOD = '2'
	};
public:
	// 从文件中加载界面数据,存放到内部容器中,再根据容器内容绘制界面
	bool LoadPlayDataFromFile(const std::string& file);
	// 开始游戏
	void Play(void);
private:
	// 用户输入一个字符(e/s/f/d),决定将蛇的头部往哪个方向移动
	bool GoAhead(char userInputDirection);// 核心函数
	// 移动蛇的头的坐标(x,y) = (x,y) + (i,j)
	bool GoAhead(int i, int j);
	//撞到墙壁或者蛇自己的身体就结束游戏
	bool IsGameOver(int, int) const;
	// 获取蛇的头的坐标
	std::pair<int, int> GetCurrentPosition(void) const;
	// 计算蛇的头移动一次后的新坐标
	std::pair<int, int> GetNextPosition(int, int) const;
	// 打印贪吃蛇游戏
	void PrintMatrix(void) const;
	// 判断 (i,j) 处是否是一个食物
	bool ExistFood(int i, int j) const;
	// 在界面上生成一个新的食物给蛇吃
	void CreateFood(void);
private:
	std::vector<std::vector<char>> m_playMatrix;// 整个游戏的数据(二维数组)
	std::list<std::pair<int, int>> m_snakeBody;// 蛇的身体数据
};

bool Snake::LoadPlayDataFromFile(const std::string& file)
{
	std::ifstream fin(file);
	if (!fin)
	{
		std::cout << "can not open file " << file << endl;
		return false;
	}
	std::string line;
	std::getline(fin, line);
	std::istringstream iss(line);// 字符串流 https://zhuanlan.zhihu.com/p/441027904
	int row = 0, column = 0;
	//读取行数和列数
	//(1) your code


	for (size_t i = 0; i < row; i++)
	{
		std::vector<char> lineData;
		std::getline(fin, line);
		std::istringstream issLineData(line);
		for (size_t j = 0; j < column; j++)
		{
			char data;
			//读取一个元素
			// (2) your code


			//将组成蛇的头#存放到蛇m_snakeBody容器中
                        //在文件里,一开始蛇的身体只有一个头,需要把这个数据存起来
			//(3) your code  判断两个char相等即可
			// 参考:https://zhuanlan.zhihu.com/p/357348144

		}
		//将第一行数据存放到二维数组中,作为第一维的一个元素(子数组)
		//(4) your code


	}
	if (m_snakeBody.size() != 1)
	{
		cout << "snake body is empty! init game failed." << endl;
		return false;
	}
	return true;
}

bool Snake::IsGameOver(int x, int y) const
{
	//判断游戏是否已经结束了
	// x y 是蛇的头打算要去的目的地,这个目的地会导致gomeover
	// 比如超出了游戏界面(下标越界)
	// 比如撞到了蛇的身体
	//(5) your code

	return true;
}
std::pair<int, int> Snake::GetCurrentPosition(void) const
{
	//返回蛇 的头的坐标,是m_snakeBody的第一个元素的值
	//(6) your code  下面的代码需要自己修改,不可以直接使用
	std::pair<int, int> front;

	return front;
}
std::pair<int, int> Snake::GetNextPosition(int i, int j) const
{
	//根据蛇的头的位置,以及一个移动的向量 (i,j) 得到蛇头部打算要去的新目的地的坐标
	auto old = GetCurrentPosition();
	//(7) your code 下面的代码需要自己修改,不可以直接使用
	int x = 0;
	int y = 0;
	return std::make_pair(x, y);
}
bool Snake::ExistFood(int i, int j) const
{
	//返回 坐标(i,j)处是否是有蛇的食物可以吃
	//(8) your code 下面的代码需要自己修改,不可以直接使用
	return false;
}
void Snake::CreateFood(void)
{
	// 生成一个新的食物给蛇来吃
	// 随机生成一个新的位置,但是这个位置可能已经是蛇的身体了
	// 所以,需要用一个循环不断的重复在一个新生成的随机位置放置食物
	// 直到放置成功为止
	do
	{
		unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
		std::mt19937 g(seed);  // mt19937 is a standard mersenne_twister_engine
		//生成新的随机的坐标
		//随机数的用法:https://blog.csdn.net/calmreason/article/details/72655060
		//(9) your code 下面的代码需要自己修改,不可以直接使用
		int x = 0;
		int y = 0;
		// 在新坐标处放置一个食物,记得检查可以放才能放
		// 一旦放好,记得退出循环,让程序继续执行
		//(10) your code



	} while (true);
}
bool Snake::GoAhead(char userInputDirection)
{
	switch (userInputDirection)
	{
	case 'w':
	case 'W':
		return GoAhead(-1, 0);//up
	case 'a':
	case 'A':
		return GoAhead(0, -1);//left
	case 'd':
	case 'D':
		return GoAhead(0, +1);//right
	case 's':
	case 'S':
		return GoAhead(+1, 0);//down
	default:
		return true;
	}
}
bool Snake::GoAhead(int i, int j)
{
	auto nextPosition = GetNextPosition(i, j);//垂直方向x不变,竖直方向y减少1
	// 首先判断游戏是否已经结束
	if (IsGameOver(nextPosition.first, nextPosition.second))
	{
		return false;
	}
	// 判断nextPosition 处是否有食物
	// 如果有食物,就吃掉这个食物
	// 并生成一个新的食物
	if (ExistFood(nextPosition.first, nextPosition.second))
	{
		// (11) your code


		//直接吃掉,尾巴不用移动
		m_playMatrix[nextPosition.first][nextPosition.second] = static_cast<char>(MatrixValueEnum::SNAKE_BODY);
		CreateFood();//随机生成一个食物
	}
	// 如果 nextPosition 处没有食物,就移动蛇的身体
	else
	{
		// (12) your code



		//尾巴移动 
		auto tail = m_snakeBody.back();
		m_playMatrix[tail.first][tail.second] = static_cast<char>(MatrixValueEnum::NOTHING);
		m_snakeBody.pop_back();

	}
}


void Snake::Play(void)
{
	CreateFood();//随机生成一个食物
	while (true)
	{
		/*清屏,这不是C++的一部分,是系统调用。
		  这个语句执行的快慢与代码无关,与控制台用户自己设置的缓冲区大小有关。
		*/
		system("cls");
		PrintMatrix();

		std::cout << "direction: W(up) A(left) S(down) D(right)\n";
		std::cout << "$: food\n";
		std::cout << "@: snake head\n";
		std::cout << "#: snake tail\n";

		char direction;
		std::cin >> direction;
		//往前走一步,如果判断无法往前走到用户指定的位置,就退出程序
		// (13) your code
		if (!GoAhead(direction))
		{
			std::cout << "Game Over!" << std::endl;
			break;
		}
	}
}
void Snake::PrintMatrix(void) const
{
	auto headPosition = m_snakeBody.front();
	for (size_t i = 0; i < m_playMatrix.size(); i++)
	{
		for (size_t j = 0; j < m_playMatrix[i].size(); j++)
		{
			if (i == headPosition.first && j == headPosition.second)
			{
				std::cout << "@" << " ";
			}
			else if (m_playMatrix[i][j] == static_cast<char>(MatrixValueEnum::FOOD))
			{
				std::cout << "$" << " ";
			}
			else if (m_playMatrix[i][j] == static_cast<char>(MatrixValueEnum::NOTHING))
			{
				std::cout << "_" << " ";
			}
			else
			{
				std::cout << m_playMatrix[i][j] << " ";
			}
		}
		std::cout << std::endl;
	}
}

int main(int argc, char** argv)
{
	Snake snake;
	if (snake.LoadPlayDataFromFile("data.txt"))
	{
		snake.Play();
	}

	return 0;
}

输入文件data.txt 的内容

7 7
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 # 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0

参考答案

贪吃蛇(控制台版)(答案)

其他参考:

Qt版本的一个贪吃蛇实现 Qt Snake C++

学生实现的效果

视频资源加载失败

视频资源加载失败

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

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

相关文章

朋友圈也可以定时定量发送?

场景1&#xff1a;明天要搞活动&#xff0c;早中晚都得发朋友圈&#xff0c;一天要发3次朋友圈&#xff0c;要在手机上定好3个闹钟&#xff0c;这是一件非常麻烦的事。 场景2&#xff1a;有朋友是房产信息的&#xff0c;每天要发布很多二手房源&#xff0c;手动发圈太耗时间&a…

记录:yolov8训练自己的数据集

一、LabelImg标注自己的原图数据集 .xml标注格式 二、带标签的数据增强 先将原始数据&#xff08;图片&#xff0c;标注&#xff09;转移到项目根目录&#xff0c;然后再数据增强&#xff0c;避免标注内容路径错误。 亮度变换加旋转 # 一、亮度 img_dir multi/images # 原始…

CSS基础选择器及常见属性

文章目录 一、CSS1、CSS简介2、CSS语法规范 二、CSS基础选择器1、选择器的作用2、选择器分类3、基础选择器标签选择器类选择器id选择器通配符选择器 三、CSS常见属性1、字体属性字体系列字体大小字体粗细文字样式 2、文本属性文本颜色对齐文本装饰文本文本缩进行间距 四、CSS引…

python编写四画面同时播放swap视频

当代技术让我们能够创建各种有趣和实用的应用程序。在本篇博客中&#xff0c;我们将探索一个基于wxPython和OpenCV的四路视频播放器应用程序。这个应用程序可以同时播放四个视频文件&#xff0c;并将它们显示在一个GUI界面中。 C:\pythoncode\new\smetimeplaymp4.py 准备工作…

2023最新任务悬赏平台源码uniapp+Thinkphp新款悬赏任务地推拉新充场游戏试玩源码众人帮威客兼职任务帮任务发布分销机

新款悬赏任务地推拉新充场游戏试玩源码众人帮威客兼职任务帮任务发布分销机制 后端是&#xff1a;thinkphpFastAdmin 前端是&#xff1a;uniapp 1.优化首页推荐店铺模块如有则会显示此模块没有则隐藏。 2修复首页公告&#xff0c;更改首页公告逻辑。&#xff08;后台添加有公…

redis 6个节点(3主3从),始终一个节点不能启动

redis节点&#xff0c;始终有一个节点不能启动起来 1.修改了配置文件 protected-mode no&#xff0c;重启 修改了配置文件 protected-mode no&#xff0c;重启redis问题依然存在 2、查看/var/log/message的redis日志 Aug 21 07:40:33 redisMaster kernel: Out of memory: K…

Jumpserver堡垒机管理(安装和相关操作)-------从小白到大神之路之学习运维第89天

第四阶段 时 间&#xff1a;2023年8月28日 参加人&#xff1a;全班人员 内 容&#xff1a; Jumpserver堡垒机管理 目录 一、堡垒机简介 &#xff08;一&#xff09;运维常见背黑锅场景 &#xff08;二&#xff09;背黑锅的主要原因 &#xff08;三&#xff09;解决背黑…

SSM框架的学习与应用(Spring + Spring MVC + MyBatis)-Java EE企业级应用开发学习记录(第三天)动态SQL

动态SQL—SSM框架的学习与应用(Spring Spring MVC MyBatis)-Java EE企业级应用开发学习记录&#xff08;第三天&#xff09;Mybatis的动态SQL操作 昨天我们深入学习了Mybatis的核心对象SqlSessionFactoryBuilder&#xff0c;掌握MyBatis核心配置文件以及元素的使用,也掌握My…

4-1-netty

非阻塞io 服务端就一个线程&#xff0c;可以处理无数个连接 收到所有的连接都放到集合channelList里面 selector是有事件集合的 对server来说优先关注连接事件 遍历连接事件

小研究 - Java虚拟机性能及关键技术分析

利用specJVM98和Java Grande Forum Benchmark suite Benchmark集合对SJVM、IntelORP,Kaffe3种Java虚拟机进行系统测试。在对测试结果进行系统分析的基础上&#xff0c;比较了不同JVM实现对性能的影响和JVM中关键模块对JVM性能的影响&#xff0c;并提出了提高JVM性能的一些展望。…

Leetcode 2651.计算列车到站时间

给你一个正整数 arrivalTime 表示列车正点到站的时间&#xff08;单位&#xff1a;小时&#xff09;&#xff0c;另给你一个正整数 delayedTime 表示列车延误的小时数。 返回列车实际到站的时间。 注意&#xff0c;该问题中的时间采用 24 小时制。 示例 1&#xff1a; 输入&…

什么样的人适合开抖店?最后一个条件必须满足!抖店开通门槛如下

我是王路飞。 作为现在热门的电商项目&#xff0c;抖店显然已经取代直播带货&#xff0c;成为了普通人在抖音卖货的新渠道&#xff0c;毕竟做账号和开直播对普通人来说&#xff0c;门槛太高了。 那么&#xff0c;在抖音开店&#xff0c;是谁都可以开吗&#xff1f;开店有什么…

K8S最新版本集群部署(v1.28) + 容器引擎Docker部署(上)

温故知新 &#x1f4da;第一章 前言&#x1f4d7;背景&#x1f4d7;目的&#x1f4d7;总体方向 &#x1f4da;第二章 基本环境信息&#x1f4d7;机器信息&#x1f4d7;软件信息&#x1f4d7;部署用户kubernetes &#x1f4da;第三章 Kubernetes各组件部署&#x1f4d7;安装kube…

基于MATLAB/Simulink的三相并网逆变器dq阻抗建模及扫频仿真

目录 整体系统介绍理论模型MATLAB实现 基于Simulink的阻抗扫频仿真整体思路注意事项流程框图 其他 本文主要介绍三相并网逆变器dq阻抗建模的相关知识&#xff0c;和大家分享一下怎么使用MATLAB/Simulink来进行理论模型的搭建以及如何通过扫频获取阻抗模型&#xff0c;一方面是给…

分类预测 | MATLAB实现SSA-CNN-SVM基于麻雀算法优化卷积支持向量机分类预测

分类预测 | MATLAB实现SSA-CNN-SVM基于麻雀算法优化卷积支持向量机分类预测 目录 分类预测 | MATLAB实现SSA-CNN-SVM基于麻雀算法优化卷积支持向量机分类预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 MATLAB实现SSA-CNN-SVM基于麻雀算法优化卷积支持向量机分类预测…

k8s的学习篇1

一 k8s的概念 1.1 k8s k8s是一个轻量级的&#xff0c;用于管理容器化应用和服务的平台。通过k8s能够进行应用的自动化部署和扩容缩容。 1.2 k8s核心部分 1.prod: 最小的部署单元&#xff1b;一组容器的集合&#xff1b;共享网络&#xff1b;生命周期是短暂的&#xff1b; …

hive-列转行

转成 select customer_code,product_type from temp.temp_xx LATERAL VIEW explode(SPLIT(product_types,,)) table_tmp AS product_type where customer_code K100515182

数据结构(Java实现)-优先级队列(堆)

队列是一种先进先出(FIFO)的数据结构&#xff0c;但有些情况下&#xff0c;操作的数据可能带有优先级&#xff0c;一般出队 列在这种情况下&#xff0c;数据结构应该提供两个最基本的操作&#xff0c;一个是返回最高优先级对象&#xff0c;一个是添加新的对象。 这种数据结构就…

Seaborn绘制热力图的子图

Seaborn绘制热力图的子图 提示&#xff1a;如何绘制三张子图 绘制的时候&#xff0c;会出现如下问题 &#xff08;1&#xff09;如何绘制1*3的子图 &#xff08;2&#xff09;三个显示条&#xff0c;如何只显示最后一个 提示&#xff1a;下面就展示详细步骤 Seaborn绘制热力…

权限提升-手工-系统权限提升

权限提升基础信息 1、具体有哪些权限需要我们了解掌握的&#xff1f; 后台权限&#xff0c;网站权限&#xff0c;数据库权限&#xff0c;接口权限&#xff0c;系统权限&#xff0c;域控权限等 2、以上常见权限获取方法简要归类说明&#xff1f; 后台权限&#xff1a;SQL注入,数…