中学生の頃、パソコン雑誌でライフゲームを知った。これは今でも僕を魅惑し続ける奇跡のようなシミュレーションだ。鳥肌が立つほど奥が深い。
ライフゲームは、ゲームっていうから誤解されやすいんだけど、いわゆるテレビゲームではなく、生物の誕生と死滅を、オセロの盤面のような世界で表現するシミュレーションなんだ。
コンウェイというイギリスの数学者が1970年に考案したらしい。結構昔だ。
ライフゲームはルールさえ知っていれば、紙と鉛筆できてしまう。
まず始めに、格子を描いて適当なマスに○を描く。 各○が生物一匹一匹を表している。
誤解しやすいことなんだけど、ライフゲームの生物は動かない。その場に居続けるか、死んで消えるか、新しく生まれるか、それだけなんだ。
生物が次の世代も生きるか、それとも死ぬかは、周りの8個のマス(セルって呼ぶことにする)に他の生物が何匹いるかで決まる。下の図の赤の生物に着目しよう。この生物の周りを薄いピンクで示した。周りに2匹か3匹の生物がいると次の世代も生きながらえる。この生物の周りには2匹の生物がいるので、次の世代も生きることができる。
それ以外の場合、つまり1以下でも4以上では、次の世代で死んで消えてしまう。
寂しいと死んじゃうし、ぎゅうぎゅうでも死んじゃうってことだね。
それぞれの生物に対して周りにいる生物の数を数えてみる。そして、死んでしまうものを赤で、生きるものを緑で数字を書いてみる。
あと、生物のいないセルでも、周りに3つの生物がいると次の世代で新しく生物が生まれる。これは水色で3と示した。
よって、生き残る生物と生まれる生物を合わせると、第2世代の生物は下のようになる。
ルールはこれだけ。
まとめるとこんな感じ。
- 生きている生物は、周りに2匹か3匹の生物がいると次の世代も生きる。それ例外は死ぬ。
- 生物がいないところでは、周りに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 へ
トップに戻る
Post Views: 731