中学生の頃、パソコン雑誌でライフゲームを知った。これは今でも僕を魅惑し続ける奇跡のようなシミュレーションだ。鳥肌が立つほど奥が深い。

ライフゲームは、ゲームっていうから誤解されやすいんだけど、いわゆるテレビゲームではなく、生物の誕生と死滅を、オセロの盤面のような世界で表現するシミュレーションなんだ。

コンウェイというイギリスの数学者が1970年に考案したらしい。結構昔だ。

ライフゲームはルールさえ知っていれば、紙と鉛筆できてしまう。

まず始めに、格子を描いて適当なマスに○を描く。 各○が生物一匹一匹を表している。

誤解しやすいことなんだけど、ライフゲームの生物は動かない。その場に居続けるか、死んで消えるか、新しく生まれるか、それだけなんだ。

生物が次の世代も生きるか、それとも死ぬかは、周りの8個のマス(セルって呼ぶことにする)に他の生物が何匹いるかで決まる。下の図の赤の生物に着目しよう。この生物の周りを薄いピンクで示した。周りに2匹か3匹の生物がいると次の世代も生きながらえる。この生物の周りには2匹の生物がいるので、次の世代も生きることができる。

それ以外の場合、つまり1以下でも4以上では、次の世代で死んで消えてしまう。 寂しいと死んじゃうし、ぎゅうぎゅうでも死んじゃうってことだね。

それぞれの生物に対して周りにいる生物の数を数えてみる。そして、死んでしまうものを赤で、生きるものを緑で数字を書いてみる。

あと、生物のいないセルでも、周りに3つの生物がいると次の世代で新しく生物が生まれる。これは水色で3と示した。

よって、生き残る生物と生まれる生物を合わせると、第2世代の生物は下のようになる。

ルールはこれだけ。

まとめるとこんな感じ。

  1. 生きている生物は、周りに2匹か3匹の生物がいると次の世代も生きる。それ例外は死ぬ。
  2. 生物がいないところでは、周りに3匹の生物がいると、新しく生まれる。

同じようにして第3世代を計算すると、下のようになるね。

こんな感じで永遠と続けていく。これが、ライフゲーム。

で、どこが面白いの?

そう思うかも知れない。それに答えるとすれば、「こんなにシンプルなルールなのに、想像を越える色々な動きをするパターンがあるから」、だ。まあ、見ててよ。

さて、手で描くのが大変になったらプログラムで動かそう。手で描くと時間がかかるけど、プログラムだと一瞬だ。するとパターンが動いて見える。

下のプログラムはJavaScriptという言語で書いている。ポームページ上で動くからとっても便利。

RUNを押すと始まる。タップで生物を作ったり消したりもできる。

var canvas1 = document.getElementById(“canvas1”); canvas1.addEventListener(‘click’, onClick, false); var ctx1 = canvas1.getContext(“2d”); var Timer; var TimerVar=1000; var w=320; var h=320; var dw =32; var dh =32; var nw=w/dw; var nh=h/dh; var s0 = new Array(nh); var s1 = new Array(nh); for (i=0;i<nh;i++){ s0[i]=new Array(nw); s1[i]=new Array(nw); } var pat = [[0,1,1,1,0], [0,1,0,0,0], [0,1,1,0,0]]; h_pat=3 w_pat=5 pat_y = 2 pat_x = 3 for(i=0;i<nh;i++){ for(j=0;j<nw;j++){ s0[i][j] = 0; s1[i][j] = 0; } } for(i=0;i<w_pat;i++){ for(j=0;j<h_pat;j++){ s0[j+pat_y][i+pat_x]=pat[j][i]; } } function Start() { if (document.f1.b1.value == "RUN") { document.f1.b1.value="STOP"; Timer = setInterval("Main()",TimerVar); Main(); Show_field(); } else { document.f1.b1.value="RUN"; Show_field(); clearInterval(Timer); } } function Show_field() { ctx1.fillStyle="white"; ctx1.rect(0,0,w,h); ctx1.fill(); for(i=0;i<nh;i++){ for(j=0;j<nw;j++){ ctx1.beginPath(); ctx1.lineWidth=1; if(document.f1.b1.value=="RUN"){ ctx1.fillStyle="rgba(200,200,200,1)"; }else{ ctx1.fillStyle="rgba(255,255,255,1)"; } ctx1.strokeStyle="rgba(100,100,100,1)"; ctx1.rect(j*dw,i*dh,dw-1,dh-1); ctx1.fill(); ctx1.stroke(); ctx1.beginPath(); if(s0[i][j]==1){ ctx1.strokeStyle="rgba(10,10,10,1)"; ctx1.lineWidth=4; ctx1.fillStyle="white"; ctx1.arc(j*dw+dw/2,i*dh+dh/2,dh/2-5,0,2*Math.PI,false); ctx1.fill(); ctx1.stroke(); ctx1.beginPath(); } } } } function Clear_all() { for(i=0;i<nh;i++){ for(j=0;j<nw;j++){ s0[i][j] = 0; } } document.f1.b1.value=="RUN" Show_field(); } function Reset() { for(i=0;i<nh;i++){ for(j=0;j<nw;j++){ s0[i][j] = 0; } } for(i=0;i<w_pat;i++){ for(j=0;j<h_pat;j++){ s0[j+pat_x][i+pat_y]=pat[j][i]; } } if(document.f1.b1.value=="STOP"){ Start(); }else{ Show_field(); } } function onClick(e) { var rect = e.target.getBoundingClientRect(); x = e.clientX – rect.left; y = e.clientY – rect.top; ix=Math.floor(x/dw); iy=Math.floor(y/dh); s0[iy][ix]=1-s0[iy][ix]; Show_field(); } function Main(){ f_live=0; for(i=1;i<nh-1;i++){ for(j=1;j<nw-1;j++){ im=i-1; jm=j-1; ip=i+1; jp=j+1; s=s0[im][jm]+s0[im][j]+s0[im][jp]+ s0[i ][jm] +s0[i ][jp]+ s0[ip][jm]+s0[ip][j]+s0[ip][jp]; if(s0[i][j]==0){ if(s==3){ s1[i][j]=1; f_live=1; }else{ s1[i][j]=0; } }else{ if(s==2 | s==3){ s1[i][j]=1; f_live=1; }else{ s1[i][j]=0; } } } } for(i=0;i<nh;i++){ for(j=0;j<nw;j++){ s0[i][j] = s1[i][j]; } } Show_field(); if(f_live==0){ Start(); } } Reset();

はじっこのセルの扱いだけど、ここでは、端の生物は次の世代で必ず死ぬようにしている。

他に、ゲームみたいに左右上下を繋げていしまうというやり方もある。

さて、次は、いろいろな面白いパターンを紹介しよう。そして、もっと大きいフィールドで遊んでみよう。

02 へ

トップに戻る