C与C++游戏项目练习6:生命游戏简易版

生命游戏简易版

今天照着书学习了个新的游戏,生命游戏。似乎这个游戏模拟的是细胞种群的繁衍,很有意思。程序员和生物学爱好者双厨狂喜~~
在这里插入图片描述
贴上实现基础功能的代码片:实现的就是一下子满屏被“*”组成的细胞填满。

#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#include<Windows.h>
#include<time.h>

#define Height 25
#define Width 50

int cells[Height][Width];

void gotoxy(int x, int y)
{
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos;
	pos.X = x;
	pos.Y = y;
	SetConsoleCursorPosition(handle, pos);
}

void StartUp()
{
	for (int i = 0; i < Height; i++)
	{
		for (int j = 0; j < Width; j++)//随机初始化为1或0
		{
			cells[i][j] = rand() % 2;
		}
	 }
}

void Show()
{
	gotoxy(0, 0);
	for (int i = 0; i <= Height; i++)
	{
		for (int j = 0; j <= Width; j++)
		{
			if (cells[i][j] == 1)//输出活细胞
			{
				printf("*");
			}
			else//输出空格
			{
				printf(" ");
			}
		}
		printf("\n");
	}
	Sleep(500);
}

void UpdateWithoutInput()
{
	int NewCells[Height][Width] = { 0 };
	int NeighbourNumber = 0;//记得初始化为0
	for (int i = 1; i < Height - 1; i++)
	{
		for (int j = 1; j < Width - 1; j++)
		{
			NeighbourNumber = cells[i - 1][j - 1] + cells[i - 1][j] + cells[i - 1][j + 1] + cells[i][j - 1] + cells[i][j + 1]
				+ cells[i + 1][j - 1] + cells[i + 1][j] + cells[i + 1][j + 1];//看细胞周围存活的"邻居"数量
			if (NeighbourNumber == 3)//为什么不写大于等于三,我觉得可能是种群密度过高也不利于细胞存活,养分什么的可能不够吧
			{
				NewCells[i][j] = 1;//周围有三个存活的细胞,该细胞存活
			}
			else if (NeighbourNumber == 2)
			{
				NewCells[i][j] = cells[i][j];//维持原状态不变
			}
			else
			{
				NewCells[i][j] = 0;//死亡
			}
		}
	}
	for (int i = 1; i <= Height - 1; i++)
	{
		for (int j = 1; j <= Width - 1; j++)
		{
			cells[i][j] = NewCells[i][j];//更新下一帧的细胞存亡数据
		}
	}
}

void UpdateWithInput()
{

}

int main()
{
	StartUp();
	while (1)
	{
		Show();
		UpdateWithInput();
		UpdateWithoutInput();
	}
	return 0;
}

查资料时发现了知乎一位大佬的讲解很清晰,对于理解这个游戏的设定规则很有帮助:这也解释了我一开始犯的错误,把条件改成了“邻居大于等于3个就存活,后来一运行就发现结果很不理想,细胞把整个屏幕占满了,没有体现出种群的更迭来,因为结合实际考虑的话,种群数量过多也会抑制种群的发展。(似乎还有什么负反馈调节机制??高中生物学的记不得了············)

如果一个生命,其周围的同类生命太少,会因为得不到帮助而死亡;如果太多,则会因为得不到足够的生命资源而死亡。
——英国数学家约翰·康威

在这里插入图片描述
原帖:https://www.zhihu.com/question/30782166

在这里插入图片描述
图源百度,S形曲线就是种群生长受到环境阻力干扰的结果。
在这里插入图片描述

这里还有关于生命游戏的一些其他资源:
https://www.cnblogs.com/lfri/p/9733883.html

