Created
April 16, 2017 19:45
-
-
Save tasuten/e0408675c7de8b3bd7bd6a6b82553fb2 to your computer and use it in GitHub Desktop.
Game of Life by Processing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
int winWidth = 600; // ウィンドウの横幅 | |
int winHeight = 400; // ウィンドウの縦幅 | |
static final int CELL_SIZE = 15; // セルの大きさ | |
int start = 2; // 初期盤面のパターン番号 | |
int nCellX = winWidth / CELL_SIZE; // 横(x)方向のセルの個数 | |
int nCellY = winHeight / CELL_SIZE; // 縦(y)方向のセルの個数 | |
// 盤面(field)の状況 | |
// 各セルはALIVEが生存、DEADが死亡を表す | |
// 上下左右に1セルの外堀がある | |
// 全てのセルはまず死亡(DEAD)で初期化される | |
boolean[][] currentField = new boolean[nCellX+2][nCellY+2]; | |
// 計算のために使われる。次の盤面 | |
boolean[][] nextField = new boolean[nCellX+2][nCellY+2]; | |
// true, falseでは分かりにくいので適当な別名を | |
static final boolean ALIVE = true; | |
static final boolean DEAD = false; | |
// 動作モード | |
// 0 .. アニメーションモード。フィールドを計算して更新していく | |
// 1 .. 編集モード。フィールドをマウスクリックで編集 | |
int mode = 0; | |
static final int ANIMATION_MODE = 0; | |
static final int EDIT_MODE = 1; | |
void setup(){ | |
// ウィンドウのサイズをCELL_SIZEの倍数にfloorする | |
if(winWidth % CELL_SIZE != 0) { | |
winWidth = int(winWidth / CELL_SIZE) * CELL_SIZE; | |
} | |
if(winHeight % CELL_SIZE != 0) { | |
winHeight = int(winHeight / CELL_SIZE) * CELL_SIZE; | |
} | |
size(winWidth, winHeight); // ウィンドウを開く | |
noStroke(); | |
smooth(); | |
background(255, 255, 255); // 背景は白 | |
stroke(0, 0, 0); // 格子の線は黒 | |
fill(0, 0, 0); // セルも黒 | |
frameRate(10); // 1秒あたりのフレーム数 | |
// ここで初期盤面を設定 | |
switch(start) { | |
case 0: | |
initFieldRandom(); | |
break; | |
case 1: | |
glider(1, 1); | |
glider(20, 1); | |
break; | |
case 2: | |
gliderGun(1, 1); | |
break; | |
default: | |
// nop | |
// currentFieldは全てDEADで初期化されるので全てDEADのField | |
break; | |
} | |
grid(); | |
drawFiled(); | |
// mode = EDIT_MODE; | |
} | |
// これがループする | |
void draw(){ | |
if (mode == ANIMATION_MODE) { | |
// 次世代を計算してnextFieldに格納し | |
nextGeneration(); | |
// その内容をcurrentFieldにコピーして | |
dupNext2Current(); | |
// 画面に表示 | |
clear(); | |
grid(); | |
drawFiled(); | |
} | |
} | |
// 画面をクリア | |
void clear() { | |
background(255, 255, 255); // 白 | |
} | |
// グリッドを書く | |
void grid(){ | |
// 縦罫線 | |
for(int x = 1; x < nCellX; x++) { | |
line(x * CELL_SIZE, 0, x * CELL_SIZE, winHeight); | |
} | |
// 横罫線 | |
for(int y = 1; y < nCellY; y++) { | |
line(0, y * CELL_SIZE, winWidth, y * CELL_SIZE); | |
} | |
} | |
// currentFieldを描画 | |
void drawFiled() { | |
// 描画範囲は外堀を除いたcurrentField[1..nCellX][1..nCellY] | |
for(int x = 1; x <= nCellX; x++){ | |
for(int y = 1; y <= nCellY; y++){ | |
if (currentField[x][y] == ALIVE) { // 生きてるセルを色付け | |
rect( (x-1) * CELL_SIZE, (y-1) * CELL_SIZE, CELL_SIZE, CELL_SIZE); | |
}else { // 死んだセル | |
// nop | |
} | |
} | |
} | |
} | |
// nextFieldの内容をcurrentFieldにコピーするだけ | |
void dupNext2Current() { | |
for(int x = 0; x <= nCellX+1; x++){ | |
for(int y = 0; y <= nCellY+1; y++){ | |
currentField[x][y] = nextField[x][y]; | |
} | |
} | |
} | |
// currentFieldを元に次世代のフィールドを計算してnextFieldに格納 | |
void nextGeneration() { | |
for (int x = 1; x <= nCellX; x++){ | |
for(int y = 1; y <= nCellY; y++){ | |
int count = countSurround(x, y); | |
if (currentField[x][y] == DEAD){ // セルが死んでる場合 | |
if (count == 3) { // 周りがちょうど3つ生存で | |
nextField[x][y] = ALIVE; // 誕生 | |
} | |
} else { // セルが生きてる場合(ALIVE) | |
if(count <= 1 || 4 <= count) { // 過疎、過密 | |
nextField[x][y] = DEAD; // 死ぬ | |
} else { // 2つか3つならば生存のまま | |
nextField[x][y] = ALIVE; | |
} | |
} | |
} | |
} | |
} | |
// currentField[x][y]に | |
// 隣接しているセルの内生きているセルの数を数え返す | |
int countSurround(int x, int y) { | |
int count = 0; | |
if (currentField[x-1][y-1] == ALIVE) count++; // 左上 | |
if (currentField[x ][y-1] == ALIVE) count++; // 直上 | |
if (currentField[x+1][y-1] == ALIVE) count++; // 右上 | |
if (currentField[x-1][y ] == ALIVE) count++; // 真左 | |
if (currentField[x+1][y ] == ALIVE) count++; // 真右 | |
if (currentField[x-1][y+1] == ALIVE) count++; // 左下 | |
if (currentField[x ][y+1] == ALIVE) count++; // 真下 | |
if (currentField[x+1][y+1] == ALIVE) count++; // 右下 | |
return count; | |
} | |
// スペースでモード切り替え | |
void keyPressed(){ | |
if (key == ' ') { | |
if (mode == ANIMATION_MODE) { | |
mode = EDIT_MODE; | |
} else if (mode == EDIT_MODE) { | |
mode= ANIMATION_MODE; | |
} | |
} else if (key == 'q') { | |
exit(); | |
} | |
} | |
// マウスクリックしたセルの生死を切り替え | |
void mouseClicked() { | |
if (mode == EDIT_MODE) { | |
int cellX = int(mouseX/CELL_SIZE+1); | |
int cellY = int(mouseY/CELL_SIZE+1); | |
if (currentField[cellX][cellY] == ALIVE) { | |
currentField[cellX][cellY] = DEAD; | |
nextField[cellX][cellY] = DEAD; | |
fill(255, 255, 255); | |
rect( (cellX-1) * CELL_SIZE, (cellY-1) * CELL_SIZE, CELL_SIZE, CELL_SIZE); | |
fill(0, 0, 0); | |
} else { | |
currentField[cellX][cellY] = ALIVE; | |
nextField[cellX][cellY] = ALIVE; | |
rect( (cellX-1) * CELL_SIZE, (cellY-1) * CELL_SIZE, CELL_SIZE, CELL_SIZE); | |
} | |
} | |
} | |
// フィールド(currentField)をランダムに初期化 | |
void initFieldRandom() { | |
for (int x = 1; x <= nCellX; x++){ | |
for(int y = 1; y <= nCellY; y++){ | |
int rndInt = round(random(0, 1)); | |
currentField[x][y] = (rndInt == 0) ? DEAD : ALIVE; | |
} | |
} | |
} | |
// (x, y)を左上としてcurrentFieldに右下向きのグライダーを生成 | |
void glider(int x, int y) { | |
// x* | |
// * | |
// *** | |
// xが(x, y) | |
currentField[x][y+1] = ALIVE; | |
currentField[x+1][y+2] = ALIVE; | |
currentField[x+2][y] = ALIVE; | |
currentField[x+2][y+1] = ALIVE; | |
currentField[x+2][y+2] = ALIVE; | |
} | |
// x, yを一番左上としてグライダーガンをcurrentFieldに生成 | |
void gliderGun(int x, int y) { | |
currentField[x+1][y+6] = ALIVE; | |
currentField[x+1][y+7] = ALIVE; | |
currentField[x+2][y+6] = ALIVE; | |
currentField[x+2][y+7] = ALIVE; | |
currentField[x+11][y+6] = ALIVE; | |
currentField[x+11][y+7] = ALIVE; | |
currentField[x+11][y+8] = ALIVE; | |
currentField[x+12][y+5] = ALIVE; | |
currentField[x+12][y+9] = ALIVE; | |
currentField[x+13][y+4] = ALIVE; | |
currentField[x+13][y+10] = ALIVE; | |
currentField[x+14][y+4] = ALIVE; | |
currentField[x+14][y+10] = ALIVE; | |
currentField[x+15][y+7] = ALIVE; | |
currentField[x+16][y+5] = ALIVE; | |
currentField[x+16][y+9] = ALIVE; | |
currentField[x+17][y+6] = ALIVE; | |
currentField[x+17][y+7] = ALIVE; | |
currentField[x+17][y+8] = ALIVE; | |
currentField[x+18][y+7] = ALIVE; | |
currentField[x+21][y+4] = ALIVE; | |
currentField[x+21][y+5] = ALIVE; | |
currentField[x+21][y+6] = ALIVE; | |
currentField[x+22][y+4] = ALIVE; | |
currentField[x+22][y+5] = ALIVE; | |
currentField[x+22][y+6] = ALIVE; | |
currentField[x+23][y+3] = ALIVE; | |
currentField[x+23][y+7] = ALIVE; | |
currentField[x+25][y+2] = ALIVE; | |
currentField[x+25][y+3] = ALIVE; | |
currentField[x+25][y+7] = ALIVE; | |
currentField[x+25][y+8] = ALIVE; | |
currentField[x+35][y+4] = ALIVE; | |
currentField[x+35][y+5] = ALIVE; | |
currentField[x+36][y+4] = ALIVE; | |
currentField[x+36][y+5] = ALIVE; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment