Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@tasuten
Created April 16, 2017 19:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tasuten/e0408675c7de8b3bd7bd6a6b82553fb2 to your computer and use it in GitHub Desktop.
Save tasuten/e0408675c7de8b3bd7bd6a6b82553fb2 to your computer and use it in GitHub Desktop.
Game of Life by Processing
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