ライフゲーム

APL で書かれたライフゲームをネタに R に初挑戦

http://d.hatena.ne.jp/sumim/20090218/p1

Rはたしなむ程度で、ゴックンしたレベルにはほど遠いけど、書いてみた。
というか、自分が理解するために手を動かしてみた、という感じ。

life = function(m){
  rot = function(n,d) (1:n + d-1)%%n + 1
  shift = function(ds) m[rot(nrow(m),ds[1]),rot(ncol(m),ds[2])]

  ds = sapply(strsplit(outer(-1:1,-1:1,paste)," "),as.numeric)
  s = array(apply(apply(ds,2,shift),1,sum),dim(m))
  (s==3) + ((s==4) & m)
}

実行結果

> m = matrix(0,5,5)
> m[2:4,2:4] = matrix(1:9 %in% c(2,3,4,5,8) + 0,3,3,T)
> m
     [,1] [,2] [,3] [,4] [,5]
[1,]    0    0    0    0    0
[2,]    0    0    1    1    0
[3,]    0    1    1    0    0
[4,]    0    0    1    0    0
[5,]    0    0    0    0    0
> life(m)
     [,1] [,2] [,3] [,4] [,5]
[1,]    0    0    0    0    0
[2,]    0    1    1    1    0
[3,]    0    1    0    0    0
[4,]    0    1    1    0    0
[5,]    0    0    0    0    0

メモ
全体的なアルゴリズムとしては、元の行列とそれを8方向にずらした行列の9枚の足し算をした行列によって生死の判断をしている(と思う)。
(s==4) & m と元の行列mでマスクをかけることによって、「1匹の周りに3匹いたら生き残り」と「何もないところの周りに4匹いても誕生しない」を区別している(と思う)。
剰余を使ったベクトルのローテーション、それを使って行列をシフトする技が勉強になった。
outer(-1:1,-1:1,shift')のような感じで、いきなり5×5×3×3の配列を作ろうとしたが、outerでは想定外の要素数を返す関数は使えなかった。それを回避するためにいったん文字列に変換してるところがかっこわるい。

追記

APL で書かれたライフゲームをネタに R に再挑戦

http://d.hatena.ne.jp/sumim/20090221/p1

私の書いたものよりももっといいものがここにあります。