モデルの詳細は「樹枝状析出」のコンテンツを参照。ここでは、具体的なプログラムを考える。 粒子は一番上の段のランダムな位置に出現し、ランダムウォークで動いてゆく。成長の「基盤」として、一番下の段には初めから粒子を敷き詰めておけば、成長の規則は「すでに静止している粒子に触れたら、そこで停止」だけでよい。”触れる”範囲は周囲8セルとする(上下左右の4セルだけにしてもよいが、その場合は少々工夫が必要)。
以下はプログラム例である
#include<stdio.h> #include<eggx.h> #include<stdlib.h> #define NX 100 #define NY 50 #define EDGE 4 main() { int s[NX][NY]; int x, y; int i,j,k,l; int particle,step,rseed; int win; /* preparation for graphics */ win=gopen(NX*EDGE,NY*EDGE); window(win,0,0,NX-1,NY-1); gsetbgcolor(win,"white"); newcolor(win,"blue"); layer(win,0,1); /* set initial state */ for(i=0; i<NX; ++i){ for(j=1; j<NY; ++j){ s[i][j] = 0; }} for(i=0; i<NX; ++i){ s[i][0] =1;} /* input step and rseed */ scanf("%d%d",&particle,&rseed); srandom(rseed); /* display initial state */ gclr(win); for(i=0; i<NX-1; ++i){ for(j=0; j<NY-1; ++j){ if(s[i][j] == 1)fillrect(win,i,j,1,1); }} copylayer(win,1,0); for(k=0; k<particle; ++k){ /* start one particle */ x = random()%NX; y = NY-2; for(;;){ /* start one step */ x += (random()%3-1); x = (x+NX)%NX; y += (random()%3-1); if(y == NY-1) { break; } else if( s[(x+NX-1)%NX][y+1] == 1 || s[x][y+1] == 1 || s[(x+NX+1)%NX][y+1] ==1 || s[(x+NX-1)%NX][y]==1 || s[(x+NX+1)%NX][y] ==1 || s[(x+NX-1)%NX][y-1] == 1 || s[x][y-1] == 1 || s[(x+NX+1)%NX][y-1] ==1 ) {s[x][y] = 1; break;} /* display one particle */ gclr(win); for(i=0; i<NX-1; ++i){ for(j=0; j<NY-1; ++j){ if(s[i][j] == 1)fillrect(win,i,j,1,1); }} if(y != NY-1)fillrect(win,x,y,1,1); copylayer(win,1,0); msleep(1); /* end of one step */ } } } |
特に画面表示はあまり効率のよいプログラムになっていないが、これで動くのでよいことにする。また、このように1ステップごとに表示していると計算の進行が非常に遅くなる。成長の様子を加速して見たければ、粒子が静止するまで画面表示しないことにしたほうがよい。
粒子のスタート位置を最上段ではなくその一段下にしてあるのは、プログラム上のテクニカルな理由で、こうしないとs[x][y+1]が存在しないセルを指す場合が生じてしまう。なお、粒子が最上段に上がってしまったら、その時点でその粒子は捨てて、次の粒子に移るようにしている(したがって、多くの粒子が無駄になる)。
x = (x+NX)%NX; |
s[(x+NX-1)%NX][y+1] == 1 |
for(;;){ |
上のプログラムは粒子が完全にランダムウォークするので、なかなか着地してくれない。横にはランダムウォークするが縦には1ステップにつき1段ずつ落ちる(ランダムではない)という別のモデルを考えることもできるだろう。その場合、移動部分は
x += (random()%3-1); x = (x+NX)%NX; y -= 1; |