C++实战:实现生命游戏

news2024/9/20 22:22:15

文章目录

  • 一、实战概述
  • 二、实战步骤
    • (一)编写生命头文件
    • (二)创建生命实现文件
    • (三)编写工具头文件
    • (四)编写工具实现文件
    • (五)编写主程序文件
    • (六)运行程序,查看结果
    • (七)尝试生命游戏其它初始布局
  • 三、实战总结

一、实战概述

  • 在C++中实现康威生命游戏是一项结合了算法设计、数据结构和用户交互的实战编程任务。首先,定义一个名为Life的类来存储游戏状态,其中包含一个二维数组用于表示细胞网格,并实现初始化(initialize)、打印当前状态(print)以及根据规则更新状态到下一代(update)的方法。neighbor_count函数用于计算每个细胞周围活细胞的数量。

  • 此外,还创建了两个辅助函数:instructions用于输出游戏使用说明;user_says_yes则处理用户的交互输入,判断是否继续执行游戏迭代。

  • 主程序main.cpp中,实例化Life对象,按照流程初始化游戏状态、打印初始布局并持续询问用户是否查看下一个世代。通过调用update方法和print方法循环展示生命游戏的演化过程。

  • 此C++实现不仅展示了如何将数学概念转化为实际代码,也体现了计算机科学中的模拟与自动化思想,通过简单的规则模拟出复杂的生命现象,为学习者提供了一个理解和实践元胞自动机理论的良好平台。

二、实战步骤

  • 创建一个名为"GameOfLife"的项目,并编写头文件life.h和源文件life.cpp。通过这些文件,可以定义游戏的基本结构、初始化游戏、打印当前状态以及更新游戏状态。

(一)编写生命头文件

  • 这个头文件定义了生命游戏类(Life)的基本结构,包括成员函数和私有变量。其中的常量 maxrow 和 maxcol 分别表示网格的最大行数和最大列数。包含的成员函数有 initialize()、print() 和 update()。
    在这里插入图片描述
// 定义游戏区域最大尺寸,这里是行数和列数
const int maxrow = 20, maxcol = 60; // 游戏格子的维度

// 定义生命游戏(Conway's Game of Life)类
class Life {
public:
    // 初始化方法,用于设置初始细胞状态
    void initialize();

    // 打印当前游戏状态的方法,显示整个网格
    void print();

    // 更新方法,根据游戏规则计算下一代细胞的状态
    void update();    

    // 使用二维数组存储游戏网格,并额外增加两行两列以简化边界条件处理
    int grid[maxrow + 2][maxcol + 2]; 

    // 计算给定位置 (row, col) 的邻居细胞存活数量的方法
    int neighbor_count(int row, int col);
};

// 结束某些预处理器条件或标志着某个阶段完成的宏定义
#define DONE

// 包含实现上述接口的具体代码
#include "life.cpp"
  • 该C++代码定义康威生命游戏类Life,含初始化、打印状态、更新规则方法及计算邻居存活数量函数。利用二维数组存储格子状态,其中边界额外扩充以简化处理,并通过包含"life.cpp"实现具体逻辑。

(二)创建生命实现文件

  • 这个源文件实现了生命游戏类中的各个成员函数。initialize()函数用于初始化游戏状态,用户可以指定活细胞的位置;print()函数负责打印当前的游戏状态;update()函数根据邻居计数规则更新游戏状态到下一代。
    在这里插入图片描述
#include <iostream>
#include <istream>
using namespace std;

#ifdef DONE

// 初始化方法:清零整个游戏区域,并让用户输入活细胞坐标,构建初始生命配置
void Life::initialize()
/*Pre: 无预条件
  Post: Life对象包含用户指定的生命配置*/
{
	int row, col;
	for (row = 0; row <= maxrow + 1; row++)
		for (col = 0; col <= maxcol + 1; col++)
			grid[row][col] = 0; // 将所有格子初始化为死状态

	cout << "List the coordinates for living cells." << endl;
	cout << "Terminate the list with the special pair -1 -1" << endl;
	cin >> row >> col;
	while (row != -1 || col != -1)
	{
		if (row >= 1 && row <= maxrow)
			if (col >= 1 && col <= maxcol)
				grid[row][col] = 1; // 根据有效坐标设置活细胞
			else
				cout << "Column " << col << " is out of range." << endl;
		else
			cout << "Row " << row << " is out of range." << endl;
		cin >> row >> col; // 继续读取下一个坐标对
	}
}

