星期五, 二月 24, 2012

用R实现生命游戏(Game of Life)


生命游戏是英国数学家John Horton Conway在1970年发明的细胞自动机(cellular automaton)。它最初于1970年10月在《科学美国人》杂志中出现。生命游戏是在一个二维矩形世界中,这个世界中的每个方格居住着一个细胞。细胞的生命状态只有活着或死亡两种。细胞在下一个时刻的生死取决于相邻八个方格中活着细胞的数量。如果相邻方格活着的细胞数量过多,这个细胞会因为资源匮乏而在下一个时刻死去;相反,如果周围活细胞过少,这个细胞会因太孤单而死去。

其中一种较为丰富的设定有如下四条:
  • 若相邻的存活细胞数少于2,则细胞死于寂寞
  • 若相邻的存活细胞数多于3,则细胞死于拥挤
  • 若相邻的存活细胞数为2或3,则细胞继续存活
  • 若相邻的存活细胞数正好为3,死亡的细胞得到复活
根据这些资料,笔者在R中运行了相应的代码,首先运行1000次的演变过程,记录每个时间点上细胞的总数,根据这些变化的数字可以得到如下的图形。可以看到一开始细胞过多而出现大量死亡,在接近灭绝的时候又由于资源的空闲而大量繁殖,但繁殖存在一个上限,之后存活数目呈上下振荡趋势。
另一种玩法是不限定演变的次数,而是反复绘图,以上帝的视角观察这个二维世界中“人们”的变化。看它们生生死死、潮起潮落。在游戏的进行中,杂乱无序的细胞会逐渐演化出各种精致、有形的结构;有时,一些已经成形的结构会因为一些无序细胞的“入侵”而被破坏。但是形状和秩序经常能从杂乱中产生出来。
注:本文参考了wiki,以及《Introduction to Scientific Programming and Simulation Using R》第五章的习题。

R代码:
rm(list=ls())
#建立一个计算邻近存活细胞数目的函数,并使边缘的细胞仍有八个邻居
neighbours <- function(A,i,j,n) {
    left <- ifelse(j ==  1,n,j-1)
    right <- ifelse(j == n, 1, j+1)
    up <- ifelse(i == 1, n, i-1)
    down <- ifelse(i == n, 1, i+1)
        nbrs <- sum(A[up,left] == 1,A[up,right] == 1,A[up,j] == 1,A[i,left] == 1, A[i,right] == 1,A[down,left] == 1,A[down,right] == 1,A[down,j] == 1)
    return(nbrs)
    }
n <- 50  #方阵的行数
A <- matrix(round(runif(n^2)),n,n) #初始化二维世界方阵
finished <- FALSE
while (!finished) {  #重复进行演化,你需要用ESC退出
    plot(c(1,n),c(1,n),type='n',xlab='',ylab='') #绘图
    for(i in 1:n) {
        for (j in 1:n) {
            if (A[i,j]==1) {
                points(i,j,pch=16,col='red')
            }
        }
    }
    B <- A #将上期的信息存入本期矩阵B,并按照条件修改B
    for (i in 1:n) {
        for (j in 1:n) {
            nbrs <- neighbours(A,i,j,n)
            if (A[i,j]==1) {
                if ((nbrs ==2) | (nbrs==3)){
                    B[i,j] <- 1
                } else {
                    B[i,j] <- 0
                }
            } else {
                if (nbrs ==3) {
                B[i,j] <- 1
                } else {
                    B[i,j] <- 0
                }
            }
        }
}
A <- B #将变化后的B矩阵存回到A中
} 

2 条评论:

  1. 玩过这个没有:
    demo('game_of_life', package='animation', ask=FALSE)

    回复删除