ライフゲーム
提供:kuhalaboWiki
(版間での差分)
| (1人の利用者による、間の14版が非表示) | |||
| 1行: | 1行: | ||
| + | == openFrameworksのサンプル == | ||
| + | |||
=== Cellクラスを作る=== | === Cellクラスを作る=== | ||
| 11行: | 13行: | ||
int nextState; //次回の状態 | int nextState; //次回の状態 | ||
int activeNeighbors; //近傍の生命の数 | int activeNeighbors; //近傍の生命の数 | ||
| − | ofColor color; // | + | ofColor color; //セルの色 |
ofColor gcolor; //グリッドの色 | ofColor gcolor; //グリッドの色 | ||
| 61行: | 63行: | ||
break; | break; | ||
default: | default: | ||
| − | nextState = | + | nextState = 0; |
break; | break; | ||
} | } | ||
| 115行: | 117行: | ||
//ライフゲームのセルに関する定義 | //ライフゲームのセルに関する定義 | ||
Cell **grid; | Cell **grid; | ||
| − | int rows, cols; | + | int rows, cols; //セルの個数。縦と横の2次元配列 |
| − | float cellWidth, cellHeight; | + | float cellWidth, cellHeight; //グリッドの幅と高さのピクセル数 |
| − | bool fullScreen | + | bool fullScreen; // フルスクリーンモードの切り替え |
| − | bool active; | + | bool active; // オートマトンの進行のオン・オフ |
| − | void init(int width, int height, int cellsize); | + | void init(int width, int height, int cellsize); //グリッドの初期化 |
| − | void pause(); | + | void pause(); //オートマトンの進行を止める |
| − | int getNumActiveNeighbors(int colIndex, int rowIndex); | + | int getNumActiveNeighbors(int colIndex, int rowIndex); //近傍の生命の数をカウントする |
| − | void RandomCell(); | + | void RandomCell(); //グリッド上にランダムに生命を置く |
| − | void ClearCell(); | + | void ClearCell(); //グリッド上の生命をクリアする。 |
| − | void goFullScreen(); | + | void goFullScreen(); //フルスクリーンモード切り替え |
}; | }; | ||
</pre> | </pre> | ||
| 289行: | 291行: | ||
ここまでで、ライフゲームとして、成立する。 | ここまでで、ライフゲームとして、成立する。 | ||
| − | + | ||
| + | 以下は追加の機能で典型的なパターンを定義してクラスを作る。 | ||
=== 典型的セルパターンのクラス === | === 典型的セルパターンのクラス === | ||
| 390行: | 393行: | ||
} | } | ||
</pre> | </pre> | ||
| + | |||
| + | |||
| + | === クラスの記述を洗練させた === | ||
| + | |||
| + | ;Cell.h | ||
| + | <pre> | ||
| + | #pragma once | ||
| + | #include "ofMain.h" | ||
| + | |||
| + | #define NEIGHBORS 8 | ||
| + | |||
| + | class Cell { | ||
| + | public: | ||
| + | int currState; //現在の状態 | ||
| + | int nextState; //次回の状態 | ||
| + | int liveNeighbors; //近傍の生命の数 | ||
| + | ofColor color; //生きているセルの色 | ||
| + | ofColor gcolor; //グリッドの色 | ||
| + | Cell* nCell[NEIGHBORS]; //近傍のセルへのポインタ | ||
| + | |||
| + | Cell(); | ||
| + | void update(); | ||
| + | void draw(float x, float y, float w, float h); | ||
| + | void clear(); | ||
| + | int getNumLiveNeighbors(); //近傍の生きているセルの数を得る | ||
| + | |||
| + | }; | ||
| + | </pre> | ||
| + | |||
| + | ;Cell.cpp | ||
| + | <pre> | ||
| + | #include "Cell.h" | ||
| + | |||
| + | //初期状態の設定 | ||
| + | Cell::Cell(){ | ||
| + | currState = 0; | ||
| + | nextState = 0; | ||
| + | color = ofColor::black; // cell color | ||
| + | gcolor = ofColor(150, 150, 150); // grid color | ||
| + | } | ||
| + | |||
| + | //セルの状態変異測 | ||
| + | void Cell::update(){ | ||
| + | liveNeighbors = getNumLiveNeighbors(); //近傍の生きているセルの数を得る | ||
| + | if (currState) { | ||
| + | switch(liveNeighbors){ | ||
| + | case 0: | ||
| + | case 1: | ||
| + | nextState = 0; | ||
| + | break; | ||
| + | case 2: | ||
| + | case 3: | ||
| + | nextState = 1; | ||
| + | color = ofColor::black; // live cell color | ||
| + | break; | ||
| + | case 4: | ||
| + | case 5: | ||
| + | case 6: | ||
| + | case 7: | ||
| + | case 8: | ||
| + | nextState = 0; | ||
| + | break; | ||
| + | } | ||
| + | } | ||
| + | else{ | ||
| + | switch(liveNeighbors){ | ||
| + | case 3: | ||
| + | nextState = 1; | ||
| + | color = ofColor::green; // born cell color | ||
| + | break; | ||
| + | default: | ||
| + | nextState = false; | ||
| + | break; | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | //近傍の生きているセルの数を得る | ||
| + | int Cell::getNumLiveNeighbors() { | ||
| + | int ret = 0; | ||
| + | |||
| + | for(int i=0; i<8;i++){ | ||
| + | ret += nCell[i]->currState; | ||
| + | } | ||
| + | return ret; | ||
| + | } | ||
| + | |||
| + | //セルを描画 | ||
| + | void Cell::draw(float x, float y, float w, float h){ | ||
| + | ofSetColor(gcolor); | ||
| + | ofNoFill(); | ||
| + | ofRect(x, y, w, h); | ||
| + | if (currState) { | ||
| + | ofSetColor(color); | ||
| + | ofFill(); | ||
| + | ofRect(x, y, w, h); | ||
| + | ofNoFill(); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | void Cell::clear() { | ||
| + | currState = 0; | ||
| + | nextState = 0; | ||
| + | color = ofColor::black; | ||
| + | } | ||
| + | </pre> | ||
| + | |||
| + | ;ofApp.h | ||
| + | <pre> | ||
| + | #pragma once | ||
| + | |||
| + | #include "ofMain.h" | ||
| + | #include "Cell.h" | ||
| + | #include "patterns.h" | ||
| + | |||
| + | class ofApp : public ofBaseApp { | ||
| + | |||
| + | public: | ||
| + | void setup(); | ||
| + | void update(); | ||
| + | void draw(); | ||
| + | |||
| + | void keyPressed(int key); | ||
| + | void mousePressed(int x, int y, int button); | ||
| + | |||
| + | void keyReleased(int key); | ||
| + | void mouseMoved(int x, int y ); | ||
| + | void mouseDragged(int x, int y, int button); | ||
| + | void mouseReleased(int x, int y, int button); | ||
| + | void windowResized(int w, int h); | ||
| + | void dragEvent(ofDragInfo dragInfo); | ||
| + | void gotMessage(ofMessage msg); | ||
| + | |||
| + | //ライフゲームのセルに関する宣言 | ||
| + | Cell **grid; | ||
| + | int cols, rows; //セルの個数。縦と横の2次元配列 | ||
| + | float cellWidth, cellHeight; //グリッドの幅と高さのピクセル数 | ||
| + | bool fullScreen; // フルスクリーンモードにするか否か | ||
| + | bool highlight; // 新しく誕生したセルをハイライトするか否か | ||
| + | bool active; // オートマトンの進行のオン・オフ | ||
| + | |||
| + | void init(int width, int height, int cellsize); //グリッドの初期化 | ||
| + | void pause(); //オートマトンの進行を止める | ||
| + | void RandomCell(); //グリッド上にランダムに生命を置く | ||
| + | void ClearCell(); //グリッド上の生命をクリアする。 | ||
| + | void goFullScreen();//フルスクリーンモード切り替え | ||
| + | }; | ||
| + | </pre> | ||
| + | |||
| + | ;ofApp.cpp | ||
| + | <pre> | ||
| + | #include "ofApp.h" | ||
| + | |||
| + | const int WIDTH = 800; | ||
| + | const int HEIGHT = 600; | ||
| + | const int CELLSIZE = 6; | ||
| + | const int FULLSCREEN_CELLSIZE = 8; | ||
| + | const int FRAMERATE = 30; | ||
| + | |||
| + | void ofApp::setup() { | ||
| + | fullScreen = false; | ||
| + | active = false; | ||
| + | |||
| + | ofSetFullscreen(false); | ||
| + | ofSetWindowShape(WIDTH, HEIGHT); | ||
| + | ofBackground(ofColor::white); | ||
| + | ofSetBackgroundAuto(true); | ||
| + | ofSetWindowTitle("Conway's Game of Life"); | ||
| + | ofSetFrameRate(FRAMERATE); | ||
| + | |||
| + | init(WIDTH, HEIGHT, CELLSIZE); //ライフゲームの初期化 | ||
| + | } | ||
| + | |||
| + | void ofApp::init(int width, int height, int cellSize) { | ||
| + | cols = width/cellSize; | ||
| + | rows = height/cellSize; | ||
| + | |||
| + | grid = new Cell *[cols]; | ||
| + | for (int i=0; i<cols; i++) { | ||
| + | grid[i] = new Cell[rows]; | ||
| + | } | ||
| + | // 自分の8近傍のセルのポインタをつける | ||
| + | // 剰余を使って、上下左右の通過を定義 | ||
| + | for (int i=0; i<cols; i++) { | ||
| + | for (int j=0; j<rows; j++) { | ||
| + | grid[i][j].nCell[0] = &(grid[(i-1 + cols)%cols][(j-1 + rows)%rows]); | ||
| + | grid[i][j].nCell[1] = &(grid[(i + cols)%cols][(j-1 + rows)%rows]); | ||
| + | grid[i][j].nCell[2] = &(grid[(i+1 + cols)%cols][(j-1 + rows)%rows]); | ||
| + | grid[i][j].nCell[3] = &(grid[(i-1 + cols)%cols][(j + rows)%rows]); | ||
| + | grid[i][j].nCell[4] = &(grid[(i+1 + cols)%cols][(j + rows)%rows]); | ||
| + | grid[i][j].nCell[5] = &(grid[(i-1 + cols)%cols][(j+1 + rows)%rows]); | ||
| + | grid[i][j].nCell[6] = &(grid[(i + cols)%cols][(j+1 + rows)%rows]); | ||
| + | grid[i][j].nCell[7] = &(grid[(i+1 + cols)%cols][(j+1 + rows)%rows]); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | if (width % cellSize != 0 || (height & cellSize) != 0) { | ||
| + | float ratio = width/height; | ||
| + | cellWidth = cellSize * ratio; | ||
| + | cellHeight = cellSize; | ||
| + | } else { | ||
| + | cellWidth = cellSize; | ||
| + | cellHeight = cellSize; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | void ofApp::update() { | ||
| + | if(active){ | ||
| + | // セルの現在の状態を調べる | ||
| + | for (int i=0; i<cols; i++) { | ||
| + | for (int j=0; j<rows; j++) { | ||
| + | grid[i][j].update(); | ||
| + | } | ||
| + | } | ||
| + | // セルの状態変数の更新 | ||
| + | for (int i=0; i<cols; i++) { | ||
| + | for (int j=0; j<rows; j++) { | ||
| + | grid[i][j].currState = grid[i][j].nextState; | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | // | ||
| + | void ofApp::draw() { | ||
| + | for (int i=0; i<cols; i++) { | ||
| + | for (int j=0; j<rows; j++) { | ||
| + | grid[i][j].draw(i*cellWidth, j*cellHeight, cellWidth, cellHeight); | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | void ofApp::RandomCell() { | ||
| + | for (int i=0; i<cols; i++) { | ||
| + | for (int j=0; j<rows; j++) { | ||
| + | grid[i][j].clear(); | ||
| + | grid[i][j].currState = ofRandom(2); | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | void ofApp::ClearCell() { | ||
| + | for (int i=0; i<cols; i++) { | ||
| + | for (int j=0; j<rows; j++) { | ||
| + | grid[i][j].clear(); | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | void ofApp::goFullScreen() { | ||
| + | active = false; | ||
| + | ofToggleFullscreen(); | ||
| + | fullScreen = !fullScreen; | ||
| + | delete grid; | ||
| + | if (fullScreen) { | ||
| + | init(ofGetScreenWidth(), ofGetScreenHeight(), FULLSCREEN_CELLSIZE); | ||
| + | } else { | ||
| + | init(WIDTH, HEIGHT, CELLSIZE); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | void ofApp::pause() { | ||
| + | active = false; | ||
| + | } | ||
| + | |||
| + | void ofApp::mousePressed(int x, int y, int button) { | ||
| + | int xcell = x/cellWidth; | ||
| + | int ycell = y/cellHeight; | ||
| + | grid[xcell][ycell].currState = !grid[xcell][ycell].currState; | ||
| + | } | ||
| + | |||
| + | void ofApp::keyPressed(int key) { | ||
| + | switch (key) { | ||
| + | case ' ': | ||
| + | active = !active; | ||
| + | break; | ||
| + | case 'R': | ||
| + | RandomCell(); | ||
| + | break; | ||
| + | case 'c': | ||
| + | ClearCell(); | ||
| + | break; | ||
| + | case 'f': | ||
| + | goFullScreen(); | ||
| + | break; | ||
| + | case 'g': | ||
| + | patterns::gliderGun(grid, 2, 2); | ||
| + | break; | ||
| + | case 'p': | ||
| + | patterns::pufferTrain(grid, cols/2 - 10, rows - 30); | ||
| + | break; | ||
| + | default: | ||
| + | break; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | //-------------------------------------------------------------- | ||
| + | void ofApp::keyReleased(int key){ | ||
| + | |||
| + | } | ||
| + | //-------------------------------------------------------------- | ||
| + | void ofApp::mouseMoved(int x, int y ){ | ||
| + | |||
| + | } | ||
| + | //-------------------------------------------------------------- | ||
| + | void ofApp::mouseDragged(int x, int y, int button){ | ||
| + | |||
| + | } | ||
| + | //-------------------------------------------------------------- | ||
| + | void ofApp::mouseReleased(int x, int y, int button){ | ||
| + | |||
| + | } | ||
| + | //-------------------------------------------------------------- | ||
| + | void ofApp::windowResized(int w, int h){ | ||
| + | |||
| + | } | ||
| + | //-------------------------------------------------------------- | ||
| + | void ofApp::gotMessage(ofMessage msg){ | ||
| + | |||
| + | } | ||
| + | //-------------------------------------------------------------- | ||
| + | void ofApp::dragEvent(ofDragInfo dragInfo){ | ||
| + | |||
| + | } | ||
| + | </pre> | ||
| + | |||
| + | == 参考 == | ||
| + | [[ジェネラティブアート論]] | ||
| + | |||
| + | [[Category:授業]] | ||
2020年10月31日 (土) 00:21時点における最新版
目次 |
[編集] openFrameworksのサンプル
[編集] Cellクラスを作る
- Cell.h
#pragma once
#include "ofMain.h"
class Cell {
public:
int currState; //現在の状態
int nextState; //次回の状態
int activeNeighbors; //近傍の生命の数
ofColor color; //セルの色
ofColor gcolor; //グリッドの色
Cell();
void update();
void draw(float x, float y, float w, float h);
void clear();
};
- Cell.cpp
#include "Cell.h"
//初期状態の設定
Cell::Cell(){
currState = 0;
nextState = 0;
color = ofColor::black; // cell color
gcolor = ofColor(150, 150, 150); // grid color
}
//セルの状態変異測
void Cell::update(){
if (currState) {
switch(activeNeighbors){
case 0:
case 1:
nextState = 0;
break;
case 2:
case 3:
nextState = 1;
color = ofColor::black; // live cell color
break;
case 4:
case 5:
case 6:
case 7:
case 8:
nextState = 0;
break;
}
}
else{
switch(activeNeighbors){
case 3:
nextState = 1;
color = ofColor::green; // born cell color
break;
default:
nextState = 0;
break;
}
}
}
//セルを描画
void Cell::draw(float x, float y, float w, float h){
ofSetColor(gcolor);
ofNoFill();
ofRect(x, y, w, h);
if (currState) {
ofSetColor(color);
ofFill();
ofRect(x, y, w, h);
ofNoFill();
}
}
void Cell::clear() {
currState = 0;
nextState = 0;
color = ofColor::black;
}
[編集] 主プログラム
- ofApp.h
#pragma once
#include "ofMain.h"
#include "Cell.h"
class ofApp : public ofBaseApp {
public:
void setup();
void update();
void draw();
void keyPressed(int key);
void mousePressed(int x, int y, int button);
void keyReleased(int key);
void mouseMoved(int x, int y );
void mouseDragged(int x, int y, int button);
void mouseReleased(int x, int y, int button);
void windowResized(int w, int h);
void dragEvent(ofDragInfo dragInfo);
void gotMessage(ofMessage msg);
//ライフゲームのセルに関する定義
Cell **grid;
int rows, cols; //セルの個数。縦と横の2次元配列
float cellWidth, cellHeight; //グリッドの幅と高さのピクセル数
bool fullScreen; // フルスクリーンモードの切り替え
bool active; // オートマトンの進行のオン・オフ
void init(int width, int height, int cellsize); //グリッドの初期化
void pause(); //オートマトンの進行を止める
int getNumActiveNeighbors(int colIndex, int rowIndex); //近傍の生命の数をカウントする
void RandomCell(); //グリッド上にランダムに生命を置く
void ClearCell(); //グリッド上の生命をクリアする。
void goFullScreen(); //フルスクリーンモード切り替え
};
- ofApp.cpp
#include "ofApp.h"
const int WIDTH = 800;
const int HEIGHT = 600;
const int CELLSIZE = 6;
const int FULLSCREEN_CELLSIZE = 8;
const int FRAMERATE = 30;
void ofApp::setup() {
fullScreen = false;
active = false;
ofSetFullscreen(false);
ofSetWindowShape(WIDTH, HEIGHT);
ofBackground(ofColor::white);
ofSetBackgroundAuto(true);
ofSetWindowTitle("Conway's Game of Life");
ofSetFrameRate(FRAMERATE);
init(WIDTH, HEIGHT, CELLSIZE);
}
void ofApp::init(int width, int height, int cellSize) {
cols = width/cellSize;
rows = height/cellSize;
grid = new Cell *[cols];
for (int i=0; i<cols; i++) {
grid[i] = new Cell[rows];
for (int j=0; j<rows; j++) {
Cell *thisCell = &grid[i][j];
}
}
if (width % cellSize != 0 || (height & cellSize) != 0) {
float ratio = width/height;
cellWidth = cellSize * ratio;
cellHeight = cellSize;
} else {
cellWidth = cellSize;
cellHeight = cellSize;
}
}
void ofApp::update() {
if(active){
// get active neighbors for each cell
for (int i=0; i<cols; i++) {
for (int j=0; j<rows; j++) {
grid[i][j].activeNeighbors = getNumActiveNeighbors(i, j);
grid[i][j].update();
}
}
for (int i=0; i<cols; i++) {
for (int j=0; j<rows; j++) {
grid[i][j].currState = grid[i][j].nextState;
}
}
}
}
void ofApp::draw() {
for (int i=0; i<cols; i++) {
for (int j=0; j<rows; j++) {
grid[i][j].draw(i*cellWidth, j*cellHeight, cellWidth, cellHeight);
}
}
}
void ofApp::RandomCell() {
for (int i=0; i<cols; i++) {
for (int j=0; j<rows; j++) {
grid[i][j].clear();
grid[i][j].currState = ofRandom(2);
}
}
}
void ofApp::ClearCell() {
for (int i=0; i<cols; i++) {
for (int j=0; j<rows; j++) {
grid[i][j].clear();
}
}
}
int ofApp::getNumActiveNeighbors(int colIndex, int rowIndex) {
int ret = 0;
int prevCol = (colIndex - 1 + cols) % cols;
int nextCol = (colIndex + 1 + cols) % cols;
int prevRow = (rowIndex - 1 + rows) % rows;
int nextRow = (rowIndex + 1 + rows) % rows;
ret += grid[prevCol][prevRow].currState;
ret += grid[prevCol][rowIndex].currState;
ret += grid[prevCol][nextRow].currState;
ret += grid[colIndex][prevRow].currState;
ret += grid[colIndex][nextRow].currState;
ret += grid[nextCol][prevRow].currState;
ret += grid[nextCol][rowIndex].currState;
ret += grid[nextCol][nextRow].currState;
return ret;
}
void ofApp::goFullScreen() {
active = false;
ofToggleFullscreen();
fullScreen = !fullScreen;
if (fullScreen) {
init(ofGetScreenWidth(), ofGetScreenHeight(), FULLSCREEN_CELLSIZE);
} else {
init(WIDTH, HEIGHT, CELLSIZE);
}
}
void ofApp::pause() {
active = false;
}
void ofApp::mousePressed(int x, int y, int button) {
int xcell = x/cellWidth;
int ycell = y/cellHeight;
grid[xcell][ycell].currState = !grid[xcell][ycell].currState;
}
void ofApp::keyPressed(int key) {
switch (key) {
case ' ':
active = !active;
break;
case 'R':
RandomCell();
break;
case 'c':
ClearCell();
break;
case 'f':
goFullScreen();
break;
case 'g':
// pause();
patterns::gliderGun(grid, 2, 2);
break;
case 'p':
// pause();
patterns::pufferTrain(grid, cols/2 - 10, rows - 30);
break;
default:
break;
}
}
ここまでで、ライフゲームとして、成立する。
以下は追加の機能で典型的なパターンを定義してクラスを作る。
[編集] 典型的セルパターンのクラス
- グライダー砲とパッファートレインのパターン定義を作る。
- ofApp.hの先頭辺りにに以下を追加すること。
#include "patterns.h"
- patterns.h
#pragma once
#include "ofApp.h"
class patterns {
public:
static void gliderGun(Cell **grid, int startPosX, int startPosY);
static void pufferTrain(Cell **grid, int startPosX, int startPosY);
};
patterns.cpp
#include "patterns.h"
void patterns::gliderGun(Cell **grid, int startPosX, int startPosY) {
// left box
grid[startPosX+1][startPosY+5].currState = 1;
grid[startPosX+1][startPosY+6].currState = 1;
grid[startPosX+2][startPosY+5].currState = 1;
grid[startPosX+2][startPosY+6].currState = 1;
// left middle of gun
grid[startPosX+11][startPosY+5].currState = 1;
grid[startPosX+11][startPosY+6].currState = 1;
grid[startPosX+11][startPosY+7].currState = 1;
grid[startPosX+12][startPosY+4].currState = 1;
grid[startPosX+12][startPosY+8].currState = 1;
grid[startPosX+13][startPosY+3].currState = 1;
grid[startPosX+13][startPosY+9].currState = 1;
grid[startPosX+14][startPosY+3].currState = 1;
grid[startPosX+14][startPosY+9].currState = 1;
grid[startPosX+15][startPosY+6].currState = 1;
grid[startPosX+16][startPosY+4].currState = 1;
grid[startPosX+16][startPosY+8].currState = 1;
grid[startPosX+17][startPosY+5].currState = 1;
grid[startPosX+17][startPosY+6].currState = 1;
grid[startPosX+17][startPosY+7].currState = 1;
grid[startPosX+18][startPosY+6].currState = 1;
// right middle of gun
grid[startPosX+21][startPosY+3].currState = 1;
grid[startPosX+21][startPosY+4].currState = 1;
grid[startPosX+21][startPosY+5].currState = 1;
grid[startPosX+22][startPosY+3].currState = 1;
grid[startPosX+22][startPosY+4].currState = 1;
grid[startPosX+22][startPosY+5].currState = 1;
grid[startPosX+23][startPosY+2].currState = 1;
grid[startPosX+23][startPosY+6].currState = 1;
grid[startPosX+25][startPosY+1].currState = 1;
grid[startPosX+25][startPosY+2].currState = 1;
grid[startPosX+25][startPosY+6].currState = 1;
grid[startPosX+25][startPosY+7].currState = 1;
// right block
grid[startPosX+35][startPosY+3].currState = 1;
grid[startPosX+35][startPosY+4].currState = 1;
grid[startPosX+36][startPosY+3].currState = 1;
grid[startPosX+36][startPosY+4].currState = 1;
}
void patterns::pufferTrain(Cell **grid, int startPosX, int startPosY) {
grid[startPosX+1][startPosY+2].currState = 1;
grid[startPosX+2][startPosY+1].currState = 1;
grid[startPosX+3][startPosY+1].currState = 1;
grid[startPosX+3][startPosY+5].currState = 1;
grid[startPosX+4][startPosY+1].currState = 1;
grid[startPosX+4][startPosY+2].currState = 1;
grid[startPosX+4][startPosY+3].currState = 1;
grid[startPosX+4][startPosY+4].currState = 1;
grid[startPosX+8][startPosY+5].currState = 1;
grid[startPosX+9][startPosY+3].currState = 1;
grid[startPosX+9][startPosY+4].currState = 1;
grid[startPosX+10][startPosY+3].currState = 1;
grid[startPosX+11][startPosY+3].currState = 1;
grid[startPosX+12][startPosY+4].currState = 1;
grid[startPosX+15][startPosY+2].currState = 1;
grid[startPosX+16][startPosY+1].currState = 1;
grid[startPosX+17][startPosY+1].currState = 1;
grid[startPosX+17][startPosY+5].currState = 1;
grid[startPosX+18][startPosY+1].currState = 1;
grid[startPosX+18][startPosY+2].currState = 1;
grid[startPosX+18][startPosY+3].currState = 1;
grid[startPosX+18][startPosY+4].currState = 1;
}
[編集] クラスの記述を洗練させた
- Cell.h
#pragma once
#include "ofMain.h"
#define NEIGHBORS 8
class Cell {
public:
int currState; //現在の状態
int nextState; //次回の状態
int liveNeighbors; //近傍の生命の数
ofColor color; //生きているセルの色
ofColor gcolor; //グリッドの色
Cell* nCell[NEIGHBORS]; //近傍のセルへのポインタ
Cell();
void update();
void draw(float x, float y, float w, float h);
void clear();
int getNumLiveNeighbors(); //近傍の生きているセルの数を得る
};
- Cell.cpp
#include "Cell.h"
//初期状態の設定
Cell::Cell(){
currState = 0;
nextState = 0;
color = ofColor::black; // cell color
gcolor = ofColor(150, 150, 150); // grid color
}
//セルの状態変異測
void Cell::update(){
liveNeighbors = getNumLiveNeighbors(); //近傍の生きているセルの数を得る
if (currState) {
switch(liveNeighbors){
case 0:
case 1:
nextState = 0;
break;
case 2:
case 3:
nextState = 1;
color = ofColor::black; // live cell color
break;
case 4:
case 5:
case 6:
case 7:
case 8:
nextState = 0;
break;
}
}
else{
switch(liveNeighbors){
case 3:
nextState = 1;
color = ofColor::green; // born cell color
break;
default:
nextState = false;
break;
}
}
}
//近傍の生きているセルの数を得る
int Cell::getNumLiveNeighbors() {
int ret = 0;
for(int i=0; i<8;i++){
ret += nCell[i]->currState;
}
return ret;
}
//セルを描画
void Cell::draw(float x, float y, float w, float h){
ofSetColor(gcolor);
ofNoFill();
ofRect(x, y, w, h);
if (currState) {
ofSetColor(color);
ofFill();
ofRect(x, y, w, h);
ofNoFill();
}
}
void Cell::clear() {
currState = 0;
nextState = 0;
color = ofColor::black;
}
- ofApp.h
#pragma once
#include "ofMain.h"
#include "Cell.h"
#include "patterns.h"
class ofApp : public ofBaseApp {
public:
void setup();
void update();
void draw();
void keyPressed(int key);
void mousePressed(int x, int y, int button);
void keyReleased(int key);
void mouseMoved(int x, int y );
void mouseDragged(int x, int y, int button);
void mouseReleased(int x, int y, int button);
void windowResized(int w, int h);
void dragEvent(ofDragInfo dragInfo);
void gotMessage(ofMessage msg);
//ライフゲームのセルに関する宣言
Cell **grid;
int cols, rows; //セルの個数。縦と横の2次元配列
float cellWidth, cellHeight; //グリッドの幅と高さのピクセル数
bool fullScreen; // フルスクリーンモードにするか否か
bool highlight; // 新しく誕生したセルをハイライトするか否か
bool active; // オートマトンの進行のオン・オフ
void init(int width, int height, int cellsize); //グリッドの初期化
void pause(); //オートマトンの進行を止める
void RandomCell(); //グリッド上にランダムに生命を置く
void ClearCell(); //グリッド上の生命をクリアする。
void goFullScreen();//フルスクリーンモード切り替え
};
- ofApp.cpp
#include "ofApp.h"
const int WIDTH = 800;
const int HEIGHT = 600;
const int CELLSIZE = 6;
const int FULLSCREEN_CELLSIZE = 8;
const int FRAMERATE = 30;
void ofApp::setup() {
fullScreen = false;
active = false;
ofSetFullscreen(false);
ofSetWindowShape(WIDTH, HEIGHT);
ofBackground(ofColor::white);
ofSetBackgroundAuto(true);
ofSetWindowTitle("Conway's Game of Life");
ofSetFrameRate(FRAMERATE);
init(WIDTH, HEIGHT, CELLSIZE); //ライフゲームの初期化
}
void ofApp::init(int width, int height, int cellSize) {
cols = width/cellSize;
rows = height/cellSize;
grid = new Cell *[cols];
for (int i=0; i<cols; i++) {
grid[i] = new Cell[rows];
}
// 自分の8近傍のセルのポインタをつける
// 剰余を使って、上下左右の通過を定義
for (int i=0; i<cols; i++) {
for (int j=0; j<rows; j++) {
grid[i][j].nCell[0] = &(grid[(i-1 + cols)%cols][(j-1 + rows)%rows]);
grid[i][j].nCell[1] = &(grid[(i + cols)%cols][(j-1 + rows)%rows]);
grid[i][j].nCell[2] = &(grid[(i+1 + cols)%cols][(j-1 + rows)%rows]);
grid[i][j].nCell[3] = &(grid[(i-1 + cols)%cols][(j + rows)%rows]);
grid[i][j].nCell[4] = &(grid[(i+1 + cols)%cols][(j + rows)%rows]);
grid[i][j].nCell[5] = &(grid[(i-1 + cols)%cols][(j+1 + rows)%rows]);
grid[i][j].nCell[6] = &(grid[(i + cols)%cols][(j+1 + rows)%rows]);
grid[i][j].nCell[7] = &(grid[(i+1 + cols)%cols][(j+1 + rows)%rows]);
}
}
if (width % cellSize != 0 || (height & cellSize) != 0) {
float ratio = width/height;
cellWidth = cellSize * ratio;
cellHeight = cellSize;
} else {
cellWidth = cellSize;
cellHeight = cellSize;
}
}
void ofApp::update() {
if(active){
// セルの現在の状態を調べる
for (int i=0; i<cols; i++) {
for (int j=0; j<rows; j++) {
grid[i][j].update();
}
}
// セルの状態変数の更新
for (int i=0; i<cols; i++) {
for (int j=0; j<rows; j++) {
grid[i][j].currState = grid[i][j].nextState;
}
}
}
}
//
void ofApp::draw() {
for (int i=0; i<cols; i++) {
for (int j=0; j<rows; j++) {
grid[i][j].draw(i*cellWidth, j*cellHeight, cellWidth, cellHeight);
}
}
}
void ofApp::RandomCell() {
for (int i=0; i<cols; i++) {
for (int j=0; j<rows; j++) {
grid[i][j].clear();
grid[i][j].currState = ofRandom(2);
}
}
}
void ofApp::ClearCell() {
for (int i=0; i<cols; i++) {
for (int j=0; j<rows; j++) {
grid[i][j].clear();
}
}
}
void ofApp::goFullScreen() {
active = false;
ofToggleFullscreen();
fullScreen = !fullScreen;
delete grid;
if (fullScreen) {
init(ofGetScreenWidth(), ofGetScreenHeight(), FULLSCREEN_CELLSIZE);
} else {
init(WIDTH, HEIGHT, CELLSIZE);
}
}
void ofApp::pause() {
active = false;
}
void ofApp::mousePressed(int x, int y, int button) {
int xcell = x/cellWidth;
int ycell = y/cellHeight;
grid[xcell][ycell].currState = !grid[xcell][ycell].currState;
}
void ofApp::keyPressed(int key) {
switch (key) {
case ' ':
active = !active;
break;
case 'R':
RandomCell();
break;
case 'c':
ClearCell();
break;
case 'f':
goFullScreen();
break;
case 'g':
patterns::gliderGun(grid, 2, 2);
break;
case 'p':
patterns::pufferTrain(grid, cols/2 - 10, rows - 30);
break;
default:
break;
}
}
//--------------------------------------------------------------
void ofApp::keyReleased(int key){
}
//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){
}
//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){
}
//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){
}
//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){
}
//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){
}
//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){
}