【生命游戏----简单规则创造复杂生命(】https://mr.baidu.com/r/ksxBNDHEru?f=cp&u=fb26ab163992ebda

3.1.2课后题全部实现的版本,使用了枚举常量来表示死细胞,活细胞,水源,食物和天敌:

typedef enum Status//枚举常量,这里用一个数字代表一种状态
{
	dead = 0,//死亡
	live = 1,//存货
	water = 2,//水源
	food = 3,//细胞的食物
	enemy=4//细胞的天敌
};

但是运行出来不知道为什么,几乎所有细胞无一生还······倒是这些除去细胞之后的元素生长得极其嚣张野蛮·····我感觉可能是跟我的数值设置有关,毕竟都是靠感觉来的,没有科学依据,所以造成了结果变成了瘟疫公司,细胞团灭···········

我的运行效果:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
阿巴阿巴阿巴阿巴阿巴阿巴······

实现按下R之后刷新游戏(这个R必须是开了大写锁定的R,没错,R和r不一样,区分大小写,不讲武德!!!)
为了方便操作,程序里我改成了r

在这里插入图片描述

细胞灭亡的全代码如下:
资源稍后也会上传,需要的可主页自取

#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#include<Windows.h>
#include<time.h>

#define Height 25
#define Width 50

int  sleeptime = 150;//默认Show()函数中刷新间隔为150s

typedef enum Status//枚举常量,这里用一个数字代表一种状态
{
	dead = 0,//死亡
	live = 1,//存货
	water = 2,//水源
	food = 3,//细胞的食物
	enemy=4//细胞的天敌
};

int cells[Height][Width];

void gotoxy(int x, int y)
{
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos;
	pos.X = x;
	pos.Y = y;
	SetConsoleCursorPosition(handle, pos);
}

void StartUp()
{
	gotoxy(0, 0);
	for (int i = 0; i < Height; i++)
	{
		for (int j = 0; j < Width; j++)//随机初始化为1或0
		{
			cells[i][j] = rand() % 10;//随机生成0-9的数字来对应枚举常量死细胞、活细胞、水源、食物、敌人
			//数字1,7,8,9都输出活细胞,这样让生成细胞的概率较大以免细胞过少导致游戏无法继续
		}
	 }
}

void Show()
{
	gotoxy(0, 0);
	for (int i = 0; i <= Height; i++)
	{
		for (int j = 0; j <= Width; j++)
		{
			if (cells[i][j] == 1|| (cells[i][j] >= 7 && cells[i][j] <=9))
			//数字1,7,8,9都输出活细胞,死细胞不输出(感觉这个@比较像细胞的形状)
			{
				printf("@");
			}
			else if (cells[i][j] == 2)//输出水源
			{
				printf("~");
			}
			else if (cells[i][j] == 3)//输出食物(感觉这个*图标长得更像食物所以就换了这个作为食物)
			{
				printf("*");
			}
			else if (cells[i][j] == 4)//输出敌人(感觉这个&长得像噬菌体所以用了这个)
			{
				printf("&");
			}
			else//5,6输出空格
			{
				printf(" ");
			}
		}
		printf("\n");
	}
	Sleep(sleeptime);
}

void UpdateWithoutInput()
{
	int NewCells[Height][Width] = { 0 };
	int NeighbourNumber = 0;//记得初始化为0
	for (int i = 1; i < Height - 1; i++)
	{
		for (int j = 1; j < Width - 1; j++)
		{
			NeighbourNumber = 0;//每个格子把邻居数量初始化为0
			if (cells[i][j] == 1 || (cells[i][j] >= 7 && cells[i][j] <= 9))//必须得是这个格子是活细胞的情况下才会判断后面的死活问题
			{
				for (int k = i - 1; k <= i + 1; k++)//看细胞周围8个格子存活的"邻居"数量、水源、敌人、食物情况
				{
					for (int l = j - 1; l <= j + 1; l++)
					{
						if (k != i && l != j)//不能算cells【i】【j】这个细胞自己
						{
							if (cells[k][l] == 1 || (cells[k][l] >= 7 && cells[k][l] <= 9))//符合是活细胞
							{
								NeighbourNumber++;
							}
							else if (cells[k][l] == 2)//该处是水源,细胞更容易存活
							{
								NeighbourNumber += 2;//因为有水和食物的地方更利于细胞种群的繁衍,所以这里种群数量(邻居)可能更多
							}
							else if (cells[k][l] == 3)//该处是食物
							{
								NeighbourNumber += 1;
							}
							else if (cells[k][l] == 4)//该处是敌人
							{
								NeighbourNumber -= 2;//敌人不利于细胞繁衍,邻居个数会少
							}
						}

					}
				}
				if (NeighbourNumber == 3)//为什么不写大于等于三,我觉得可能是种群密度过高也不利于细胞存活,养分什么的可能不够吧
				{
					NewCells[i][j] = 1;//周围有三个存活的细胞,该细胞存活
				}
				else if (NeighbourNumber == 2)
				{
						;//该位置是细胞,就维持原状,什么也不做
				}
				else
				{
					NewCells[i][j] = 0;//死亡
				}
			}
			else if(cells[i][j]>=2&& cells[i][j]<=6)//不是细胞,就重新随机生成水源。食物,空格或者敌人
			{
				NewCells[i][j] = rand() % 5+2;//随机生成0-4,+2就是2-6,即随机生成的是水源,食物和天敌、空格的一种
			}
		}
	}
	for (int i = 1; i <= Height - 1; i++)
	{
		for (int j = 1; j <= Width - 1; j++)
		{
			cells[i][j] = NewCells[i][j];//更新下一帧的细胞存亡数据
		}
	}
}

void UpdateWithInput()
{
	char input;
	if (_kbhit())
	{
		input = _getch();
		if (input == 27)//ESC暂停
		{
			system("pause");
		}
		else if (input == 'r')//restart重新开始,注意r是区分大小写的,这里要大写R的话必须开大写锁定!!!坑爹!!!
		{
			system("cls");//清屏
			StartUp();
			Show();
			Sleep(sleeptime);//增加一个Sleep缓冲,视觉体验更加,不至于很快一闪而过
		//goto RestartLable;//不能跳转到main函数中的StartUp,因为goto和label只能在一个函数中使用
		//goto语句可以使程序在没有任何条件的情况下跳转到指定的位置,所以goto语句又被称为是无条件跳转语句。
		}
		else if (input == '+')//加速游戏
		{
			sleeptime -= 50;//刷新时间间隔减少50秒
		}
		else if (input == '-')//减速游戏
		{
			sleeptime += 50;
		}
	}
}

int main()
{
	StartUp();//初始化
	while (1)
	{
		Show();
		UpdateWithInput();
		UpdateWithoutInput();
	}
	return 0;
}

在这里插入图片描述

“康威因与COVID-19相关的并发症去世,享年82岁。

生命游戏之父、数学家约翰·康威因新冠肺炎去世”
天哪太可惜了,没想到发明这个生命游戏的伟人竟然是和我们同时期的人物………跟我以前脑海里“课本上的伟人都是不在世的”的固有观念截然不同,这让我更加感受到世事无常和遗憾。

“此次疫情虽然夺去了生命游戏之父的生命,但是生命游戏将永远继续下去,我们将永远缅怀他。”

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值