// 打印当前生命游戏配置的方法
void Life::print()
/*Pre: Life对象已包含一个生命配置
  Post: 用户可以看到该配置信息*/
{
	int row, col;
	cout << "\nThe current Life configuration is:" << endl;
	for (row = 1; row <= maxrow; row++)
	{
		for (col = 1; col <= maxcol; col++)
			if (grid[row][col] == 1)
				cout << '*'; // 输出活细胞用星号表示
			else
				cout << ' '; // 死细胞用空格表示
		cout << endl;		 // 换行准备输出下一行
	}
	cout << endl; // 输出结束后的额外换行
}

// 更新方法:根据康威生命游戏规则计算并生成下一世代的生命配置
void Life::update()
/*Pre: Life对象已包含一个生命配置
  Post: Life对象现在包含基于原有配置计算出的新一代生命配置*/
{
	int row, col;
	int new_grid[maxrow + 2][maxcol + 2]; // 创建一个新的临时网格用于存放下一代状态

	// 遍历每一个细胞,根据邻居数量决定新状态
	for (row = 1; row <= maxrow; row++)
		for (col = 1; col <= maxcol; col++)
			switch (neighbor_count(row, col))
			{
			case 2:
				new_grid[row][col] = grid[row][col]; // 当前状态保持不变
				break;
			case 3:
				new_grid[row][col] = 1; // 符合“生死准则”的细胞变为活细胞
				break;
			default:
				new_grid[row][col] = 0; // 其他情况,细胞变为死细胞
			}

	// 将临时网格中的新状态复制回原网格中,完成更新过程
	for (row = 1; row <= maxrow; row++)
		for (col = 1; col <= maxcol; col++)
			grid[row][col] = new_grid[row][col];
}

// 生命游戏类 Life 的成员函数,计算给定位置周围活细胞数量的方法
int Life::neighbor_count(int row, int col)
{
	// 检查输入坐标是否在有效范围内(假设网格从1开始计数)
	if (row < 1 || row > maxrow || col < 1 || col > maxcol)
		return 0; // 如果坐标无效,则返回0表示没有活细胞邻居

	int count = 0;							 // 初始化活细胞计数器为0
	for (int i = row - 1; i <= row + 1; ++i) // 遍历以给定行为中心的3行
	{
		for (int j = col - 1; j <= col + 1; ++j) // 遍历以给定列为中心的3列
		{
			// 跳过当前格子自身(不计入邻居)
			if (i == row && j == col)
				continue;

			// 检查所考虑的单元格是否在有效范围内并存活
			if (i >= 1 && i <= maxrow && j >= 1 && j <= maxcol && grid[i][j] == 1)
				++count; // 若存活,则增加计数器
		}
	}

	return count; // 返回活细胞邻居的数量
}

#endif
  • 这段代码为康威生命游戏实现了一个简单的类Life,包含了初始化、打印当前配置以及根据游戏规则更新配置的方法。同时,还有一个辅助函数用来计算每个细胞周围活细胞的数量。注释详细解释了各个函数的前置条件、后置条件以及功能。

(三)编写工具头文件

  • 这个头文件包含了两个辅助函数声明:instructions()用于打印使用生命游戏的说明信息;user_says_yes()用于获取用户的输入,并判断是否为肯定回答。
    在这里插入图片描述
void instructions();
bool user_says_yes();

#define DONE
#include "utility.cpp"

(四)编写工具实现文件

  • 这个源文件实现了utility.h中声明的两个辅助函数。instructions()函数打印关于如何使用生命游戏的详细说明;user_says_yes()函数接收用户输入并返回一个布尔值,表示用户是否给出了肯定回答。
    在这里插入图片描述
#include <iostream>
#include <istream>
using namespace std;

#ifdef DONE

// 函数:打印游戏使用说明
void instructions()
/*Pre: 无预条件.
  Post: 已经打印了使用生命游戏的说明。*/
{
	cout << "Welcome to Conway's game of Life." << endl;
	cout << "This game uses a grid of size " << maxrow << " by " << maxcol << " in which " << endl;
	cout << "each cell can either be occupied by an organism or not." << endl;
	cout << "The occupied cells change from generation to generation" << endl;
	cout << "according to the number of neighboring cells which are alive." << endl;
}

