目次へ 1ページ 2ページ 3ページ 4ページ

2.3 プログラムの拡張  1999.03.13(初版)

2.3.1 周期的境界条件  境界の左端を右端につなぎ、上端を下端につないで境界を周期的にしてみましょう。 つまり境界を越えると反対側の境界に現れるようにします。次の関数を用意して、
// 境界を周期的に扱う
int cyclic(const int i) 
{ 
    if(i > N-1) 
        return (i - N); 
    else if(i < 0) 
        return (N + i); 
    else 
        return i; 
}
lifeクラスのメンバー関数 life::count() を次のように書き換えるとよいでしょう。
// 隣接した生命体の状態をカウント
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()]--; // 自分の状態は数えない 
}
また、世代交代で今度は境界値も含めます。
// 世代交代
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]; // 新しい状態をコピー 
        } 
}
以上。 ソース・ファイルはこちらです。 LIFE03.CPP(5KB) または、HTMLファイルで見る場合ははこちら

実行ファイルとソースファイルのダウンロードはこちらです。
ライフゲーム (3)
実行ファイルとソース・ファイル
Windows 95/ 98上で動作します。
  ダウンロード
  life03.lzh (47KB)

 * このソフトウェアは、SYMANTEC. NORTON AntiVirus 5.0 でウィルス検査を 
  行っています。 
 * ファイルは吉崎栄泰氏による LHA (Copyright(c)1988-92 H.Yoshizaki)を 
  使って圧縮しています。



2.3.2 クラスを追加する  継承を使ったバージョンの優れている点は、ソフトウェアの設計に柔軟な拡張性を持 たせることができることです。ここで新たにクラスを追加することを考えます。  これまで派生クラスは dying と living の2つありましたが、さらにもう1つの状態 を考えることができます。「生命体が存在しない」という状態です。つまりセルが空っ ぽということです。そうすることで、生きている状態は白色で示し、死んでいる状態に は別の色を使って世代ごとにランダムに印を付けることで、生命体が繁殖してゆく足跡 を追うことができます。  まず、列挙子の定義に空っぽの状態を示すタグ名 EMPTY を追加し、 enum state{ EMPTY, DYING, LIVING, STATES}; と書き変えます。新しい派生クラスとして、空っぽクラス empty を追加して、
// 空(生命体は存在しない)クラス
class empty : public life{ 

public: 
    empty(int r, int c) { row = r; col = c;}    
    state getstate() const { return EMPTY; }    
    life* next(field); 
    void draw(GRAPH *){} // 何もしない 
};
またメンバ関数を書きます。
// 次の世代の状態を決定する
life* empty::next(field w) 
{ 
    int sum[STATES]; 
    count(w, sum); 
    if(sum[LIVING] == 3) 
        return (new living(row, col)); 
    else 
        return (new empty(row, col)); 
}
後は描画関数 dying::draw() を少し手直しするだけです。  ここで用意した実際のコードにはもう一工夫加えています。これまでは世代の変化の 度に画面を一旦クリアして再び描画仕直していました。これではグラフィックス関数の 呼び出しのために効率を悪くしています。前の世代と同じ状態のセルには描画しないよ うにして、変化したセルだけを描画するようにしています。詳細はソースコードをご覧 ください。 ソース・ファイルはこちらです。 LIFE04.CPP(6KB) または、HTMLファイルで見る場合ははこちら

 実行ファイルとソース・ファイルのダウンロードはこちらです。
ライフゲーム (4)
実行ファイルとソース・ファイル
Windows 95/ 98上で動作します。
  ダウンロード
  life04.lzh (48KB)

 * このソフトウェアは、SYMANTEC. NORTON AntiVirus 5.0 でウィルス検査を 
  行っています。 
 * ファイルは吉崎栄泰氏による LHA (Copyright(c)1988-92 H.Yoshizaki)を 
  使って圧縮しています。


2.3.3 もっと複雑な環境シミュレーション  はじめに生命体の状態をクラスにするのは少し奇妙に見えると述べましたが、自然な クラス設計であることが分かります。奇妙に見えたのは、一種類の生命体を考えたから です。これは次のようなプログラミングを考えると良く理解できます。  複数の種類の生物が共存する環境シミュレーションを考えます。捕食者と被捕食者が いる場合などです。典型的な例は、肉食動物のキツネと草食動物のウサギです。ウサギ は草を食べて生き、キツネはウサギを捕獲します(さらにキツネはハンターに撃たれる かもしれない)。草とウサギとキツネの繁栄と絶滅は互いにリンクしています。この状 況は、ライフゲームとまったく同じです。  このキツネたちのクラス設計の例は、次の文献にもあります。 Ira Pohl著:C++によるオブジェクト指向プログラミング、アスキー出版局

目次 前のページへ 

Copyright(c) 1999 Yamada,K