セルオートマトンの中でもっとも有名なGame of Life(ライフ・ゲーム)のプログラムを書いてみよう。 これは2次元9近傍CAの一種である。なお、Game of Lifeの解説とシミュレータの完成品を 置いたホームページは「関連コンテンツへのリンク」から辿れる。
sum = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
state = 1 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
state = 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
state=s[x][y]; snew[x][y]=rule[state][sum]; |
(1)上左隅(2)上右隅(3)下左隅(4)下右隅(5)上辺(隅以外)(6)下辺(隅以外)(7)左辺(隅以外)(8)右辺(隅以外)(9)辺以外の9通りに分類できるから、たとえばその部分のプログラムは
if(y==0){ if(x==0){ sum=s[NX-1][NY-1]+s[0][NY-1]+s[1][NY-1]+s[NX-1][0]+s[1][0]+s[NX-1][1]+s[0][1]+s[1][1];} else if(x==NX-1){ sum=s[NX-2][NY-1]+s[NX-1][NY-1]+s[0][NY-1]+s[NX-2][NY-1]+s[0][NY-1]+s[NX-2][1]+s[NX-1][1]+s[0][1];} else{ sum=s[x-1][NY-1]+s[x][NY-1]+s[x+1][NY-1]+s[x-1][NY-1]+s[x+1][NY-1]+s[x-1][1]+s[x][1]+s[x+1][1];} } else if(y==NY-1){ if(x==0){ sum=s[NX-1][NY-2]+s[0][NY-2]+s[1][NY-2]+s[NX-1][NY-1]+s[1][NY-1]+s[NX-1][0]+s[0][0]+s[1][0];} else if(x==NX-1){ sum=s[NX-2][NY-2]+s[NX-1][NY-2]+s[0][NY-2]+s[NX-2][NY-1]+s[0][NY-1]+s[NX-2][0]+s[NX-1][0]+s[0][0];} else{ sum=s[x-1][NY-2]+s[x][NY-2]+s[x+1][NY-2]+s[x-1][NY-1]+s[x+1][NY-1]+s[x-1][0]+s[x][0]+s[x+1][0];} } else{ if(x==0){ sum=s[NX-1][y-1]+s[0][y-1]+s[1][y-1]+s[NX-1][y]+s[1][y]+s[NX-1][y+1]+s[0][y+1]+s[1][y+1];} else if(x==NX-1){ sum=s[NX-2][y-1]+s[NX-1][y-1]+s[0][y-1]+s[NX-2][y]+s[0][y]+s[NX-2][y+1]+s[NX-1][y+1]+s[0][y+1];} else{ sum=s[x-1][y-1]+s[x][y-1]+s[x+1][y-1]+s[x-1][y]+s[x+1][y]+s[x-1][y+1]+s[x][y+1]+s[x+1][y+1];} } |
しかし、これではプログラムが長たらしくなってしまい、間違いも起こりやすい(計算速度の上でも損なのだが、プログラミング初心者は計算速度や効率について気にしないほうがよい。むしろ、プログラムが読みにくくなり間違いが起こりやすいことのほうが問題)。 ここでは、少々トリッキーだが、以下のような方法を採用しよう
盤面を縦横とも2マスずつ大きくする。つまり、配列 s の大きさを NX×NY ではなく、(NX+2)×(NY+2) とする。 これを本来の盤面の上下左右にそれぞれ1列ずつ余分のマス目がついているものとし、そこには反対端の列の状態をコピーしておく。たとえば、NX=NY=4の場合は下図のようにする。
(15) | (12) | (13) | (14) | (15) | (12) |
(3) | 0 | 1 | 2 | 3 | (0) |
(7) | 4 | 5 | 6 | 7 | (4) |
(11) | 8 | 9 | 10 | 11 | (8) |
(15) | 12 | 13 | 14 | 15 | (12) |
(3) | (0) | (1) | (2) | (3) | (0) |
#include<stdio.h> #include<stdlib.h> #define NX 30 #define NY 10 main() { int s[NX+2][NY+2], snew[NX+2][NY+2]; int rule[2][9]; int x,y,i; int step,rseed; int state,sum; /* set rule */ for(i=0;i<9;++i)rule[0][i]=rule[1][i]=0; rule[0][3]=1; rule[1][2]=rule[1][3]=1; /* input step and rseed */ scanf("%d%d",&step,&rseed); srandom(rseed); /* set random initial state */ for(y=1;y<NY+1;++y){ for(x=1;x<NX+1;++x)s[x][y]=random()%2; } /* transfer boundary */ for(x=1;x<NX+1;++x){ s[x][0] = s[x][NY]; s[x][NY+1] = s[x][1]; } for(y=0;y<NY+2;++y){ s[0][y] = s[NX][y]; s[NX+1][y] = s[1][y]; } for(i=0; i<step; ++i){ /* start one step */ for(y=1;y<NY+1;++y){ for(x=1;x<NX+1;++x){ /* one cell*/ state=s[x][y]; sum=s[x-1][y-1]+s[x-1][y]+s[x-1][y+1] +s[x][y-1]+s[x][y+1] +s[x+1][y-1]+s[x+1][y]+s[x+1][y+1]; snew[x][y]=rule[state][sum]; }} /* transfer snew[][] to s[][] */ for(y=1;y<NY+1;++y){ for(x=1;x<NX+1;++x)s[x][y] = snew[x][y]; } /* transfer boundary */ for(x=1;x<NX+1;++x){ s[x][0] = s[x][NY]; s[x][NY+1] = s[x][1]; } for(y=0;y<NY+2;++y){ s[0][y] = s[NX][y]; s[NX+1][y] = s[1][y]; } /* display one step */ printf("-----------------------------------------------\n"); for(y=1;y<NY+1;++y){ for(x=1;x<NX+1;++x){ {if(s[x][y]==1) printf("o"); else printf(" ");} } printf("\n"); } } } |
#include<stdlib.h> |
/* set random initial state */ for(y=1;y<NY+1;++y){ for(x=1;x<NX+1;++x)s[x][y]=random()%2; } |
/* transfer boundary */ for(x=1;x<NX+1;++x){ s[x][0] = s[x][NY]; s[x][NY+1] = s[x][1]; } for(y=0;y<NY+2;++y){ s[0][y] = s[NX][y]; s[NX+1][y] = s[1][y]; } |
/* one cell */ state=s[x][y]; sum=s[x-1][y-1]+s[x-1][y]+s[x-1][y+1] +s[x][y-1]+s[x][y+1] +s[x+1][y-1]+s[x+1][y]+s[x+1][y+1]; snew[x][y]=rule[state][sum]; |
/* transfer snew[][] to s[][] */ for(y=1;y<NY+1;++y){ for(x=1;x<NX+1;++x)s[x][y] = snew[x][y]; } |