// 函数:获取用户确认(yes/no)的回答,并返回布尔值表示结果
bool user_says_yes()
{
	int c;
	bool initial_response = true; // 标记是否是首次提示

	do
	{ // 循环直到获得有效输入为止
		if (initial_response)
			cout << " (y,n)? " << flush; // 首次提示信息
		else
			cout << "Respond with either y or n: " << flush; // 非首次提示信息
		do
		{ // 忽略空白字符并等待用户输入
			c = cin.get();
		} while (c == '\n' || c == ' ' || c == '\t'); // 检查换行符、空格和制表符
		initial_response = false;
	} while (c != 'y' && c != 'Y' && c != 'n' && c != 'N'); // 循环直至用户输入 y, Y, n 或 N
	return (c == 'y' || c == 'Y');							// 如果用户输入的是 y 或 Y,则返回 true,否则返回 false
}
#endif
  • instructions()函数用于输出康威生命游戏的基本介绍和运行原理,而user_says_yes()函数负责从用户那里获取“是/否”形式的回答,并在接收到有效的 y/n 输入后返回布尔值,以确定用户是否同意或希望继续进行某个操作。这个函数通过循环确保用户只能输入预期的有效字符。

(五)编写主程序文件

  • 编写主程序文件main.cpp,以运行我们的生命游戏并查看结果。在这个过程中,我们可以尝试不同的初始布局,观察它们如何按照生命游戏的规则演变。
    在这里插入图片描述
#include "life.h"
#include "utility.h"

int main() // 主程序:运行康威生命游戏
/*Pre: 用户提供一个初始的生命细胞配置。
  Post: 程序按照生命游戏规则打印出一系列显示生命细胞配置变化的图像。
  使用:Life 类及其方法 initialize(), 2 print(), 和 update()。
		函数 instructio1ns(); user_says_yes()。*/
{
	Life configuration;			// 创建一个 Life 类的对象,用于存储和更新生命游戏状态
	instructions();				// 输出游戏使用说明
	configuration.initialize();		// 初始化生命游戏的起始状态
	cout << "count = " << configuration.neighbor_count(2, 3) << endl; // 示例性调用 neighbor_count 方法,并打印某个位置周围活细胞的数量
	configuration.print();		// 打印当前生命游戏状态
	cout << "Continue viewing new generations? " << endl;
	while (user_says_yes()) // 当用户希望继续查看时,循环执行以下操作
	{
		configuration.update(); // 根据生命游戏规则计算并更新到下一个世代
		configuration.print();	// 打印更新后的新一代生命游戏状态
		cout << "Continue viewing new generations? " << endl;
	}

	return 0; // 主程序正常结束,返回值为0
}
  • 这段代码定义了主函数main(),它创建了一个Life对象来处理生命游戏的所有状态变化。首先输出游戏说明,然后初始化生命游戏状态,接着通过neighbor_count()方法演示如何计算某个格子周围的活细胞数量,并打印当前状态。

  • 接下来,程序进入一个循环,询问用户是否继续观察新的生命游戏世代。如果用户选择继续(由user_says_yes()函数获取),则通过调用configuration.update()更新到下一世代,并再次打印新的状态,循环反复直到用户不再希望继续观看。最后,主函数返回0,表示程序成功执行完毕。

(六)运行程序,查看结果

  • 运行生命游戏程序后,我们可以看到一个由星号(*)表示的生命单元组成的初始布局。随着每个世代的更新,生命的数量和分布会发生变化,根据生命游戏的规则(B3/S23),只有在有2个或3个邻居时生命才能存活。通过观察这些动态变化,我们可以感受到生命游戏中的简单规则如何产生复杂且意想不到的行为模式。
  • 尝试初始布局
    在这里插入图片描述
  • 运行程序,输入
2 2
2 3
2 4
2 5
-1 -1

在这里插入图片描述

  • 输入y,继续游戏
    在这里插入图片描述

  • 输入y,继续游戏
    在这里插入图片描述

  • 输入n,结束游戏
    在这里插入图片描述

