生命游戏的简单实现(c++代码)

今天上数模课,本来一如既往准备自习,但是,生命游戏——从前就在“人工智能”的书上看到过,今天一讲,发现如此简单。课上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窗口实现 ,比较丑陋。(下面是过程的图)


结语

实现起来还是非常有趣且简单的!!

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值