博物馆|生命游戏

写在前面

现有的科学研究显示,生命形式由单细胞开始。中学时在实验课上借着显微镜看细胞,看着镜中一个个排列规整,“生机勃勃”的细胞,会想象它们在”细胞群”中度过的一生,那么我们可不可以建立一个简单的模型来模拟一下,看看它们可能的演变过程呢。

Part I

那我们来建个模吧。

为了简化问题

我们考虑将每个生命(细胞)简化为方格平面上的一格

唰!我们割开一个二维平面,然后将平面划分成一个个小格子

上图中黑色格子就是我们简化的细胞模型

在放置完细胞后,下一步做什么?

神说,要有光。(划去)

我们来考虑这样一些问题

当时间开始走动起来的时候,

细胞本身

  1. 在什么条件下能够存活
  2. 在什么条件下能够繁衍后代,以及后代存在的位置
  3. 在什么条件下死亡

我们知道生命是要和外界周围发生联系的

所以我们把四周八个格子称为中心格子的邻居,纳入考量

我们感性地可以制定下面的规则

  • 任何活细胞如果活邻居少于2个,则死掉。(“人口”过少)
  • 任何活细胞如果活邻居为2个或3个,则继续活。(正常)
  • 任何活细胞如果活邻居大于3个,则死掉。(”人口“过多)
  • 任何"空地"如果活邻居正好是3个,则活过来。(繁殖)

诶等等,就这样的几个规则?

说好的生命游戏呢?四个规则能玩出什么花来吗?

Part II

我们来看看这简单的四个规则究竟能撞出怎样的火花吧。

根据Part1中制定的规章

我们可以用C++编制一个简单的生命游戏

//生命游戏核心代码
#define MAXN 10
#define KEEP 2
#define BORN 3
struct Cell{
    bool live;
    int others;
}c[MAXN|1][MAXN|1];
inline void judge(){
    for(int i=1;i<=MAXN;i++)
        for(int j=1;j<=MAXN;j++){
                c[i][j].others=0;
                if(c[i-1][j].live&&i-1>0) c[i][j].others++;
                if(c[i+1][j].live&&i+1<MAXN) c[i][j].others++;
                if(c[i][j-1].live&&j-1>0) c[i][j].others++;
                if(c[i][j+1].live&&j+1<MAXN) c[i][j].others++;
                if(c[i-1][j-1].live&&i-1>0&&j-1>0) c[i][j].others++;
                if(c[i+1][j-1].live&&i+1<MAXN&&j-1>0) c[i][j].others++; 
                if(c[i-1][j+1].live&&i-1>0&&j+1<MAXN) c[i][j].others++;
                if(c[i+1][j+1].live&&i+1<MAXN&&j+1<MAXN) c[i][j].others++;
        }
    suriver=0;
    for(int i=1;i<MAXN;i++)
        for(int j=1;j<MAXN;j++){
                switch(c[i][j].others){
                    case BORN: c[i][j].live=true;suriver++; break;
                    case KEEP: if(c[i][j].live)suriver++;break;
                    default: c[i][j].live=false; break;
                }
        }
}

如果还不会编制C++代码,可以下载更为完善的Golly进行模拟

我们先来试试构建的这个模型吧

随机构造一些坐标放置细胞,如下

5 5
4 5
3 5
1 2
1 1
2 3
3 2
3 5
6 5
3 4
2 7
6 3
4 7
6 2
4 7
-1 -1

得到

根据上面简单的演示我们可以看到,仅仅只是使用了四个简单的规则,和一些杂乱无章的初始活细胞位置,也能够演化出复杂多变的局面。

事实上

通过不断的测试,人们发现了更多有意思的特殊”生命形式“

会不断行进的”滑翔者“

可以源源不断产生滑翔者的”滑翔者“枪

甚至还有可以不断行进并产生”滑翔者“的”繁殖者“

它会向右行进,留下一个接一个的“滑翔者枪”。动图最后一帧定格时用三种颜色区分了繁殖者本体、滑翔者枪和它们打出来的滑翔者

Part 3

事实上,我们建模的过程和英国数学家约翰·何顿·康威在1970年研究元胞自动机的过程如出一辙,因此该规则下的”生命游戏“也被称之为康威生命游戏。

仅仅是简单的四个规则,我们放置下的细胞们也可以演化出多样的结构。