(七)尝试生命游戏其它初始布局

  • 在生命游戏中,尝试不同的初始布局可以产生千变万化的结果。例如,你可以从简单的点状布局开始,观察它们如何相互作用和演变;也可以设计复杂的图案,如滑翔机、飞船等,看它们如何在网格上移动和繁殖。通过探索各种初始布局,我们可以更深入地理解生命游戏的规则和复杂性。
    在这里插入图片描述

三、实战总结

  • 在C++中实现康威生命游戏的实战项目通过设计Life类及其成员函数,将数学理论转化为实际代码。该项目涵盖了从初始化、打印到更新游戏状态的关键环节,并通过计算邻居数量的方法遵循生命游戏规则进行迭代。此外,项目还包括了辅助工具函数以增强用户体验,如输出游戏说明和处理用户交互。主程序实现了整个生命游戏的流程控制,允许用户观察不同初始布局下的演化过程。此实现不仅展示了如何构造元胞自动机模型,也通过实践帮助学习者深入理解简单规则如何产生复杂行为这一深刻概念。

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

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

相关文章

wordcloud,一个超强的 Python 库!

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 大家好&#xff0c;今天为大家分享一个超强的 Python 库 - wordcloud。 Github地址&#xff1a;https://github.com/amueller/word_cloud 词云图是一种独特而引人注目的数据可视化方式&#xff0c;通常用于显示…

第35集《佛法修学概要》

己四 、 精进度 分三&#xff1a;庚一、 精进自性。庚 二、趣入修习精进方便。 庚三、修习精进差别内容 请大家打开讲义第九十四页&#xff0c;我们看己四&#xff0c;精进度。 当我们从人天乘一个好人的阶段提升到一种菩萨道的修学&#xff0c;我们就要注意两个重点了。在我…

什么是内网穿透?

简介&#xff1a; 书面来说&#xff1a;内网穿透是一种网络技术&#xff0c;用于将内部私有网络中的服务暴露给公共网络&#xff0c;使得外部网络可以通过公网访问内网的服务。通常情况下&#xff0c;内网中的设备和服务由于位于私有网络中&#xff0c;无法直接通过公网IP进行…

9.1 Maven项目管理(❤❤❤❤)

9.1 Maven项目管理 1. Maven介绍2. 创建Maven项目2.1 创建2.2 结构分析3. Maven依赖管理3.1 简介3.2 设置下载镜像仓库4. 本地仓库与中央仓库5. Maven生命周期6. Maven插件技术6.1 build标签7. maven属性管理

Django从入门到精通(一)

目录 一、Django环境搭建与命令 1.1、安装 1.2、命令行 创建项目 编写代码 运行 app概念 1.3、Pycharm创建项目 1.4、虚拟环境 创建虚拟环境 - 命令行 介绍 操作 基本问题 Pycharm 项目虚拟环境 django虚拟环境【安装django最新版本】 django虚拟环境【安装指…

《软件方法》强化自测题-杂项(3)-少林足球巴别塔-不属于“软件方法建模师”考察范围

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 本套自测题不属于“软件方法建模师”考察范围。 自测链接&#xff1a;https://www.101test.com/cand/index?paperIdQR6CGK 1. [单选] 著名歌曲《橄榄树》&#xff08;不要问我从那…

端口映射的定义、特点、场景、实例、常见问题回答(Port Mapping)

目 录 一、端口映射&#xff08;Port Mapping&#xff09; 二、端口映射应用场景&#xff08;什么时候用到端口映射&#xff09; &#xff08;一&#xff09;、使用端口映射的条件 &#xff08;二&#xff09;使用端口映射的具体场景 三、端口映射技术的特点 …

内网安全管理系统(保密管理系统)

在当今信息化的时代&#xff0c;企业的内网已经成为其核心资产的重要组成部分。 随着企业的快速发展和信息化程度的提升&#xff0c;内网安全问题日益凸显&#xff0c;如何保障内网的安全和机密信息的保密性&#xff0c;已经成为企业亟待解决的问题。 内网安全管理系统(保密管…

Docker项目部署()

1.创建文件夹tools mkdir tools 配置阿里云 Docker Yum 源 : yum install - y yum - utils device - mapper - persistent - data lvm2 yum - config - manager -- add - repo http://mirrors.aliyun.com/docker- ce/linux/centos/docker - ce.repo 更新 yum 缓存 yum makec…

大路灯和护眼台灯哪个好?2024五款大路灯推荐

