第7回の目標:練習問題をこなしてプログラミングに慣れる。
セル(四角)が1列に並ぶ世界を考える。セルには生き物がいる場合(1)といない場合(0)がある。セルAとAの両隣(の計3つのセル)にどのように生き物がいるかで、次の世代のセルAに生き物がいるかどうかが決まる。
この次の世代を決めるルールを次のように表す。
| ある世代のAの左隣とAとAの右隣 | 次の世代のA |
| 111 | |
| 110 | |
| 101 | |
| 100 | |
| 011 | |
| 010 | |
| 001 | |
| 000 |
101個のセルを考え、初期値として、中央のセルは1、その他のセルは0とする。このセル達に対して、先のルールを適用して次の世代、次の世代を計算していく。
横1行が一つの世代で、その1行下に次の世代、さらにその1行下に次の世代である。60世代を図示すると以下になる。
例題1 次の世代を決めるルールを変更して、再描画してみよ。(再計算ボタンは上にある)
例:HTML
~省略~
<head>
<script src="cellAutomaton.js"></script>
</head>
~省略~
<canvas id="ID1246" width="505" height="300">
</canvas>
~省略~
例:javascript(cellAutomaton.js)
//ある世代と次の世代の対応
let rule = [["111", 0],
["110", 1],
["101", 0],
["100", 1],
["011", 1],
["010", 0],
["001", 1],
["000", 0]];
function applyRule(left_A, A, right_A) {
let i;
let oldGeneration = String(left_A) + String(A) + String(right_A);
for (i = 0; i < rule.length; i++) {
if (rule[i][0] == oldGeneration) {
return rule[i][1];
}
}
}
function nextGeneration(world) {
let newWorld = [];
for (i = 0; i <= 100; i++) {
// 世界の左端
if (i == 0) {
newWorld[i] = applyRule(0 , world[i], world[i+1]);
// 世界の右端
} else if (i == 100) {
newWorld[i] = applyRule(world[i-1], world[i], 0 );
// 世界の端でないところ
} else {
newWorld[i] = applyRule(world[i-1], world[i], world[i+1]);
}
}
return newWorld;
}
function draw1generation (world, context, offset) {
let i;
let rect_size = 5;
context.clearRect(0,offset,505,rect_size);
context.fillStyle = "rgb(0, 0, 0)";
for (i=0; i <= 100; i++) {
if (world[i] == 1) {
context.fillRect(i*rect_size, offset, rect_size, rect_size);
}
}
}
function cellAutomaton() {
let world=[];
let canvas, i;
// オートマトンの世界の初期化
for (i = 0; i <= 100; i++) {
world[i] = 0;
}
world[50] = 1; // 中央に1匹生物を置く
// 描画準備
canvas = document.getElementById('ID1246');
context = canvas.getContext('2d');
for (i = 0; i < 60; i++) {
draw1generation(world, context, i*5);
world = nextGeneration(world);
}
}
window.onload = function () {
cellAutomaton();
}
javascriptの2行目のruleが次の世代を決める。上記の例では、テキストボックスの入力値を読み取って、ルールを変更するような処理は省略されている。
applyRule関数はruleを用いて、次の世代のあるセルに生き物がいるかいないかを判定する。
nextGeneration関数はapplyRule関数を用いて、101セルある世界の次の世代を計算する。
draw1generation関数は1世代分を横1列に描画する。
cellAutomaton関数では、オートマトンの世界を宣言して初期化し、nextGeneration関数で計算しながら60世代分を描画している。
例題2 ライフゲームを実装せよ。ライフゲーム:2次元のセルオートマトンである。セルが縦横に並ぶ世界があり、セルには生き物がいる場合といない場合がある。あるセルAの周囲8マスの生き物の数により、次の世代でセルAに生き物がいるかどうかが決まる。詳しいルールは下にある。世代交替させて生き物たちが繁殖していくのを眺めるものである。
下のように動く。このサンプルではランダムに2割りくらいのセルに生き物を配置してライフゲームを開始している。