生命游戏的简单实现(c++代码)
一、生命游戏生命游戏(Game of Life, 简称生命)是 John Conway 于 1970 年发明的生命游戏不是通常意义上的游戏,没有游戏者,也无所谓胜负生命游戏是一类特殊的细胞自动机一旦给定初始状态,之后的发展完全由规则确定生命充满了悬念!绝大多数情况下,不可能只根据初始状态(或称模式)判断未来的发展,只能按照游戏的规则运行下去实现起来还是非常有趣且简单的!!
·
今天上数模课,本来一如既往准备自习,但是,生命游戏——从前就在“人工智能”的书上看到过,今天一讲,发现如此简单。课上30min实现了一份简单的生命游戏代码/
前言
系统演变仿真——生命游戏(与细胞自动机but没实现)
这是数模课的一节内容,讲计算机仿真,其中的一个小点,生命游戏。
一、生命游戏
- 生命游戏(Game of Life, 简称 生命)是 John Conway 于 1970 年发明的
- 生命游戏不是通常意义上的游戏,没有游戏者,也无所谓胜负
- 生命游戏是一类特殊的 细胞自动机(Cellular Automata)
- 一旦给定初始状态,之后的发展完全由规则确定
生命充满了悬念!绝大多数情况下,不可能只根据初始状态(或称模式)判断未来的发展,只能按照游戏的规则运行下去
生命游戏的基本设置
- 游戏在一个方形网格中进行,网格在各个方向上都是无限延伸的
- 每个网格中有一个细胞,细胞可以是 活 的或者 死 的
- 如果细胞是活的就在它所在的方格做一个标记,死的细胞则留空
- 每个细胞的 邻居 是指它最邻近的 8 个方格
生命游戏的规则
- 游戏的每一步中,计算每个细胞的 活邻居数目,由此数字决定下一步发展
- 如果一个死细胞正好有 3 个活邻居,则下一步变成一个活细胞(诞生)
- 如果一个活细胞有 2 个或 3 个活邻居,则可以继续活下去(生存)
- 其他情况下,细胞将死去或保持死的状态(拥挤或孤独)
生命游戏的应用与发展
- 生命游戏的演变规则近似的描述了生物群体的生存规律,经过扩展能够模拟生命活动中的生存、灭绝、竞争等等复杂现象
- Conway 证明,生命游戏具有通用图灵机的计算能力,能力上与图灵机等价
- 生命游戏的主要扩展方式包括修改或扩展规则和改变生存空间设置
二、代码实现过程
- 游戏的每一步中,计算每个细胞的 活邻居数目,由此数字决定下一步发展
这一步遍历整个表并且记录信息即可。
- 如果一个死细胞正好有 3 个活邻居,则下一步变成一个活细胞(诞生)
- 如果一个活细胞有 2 个或 3 个活邻居,则可以继续活下去(生存)
- 其他情况下,细胞将死去或保持死的状态(拥挤或孤独)
这一步跟据记录的信息,标记/更新下一轮存活/死亡的信息。
实际上,一句代码即可:
table[i][j]=(count[i][j]==3?true:(count[i][j]==2?table[i][j]:false));
此外,每一轮,经过循环控制就可以实现一代又一代的演变。
三、代码
#include<iostream>
#include<cstdio>
#include<random>
#include<time.h>
#include<windows.h>
#define SIZE 30
#define TIMES 1000
using namespace std;
bool table[SIZE][SIZE];
int count[SIZE][SIZE];//存储该网格周围存活细胞数
void init();//初始化table
void show();//打印table
void count_live(); //计算所有网格周围存活细胞数,结果存在count中
int calcu(int x,int y);//计算单个网格周围存活细胞数
void live_next();//计算下一个时间片存活的情况
int main()
{
init();
int times=0;
while(times++<TIMES)
{
show();
Sleep(20);
count_live();
live_next();
system("cls");
}
system("pause");
return 0;
}
void init()
{
srand(time(0));
for(int i=0;i<SIZE;++i)
for(int j=0;j<SIZE;++j)
{
table[i][j]=(rand()%3==0);
}
}
void show()//打印table
{
for(int i=0;i<SIZE;++i)
{
cout<<endl;
for(int j=0;j<SIZE;++j)
{
if(table[i][j])cout<<"*"<<" ";
else cout<<" "<<" ";
}
cout<<endl;
}
}
void count_live()
{
for(int i=0;i<SIZE;++i)
for(int j=0;j<SIZE;++j)
{
count[i][j]=calcu(i,j);
}
}
int calcu(int x,int y)//计算单个网格周围存活细胞数
{
int num=0;
if(table[(x-1+SIZE)%SIZE][(y-1+SIZE)%SIZE])num++;
if(table[(x-1+SIZE)%SIZE][(y+SIZE)%SIZE])num++;
if(table[(x-1+SIZE)%SIZE][(y+1+SIZE)%SIZE])num++;
if(table[(x+SIZE)%SIZE][(y-1+SIZE)%SIZE])num++;
if(table[(x+SIZE)%SIZE][(y+1+SIZE)%SIZE])num++;
if(table[(x+1+SIZE)%SIZE][(y-1+SIZE)%SIZE])num++;
if(table[(x+1+SIZE)%SIZE][(y+SIZE)%SIZE])num++;
if(table[(x+1+SIZE)%SIZE][(y+1+SIZE)%SIZE])num++;
return num;
}
void live_next()//计算下一个时间片存活的情况
{
for(int i=0;i<SIZE;++i)
{
for(int j=0;j<SIZE;++j)
{
table[i][j]=(count[i][j]==3?true:(count[i][j]==2?table[i][j]:false));
}
}
}
说明
#define SIZE 30
#define TIMES 1000
用于控制地图的大小、循环的轮次。
//init():
table[i][j]=(rand()%3==0);
用于控制初始化时,初始状态的网格点存活的概率,通过修改可以调整初始存活生命的多与少。
//show():
if(table[i][j])cout<<"*"<<" ";
else cout<<" "<<" ";
用于显示死亡/存活,可以自己修改显示的方式。
//main():
Sleep(20);
用于控制显示的帧率。
//calcu():
if(table[(x-1+SIZE)%SIZE][(y-1+SIZE)%SIZE])num++;
if(table[(x-1+SIZE)%SIZE][(y+SIZE)%SIZE])num++;
if(table[(x-1+SIZE)%SIZE][(y+1+SIZE)%SIZE])num++;
if(table[(x+SIZE)%SIZE][(y-1+SIZE)%SIZE])num++;
if(table[(x+SIZE)%SIZE][(y+1+SIZE)%SIZE])num++;
if(table[(x+1+SIZE)%SIZE][(y-1+SIZE)%SIZE])num++;
if(table[(x+1+SIZE)%SIZE][(y+SIZE)%SIZE])num++;
if(table[(x+1+SIZE)%SIZE][(y+1+SIZE)%SIZE])num++;
采用了边界取模循环,类比于空间无限大,回避边界问题。
可视化通过cmd窗口实现 ,比较丑陋。(下面是过程的图)
结语
实现起来还是非常有趣且简单的!!
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
已为社区贡献10条内容
所有评论(0)