家用照明发展至今&#xff0c;从古时的匡衡凿壁借光读书&#xff0c;到后面的油灯、蜡烛等照明方式&#xff0c;再到近代的普通白炽灯&#xff0c;荧光灯、LED等电致发光灯具&#xff0c;发展到现在&#xff0c;科技在进步&#xff0c;文明在升级&#xff0c;照明灯具早已不再仅…

各种Linux版本安装Docker

文章目录 一、Ubuntu 20.04.61. 网卡和DNS配置2. Docker安装 二、CentOS Linux 7.91. 网卡和DNS配置2. Docker安装 三、Alibaba Cloud Linux 31. DNS配置2. repo说明3. Docker安装 四、验证是否安装成功 一、Ubuntu 20.04.6 1. 网卡和DNS配置 /etc/netplan 找到 *.yaml 文件 …

YOLOv8全网首发:新一代高效可形变卷积DCNv4如何做二次创新?高效结合SPPF

💡💡💡本文独家改进:DCNv4更快收敛、更高速度、更高性能,与YOLOv8 SPPF高效结合 收录 YOLOv8原创自研 https://blog.csdn.net/m0_63774211/category_12511737.html?spm=1001.2014.3001.5482 💡💡💡全网独家首发创新(原创),适合paper !!! 💡💡💡…

bgp选路

完成基础配置后&#xff1a; 配置bgp&#xff08;如r2&#xff09;&#xff1a; 全布配置与重发布完成后&#xff1a;全网可达 起源属性修改选路&#xff1a;

LeetCode 0082.删除排序链表中的重复元素 II:模拟

【LetMeFly】82.删除排序链表中的重复元素 II&#xff1a;模拟 力扣题目链接&#xff1a;https://leetcode.cn/problems/remove-duplicates-from-sorted-list-ii/ 给定一个已排序的链表的头 head &#xff0c; 删除原始链表中所有重复数字的节点&#xff0c;只留下不同的数字…

2023年十款开源测试开发工具推荐(自动化、性能、造数据、流量复制)

1、AutoMeter-API 自动化测试平台 AutoMeter 是一款针对分布式服务&#xff0c;微服务 API 做功能和性能一体化的自动化测试平台&#xff0c;一站式提供发布单元&#xff0c;API&#xff0c;环境&#xff0c;用例&#xff0c;前置条件&#xff0c;场景&#xff0c;计划&#xf…

家教上门助教小程序源码,家教小程序,家教系统,家教app,家教源码

家教上门助教小程序源码&#xff0c;家教小程序&#xff0c;家教系统&#xff0c;家教app&#xff0c;家教源码 推荐使用宝塔面板Linux NginxPHPMYSQL 支持家教老师筛选 支持家教人员入住 支持购买课程 支持教学资讯 支持订单课程

剪映导入素材全是绿屏解决方案

自己导入的视频或者是使用素材库里面的素材导入&#xff0c;结果都是一样全都是绿屏 网上找到原因是&#xff1a;兼容性或者软件的问题。 结果方案 &#xff1a; 菜单--全局设置 全局设置--性能。 把启用硬件加速编码和启动硬件加速解码俩个复选框取消掉&#xff01;重启一下…

某马头条——day06

自媒体文章上下架 使用消息队列在自媒体下架时通知文章微服务。 kafka概述 kafka环境搭建 docker pull zookeeper:3.4.14 docker run -d --name zookeeper -p 2181:2181 zookeeper:3.4.14 安装kafka docker pull wurstmeister/kafka:2.12-2.3.1 docker run -d --name kafka…

CVE-2023-46226 Apache iotdb远程代码执行漏洞

项目介绍 Apache IoTDB 是针对时间序列数据收集、存储与分析一体化的数据管理引擎。它具有体量轻、性能高、易使用的特点&#xff0c;完美对接 Hadoop 与 Spark 生态&#xff0c;适用于工业物联网应用中海量时间序列数据高速写入和复杂分析查询的需求。 项目地址 https://io…

像 Google SRE 一样 OnCall

在 Google SRE 的著作《Google运维解密》(原作名&#xff1a;Site Reliability Engineering: How Google Runs Production Systems)中&#xff0c;Google SRE 的关键成员们几乎不惜用了三个章节的篇幅描述了在 Google 他们是如何 OnCall 的。 Google SRE 实践中&#xff0c;有…