/************************************************************** * ライフ・ゲーム (3)継承を使う 境界を周期的にする * * LIFE03 ver 1.0 * * Copyright(c) 1999 Yamada,K (1999.03.07) * * * * スペースキーで終了する * *************************************************************** */ #include <iostream.h> #include <time.h> #include "glibw32.h"// グラフィックス・クラスライブラリ GLIBW32 const int N = 40; // 正方形の升目の数 enum state{ DYING, LIVING, STATES}; class life; // 前方宣言 typedef life* field[N][N]; // 生命体の抽象クラス class life{ public: virtual state getstate() const = 0; //状態識別 virtual life* next(field) = 0; //次の状態 virtual void draw(GRAPH *) = 0; //描画 protected: int row, col; // 位置 void count(field w, int sum[]) const; }; // 境界を周期的に扱う int cyclic(const int i) { if(i > N-1) return (i - N); else if(i < 0) return (N + i); else return i; } // 隣接した生命体の状態をカウント void life::count(field w, int sum[]) const { sum[DYING] = sum[LIVING] = 0; for(int i = -1; i <= 1; ++i) for(int j = -1; j <= 1; ++j) sum[w[cyclic(row + i)][cyclic(col +j)]->getstate()]++; sum[w[row][col]->getstate()]--; // 自分の状態は数えない } // 生きている生命体のクラス class living : public life{ public: living(int r, int c) { row = r; col = c; } state getstate() const { return LIVING; } life* next(field); void draw(GRAPH *); }; // 死んでいる生命体のクラス class dying : public life{ public: dying(int r, int c) { row = r; col = c; } state getstate() const { return DYING; } life* next(field); void draw(GRAPH *) { } }; // 次の世代の状態を決定する life* living::next(field w) { int sum[STATES]; count(w, sum); if(sum[LIVING] == 2 || sum[LIVING] == 3) return (new living(row, col)); else return (new dying(row, col)); } // 次の世代の状態を決定する life* dying::next(field w) { int sum[STATES]; count(w, sum); if(sum[LIVING] == 3) return (new living(row, col)); else return (new dying(row, col)); } // 描画 void living::draw(GRAPH *g) { g->frectangle(row*10+3,col*10+3,row*10+7,col*10+7, WHITE); } // オブジェクトの生成 void init(field w) { for(int i = 0; i < N; ++i) for(int j = 0; j < N; ++j) w[i][j] = new dying(i,j); } // 生命体の初期設定 void create(field w, int i, int j) { // 生命体の生息パターン delete(w[i][j+1]); w[i][j+1] = new living(i,j+1); delete(w[i-1][j]); w[i-1][j] = new living(i-1,j); delete(w[i][j]); w[i][j] = new living(i,j); delete(w[i+1][j]); w[i+1][j] = new living(i+1,j); delete(w[i+1][j-1]); w[i+1][j-1] = new living(i+1,j-1); } // 世代交代 void update(field w) { field w_temp; // 一時的なポインタ int i,j; // 次の状態を一時的に記憶 for(i = 0; i < N; ++i) for(j = 0; j < N; ++j) w_temp[i][j] = w[i][j]->next(w); for(i = 0; i < N; ++i) for(j = 0; j < N; ++j){ delete(w[i][j]); // 古い状態を削除 w[i][j] = w_temp[i][j]; // 新しい状態をコピー } } // オブジェクトの削除 void dele(field w) { for(int i = 0; i < N; ++i) for(int j = 0; j < N; ++j) delete (w[i][j]); } // 描画関数 void draw(GRAPH *g, field w) { g->cls(); for(int i = 0; i < N; ++i) for(int j = 0; j < N; ++j) w[i][j]->draw(g); Sleep(100); // 遅延関数(100ミリ秒間停止する) } int main() { int no; cout << "このライフゲームは、あらかじめ決まったパターンの配置(種)\n" << "から開始します。それぞれの種の中心位置は乱数で決定します。\n" << "スペースキーで描画を終了します。\n\n" << "種の個数を入力してください:"; cin >> no; ginit( N*10, N*10 ); // グラフィックスの初期化 GRAPH g; // GRAPH オブジェクトの生成 field w; init(w); // life オブジェクトの生成 time_t t; srand((unsigned) time(&t)); //乱数の初期化 if(no < 1) no = 1; while(no--){ int i = rand() % (N-5) + 3; int j = rand() % (N-5) + 3; create(w, i, j); // 生命体の設定 } while( vkey() != VK_SPACE ){ // スペースキーが押されるまで draw(&g, w); update(w); // 世代交代 } dele(w); // life オブジェクトの削除 gend(); // グラフィックスの終了 return 0; }
| 戻る |
Copyright 1999 Yamada,K