那么我们所处的真实宇宙的规则,最终也会是如此的简单优雅吗?

开发出著名科学计算软件Mathematica的斯蒂芬·沃尔夫勒姆(Stephen Wolfram)曾如此说:

宇宙的本质是计算

或许这句话听来过于”武断“,但斯蒂芬的判断说明了,既然不含随机性的细胞自动机也可以产生”无法预测“的模式,我们生活中所存在的”不确定性“,可能也是根据”不含随机性“的有限规则计算产生的”确定结果“。

写在后面

关于元胞自动机的扩展阅读资料:https://www.guokr.com/article/439770/

部分图源来自:Life Wiki https://www.conwaylife.com/wiki/

附上自己编的生命游戏程序,另托管于Github,可点原文查看

#include<cstdio>
#include<Windows.h>
#define SLEEPTIME 500//刷新时间
#define MAXN 50//地图边长
#define KEEP 2//不死最少需细胞
#define BORN 3//产生最少需细胞
struct Cell{
    bool live;
    int others;
}c[MAXN|1][MAXN|1];
int round=0,suriver=0;
void HideCursor() { 
    CONSOLE_CURSOR_INFO cursor_info = {1, 0};  
    SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}
// 更改窗口大小,自适应
void ChangeWindow() {
    const int columns = 2*MAXN;
    const int rows = MAXN;
    char ch[100];
    int size = sprintf(ch,"mode con cols=%d lines=%d",columns,rows);
    ch[size]='\0';
    system(ch);
    HideCursor();
}
inline void init(){
    int x,y;
    while(1){
        scanf("%d %d",&x,&y);
        if(x>0&&x<=MAXN&&y>0&&y<=MAXN)
            c[x][y].live=true;
        else if(x==-1&&y==-1) return ;
        else printf("NO EXIST!\n");
    }
    fclose(stdin);
}
//根据规则执行的局面判断
inline void judge(){
    for(int i=1;i<=MAXN;i++)
        for(int j=1;j<=MAXN;j++){
                c[i][j].others=0;
                if(c[i-1][j].live&&i-1>0) c[i][j].others++;
                if(c[i+1][j].live&&i+1<=MAXN) c[i][j].others++;
                if(c[i][j-1].live&&j-1>0) c[i][j].others++;
                if(c[i][j+1].live&&j+1<=MAXN) c[i][j].others++;
                if(c[i-1][j-1].live&&i-1>0&&j-1>0) c[i][j].others++;
                if(c[i+1][j-1].live&&i+1<=MAXN&&j-1>0) c[i][j].others++; 
                if(c[i-1][j+1].live&&i-1>0&&j+1<=MAXN) c[i][j].others++;
                if(c[i+1][j+1].live&&i+1<=MAXN&&j+1<=MAXN) c[i][j].others++;
        }
    suriver=0;
    for(int i=1;i<=MAXN;i++)
        for(int j=1;j<=MAXN;j++){
                switch(c[i][j].others){
                    case BORN: c[i][j].live=true;suriver++; break;
                    case KEEP: if(c[i][j].live)suriver++;break;
                    default: c[i][j].live=false; break;
                }
        }
}
inline void draw(){
    ChangeWindow();
    for(int i=1;i<=MAXN;i++){
        for(int j=1;j<=MAXN;j++){
            if(c[i][j].live)    printf("■");
            else printf("□");
        }
        //printf("\n");
    }
    printf(" round:%d suriver:%d",round,suriver);
}
int main(){
    printf("Input by file?(\"y\"or\"n\")\n");
    if(getchar()=='y') freopen("data.txt","r",stdin);
    else printf("Put points you want.\nInput -1 -1 to finish\n");
    init();
    draw();
    while(1){
        round++;
        judge();
        draw();
        Sleep(SLEEPTIME);
    }
    //fclose(stdout);
    return 0;
}

以及配套的随机数据生成器

#include<cstdio>
#include<ctime>
#include<cstdlib>
int main(){
    freopen("data.txt","w",stdout);
    srand(time(0));
    int amount=rand()%50+10;
    for(int i=1;i<=amount;i++){
        printf("%d %d\n",rand()%9+1,rand()%9+1);
    }
    printf("-1 -1\n");
    fclose(stdout);
    return 0;
}

So,当个创世神吧!

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