[计算机模拟]元胞自动机[CA]初探---“生命游戏”的实现
by EmilMatthew 05/10/26
首先看一下什么是元胞自动机(摘自一篇网文)
元胞自动机(Cellular Automata,简称CA,也有人译为细胞自动机、点格自动机、分子自动机或单元自动机)。是一时间和空间都离散的动力系统。散布在规则格网 (Lattice Grid)中的每一元胞(Cell)取有限的离散状态,遵循同样的作用规则,依据确定的局部规则作同步更新。大量元胞通过简单的相互作用而构成动态系统的演化。不同于一般的动力学模型,元胞自动机不是由严格定义的物理方程或函数确定,而是用一系列模型构造的规则构成。凡是满足这些规则的模型都可以算作是元胞自动机模型。因此,元胞自动机是一类模型的总称,或者说是一个方法框架。其特点是时间、空间、状态都离散,每个变量只取有限多个状态,且其状态改变的规则在时间和空间上都是局部的。
元胞自动机的应用领域主要在:
1在凝聚态物理中用它来摸拟晶体生长,悬浮体的聚集,缺陷的产生.
2在流体力学中用它来摸拟粘滞流体的各种流动。
3在化学反应用用它来摸以反应扩散系统中的振荡和螺旋波。
4在生命科学中用它来摸拟心脏的纤颤,肿瘤的生长。
...
好了,有些抽像不是吗?下面看一个元胞自动机有趣的入门示例---LifeGame(生命游戏):
生命游戏是由英国剑桥大学数学家Conway提出的,游戏的规则是这样的,在一个正方的棋盘格上,每格只有两个状态,”生”和”死”,分别表示是否被一个棋子所占有.每个方格有八个邻格,游戏的规则如下:
1. 对于处在”生态的格,若八个邻居中有2个或3个”生”,则继续存活,否则将因过于孤独或过于拥挤而死亡.
2. 对于处在”死”态的空格,若八个邻格中有3个”生”,则该格转变为”生”(代表繁衍过程),否则继续空着.
规则讲完了,看到这里,相信掌握了任何一种开发工具的图形编程的朋友应该都有能力去尝试相应的摸拟了,我这里给出我用AS2在Flash中的实现(PS:由于最近几天我的用来展示的个人空间登陆不上,所以放不到网上了,你可以下载回去看,需装FalshPlayer7.0若以上版本)
下面给出该游戏在AS2中的实现的代码:
function lifeGame():Void
{
//caculate.
var squareSize:Number=10;
for(var i:Number=0;i<_root.gRowNum;i++)
for(var j:Number=0;j<_root.gColNum;j++)
{
var count:Number=0; //the live neighbor num count.
for(var k:Number=-1;k<=1;k++)
for(var l:Number=-1;l<=1;l++)
{
if(_root.gMapXk[i+k][j+l]==_root.LIVED&&!(k==0&&l==0)&&i+k>=0&&j+l>=0)
count++;
}
if(_root.gMapXk[i][j]==_root.LIVED)//original state is lived
{
if (count<=1||count>3)
_root.gMapXk_1[i][j]=_root.DEAD;
else
_root.gMapXk_1[i][j]=_root.LIVED;
/*if(i<=3&&j<=3)
trace("s1:"+String(i)+String(j)+String(_root.gMapXk_1[i][j])+String(count));*/
}
else if(_root.gMapXk[i][j]==_root.DEAD)//original state is dead.
{
if (count==3)
_root.gMapXk_1[i][j]=_root.LIVED;
else
_root.gMapXk_1[i][j]=_root.DEAD;
/*if(i<=3&&j<=3)
trace("s2:"+String(i)+String(j)+String(_root.gMapXk_1[i][j])+String(count));*/
}
}
//update show,and update XK
for(var i:Number=0;i<_root.gRowNum;i++)
for(var j:Number=0;j<_root.gColNum;j++)
{
if(_root.gMapXk[i][j]==_root.LIVED&&_root.gMapXk_1[i][j]==_root.DEAD)
{
drawSquare(_root.gXOffset+j*squareSize,_root.gYOffset+i*squareSize,_root.gColorArr[12],squareSize);
_root.gMapXk[i][j]=_root.DEAD;
}
else if(_root.gMapXk[i][j]==_root.DEAD&&_root.gMapXk_1[i][j]==_root.LIVED)
{
drawSquare(_root.gXOffset+j*squareSize,_root.gYOffset+i*squareSize,_root.gColorArr[3],squareSize);
_root.gMapXk[i][j]=_root.LIVED;
}
}
_root.gIterTimes++;
trace3("IterTimes:"+String(_root.gIterTimes)+"\n");
}
其实没什么难度,就是照着上面的规则把相应的代码写出即是(但是要注意细节,一不小心就会出错的),主要用到两个数组gMapXk和gMapXk_1进行迭代.
在Matlab里有相应的例子,要知道,几星期我还看着觉得有些云里雾里的感觉呢.只是觉得真的很有趣,现在亲手将之实践,并且能借助flash及网络的传播力将这些有趣的科学现象及其实现的方法介绍出来,小有些成就感. J
这是我根据手头的资料所做的相关测试,你可以根据不同的输入观察不同初始条件下元胞的生长情况.
你可以通过修改inputData.xml文件中的startRowNum和startColNum两个变量来扩充起始矩阵的规模:
1绝灭的初始态:
<row>1,0,0,0</row>
<row>0,1,0,0</row>
<row>0,0,1,0</row>
<row>0,0,0,0</row>
2稳定的初始态:
<row>0,0,1,1</row>
<row>0,0,0,1</row>
<row>0,0,0,0</row>
<row>0,0,0,0</row>
3振荡的初始态:
<row>0,0,1,1</row>
<row>0,0,0,1</row>
<row>0,0,0,0</row>
<row>0,0,0,0</row>
4爬行的初始态: (最后会趋于稳定态)
<row>0,1,0,0</row>
<row>0,0,1,0</row>
<row>1,1,1,0</row>
<row>1,1,1,0</row>
源码下载:
http://emilmatthew.51.net/downloads/CATest.rar
//如果上面这个链接无法响应下载(有可能是被网站给屏蔽掉了),则可使用下载工具(如迅雷等)下载。欢迎提出批评与指正意见