昨晩、なんと7時に寝てしまい、今朝は1時に起きる始末。寝床の中でつらつら考えていると、古くから欧州、中東、アジア、中南米等場所を選ばず発生した侵略、覇権、示威、暴力等の人間の愚かさが思い起こされるも、宇宙の広大さを鑑みればそれは卑小さにしか過ぎず、まるでその様は「昔作ったBCCSkeltonのLifeGameのようだ」と感慨を抱きました。

ん?

それはネタとして使えるかも?と考え始めました。

 

末尾にあるのは、定年退職した直後にC++とBCCSkeltonの復習で書いた「ライフゲーム」プログラムで、

昔からあるライフゲームのアルゴリズムをクラス(注)でまとめようとしたものです。現在見直すと羞恥に堪えませんがお許しを。

注:このクラスは「世界」を表現していて、「生命体」を表現していないことに注意。

 

このライフゲームは、「世界(縦、横二次元の領域)」にランダムで1/3程度の「生命体(Cells)」を発生させ、集落(による共生)ができないと次世代生命が生まれなくなったり、死滅してしまいますが、一定数いれば繁殖し、過密状態になるとまた死滅するというものです。

 

このライフゲームが単純である理由は、

(1)種族が無い単一生命体(性別のない単一生殖)

(2)複数いると共助、共生する(というお気楽さ)

なのでしょうか?最初に作った時は世代交代で集落が変化してゆく様(それなりに)面白く見えますが、何度か見ると飽きてきますね。

 

では、どうすればより「人間に近いライフゲーム」が作れるのか?これは上記単純である理由を逆に降ればよいでしょう。

(1)クラスを「生命体ベースで作る。」

(2)生命体は「寿命」、「性別」、「種族」の属性を持ち、メソッドに「有効 vs. 敵対」判断と「(有効なら)共生」「(敵対なら)攻撃」を加えてやればよいのではないか?

(3)世界(閉鎖領域)をクラスで表現し、複数の種族(同一IDの生命体)を発生させ、単独別離の状態では従来のライフゲーム類似のルールで発展、衰退するが、発展の過程で多種族に遭遇すると攻撃(より複雑化するなら「避難」も)して自種族を存続させるようにすればよいのではないか?

 

と、ここまで考えて

「それって、うちらの世界、まんまじゃん!」

ということに気が付きました。

まぁ、気長にアイデアを熟成させましょうか?_

 

【LifeClass.h】

/*
    LifeClass.h
*/
// 定数定義


#define    MAX_WIDTH    50        // 世界の最大幅
#define    MAX_HEIGHT    50        // 世界の最大高さ
#define    INTERVAL    100        // Generation(世代)表示の長さ
#define    ALIVE        1
#define    DEAD        0
#define    TRUE        1
#define    FALSE        0

// Lifeクラス定義
class Life {
private:
    int        Width;
    int        Height;
    int*    Cells;
    int*    NewGen;
public:
    // サイズ無指定コンストラクター
    Life() {
        // 乱数の初期化
        srand((unsigned int)time(NULL));
        // 世界と次世代
        Cells = 0;
        NewGen = 0;
        // 世界の規模
        Width = rand() % (MAX_WIDTH - 2) + 3;    // Min 3が必要
        Height = rand() % (MAX_HEIGHT - 2) + 3;    // Min 3が必要
        // 生命体(Cells)の初期化
        if(!Cells)    Cells = new int[Width * Height];
        if(!NewGen)    NewGen = new int[Width * Height];
        // 世界の初期化(誕生する生命体数は1/3)
        for(int y = 0; y < Height; y++) {
            for(int x = 0; x < Width; x++) {
                if(rand() % 3 == 0)    // Cellを増やす場合、2(50%) → 3(66%)にする
                    Cells[x + Width * y] = ALIVE;
                else
                    Cells[x + Width * y] = DEAD;
            }
        }
    }
    // サイズ指定コンストラクター
    Life(int w, int h) {
        // 乱数の初期化
        srand((unsigned int)time(NULL));
        // 世界と次世代
        Cells = 0;
        NewGen = 0;
        // 世界の規模
        w = (w < 3 ? 3 : w);                // 幅はMin 3
        h = (h < 3 ? 3 : h);                // 高さもMin 3
        Width = (w > MAX_WIDTH ? MAX_WIDTH : w);    // 幅はMAX_WIDTH限度
        Height = (h > MAX_HEIGHT ? MAX_HEIGHT : h);    // 高さはMAX_HEIGHT限度
        // 生命体(Cells)の初期化
        if(!Cells)    Cells = new int[Width * Height];
        if(!NewGen)    NewGen = new int[Width * Height];
        // 世界の初期化(誕生する生命体数は1/3)
        for(int y = 0; y < Height; y++) {
            for(int x = 0; x < Width; x++) {
                if(rand() % 3  == 0)    // Cellを増やす場合、2(50%) → 3(66%)にする
                    Cells[x + Width * y] = ALIVE;
                else
                    Cells[x + Width * y] = DEAD;
            }
        }
    }
    // デストラクター
    ~Life() {
        delete [] Cells;
        delete [] NewGen;
    }
    // 次世代(NewGen)の世界の評価
    void Eval() {
        // 上下左右の状況確認
        for(int y = 0; y < Height; y++) {        // 高さ
            for(int x = 0; x < Width; x++) {    // 幅
                int count = 0;    // 周囲の生存(ALIVE)生命体(Cell)数
                if(x == 0) {                                            // 左は無い
                    if(y == 0) {                                            // 上は無い
                        if(Cells[(x + 1) + Width * y] == ALIVE)                    // 右
                            count++;
                        if(Cells[(x + 1) + Width * (y + 1)] == ALIVE)            // 右下
                            count++;
                        if(Cells[x + Width * (y + 1)] == ALIVE)                    // 下
                            count++;
                    }
                    else {
                        if(y == Height -1) {                                // 下は無い
                            if(Cells[x + Width * (y - 1)] == ALIVE)                // 上
                                count++;
                            if(Cells[(x + 1) + Width * (y - 1)] == ALIVE)        // 右上
                                count++;
                            if(Cells[(x + 1) + Width * y] == ALIVE)                // 右
                                count++;
                        }
                        else {    // 上下あり
                            if(Cells[x + Width * (y - 1)] == ALIVE)                // 上
                                count++;
                            if(Cells[(x + 1) + Width * (y - 1)] == ALIVE)        // 右上
                                count++;
                            if(Cells[(x + 1) + Width * y] == ALIVE)                // 右
                                count++;
                            if(Cells[(x + 1) + Width * (y + 1)] == ALIVE)        // 右下
                                count++;
                            if(Cells[x + Width * (y + 1)] == ALIVE)                // 下
                                count++;
                        }
                    }
                }
                else {
                    if(x == Width - 1) {                                // 右は無い
                        if(y == 0) {                                        // 上は無い
                            if(Cells[x + Width * (y + 1)] == ALIVE)                // 下
                                count++;
                            if(Cells[(x - 1) + Width * (y + 1)] == ALIVE)        // 左下
                                count++;
                            if(Cells[(x - 1) + Width * y] == ALIVE)                // 左
                                count++;
                        }
                        else {
                            if(y == Height -1) {                            // 下は無い
                                if(Cells[(x - 1) + Width * y] == ALIVE)            // 左
                                    count++;
                                if(Cells[(x - 1) + Width * (y - 1)] == ALIVE)    // 左上
                                    count++;
                                if(Cells[x + Width * (y - 1)] == ALIVE)            // 上
                                    count++;
                            }
                            else {                                            // 上下あり
                                if(Cells[x + Width * (y + 1)] == ALIVE)            // 下
                                    count++;
                                if(Cells[(x - 1) + Width * (y + 1)] == ALIVE)    // 左下
                                    count++;
                                if(Cells[(x - 1) + Width * y] == ALIVE)            // 左
                                    count++;
                                if(Cells[(x - 1) + Width * (y - 1)] == ALIVE)    // 左上
                                    count++;
                                if(Cells[x + Width * (y - 1)] == ALIVE)            // 上
                                    count++;
                            }
                        }
                    }
                    else {                                                // 左右あり
                        if(y == 0) {                                        // 上は無い
                            if(Cells[(x + 1) + Width * y] == ALIVE)                // 右
                                count++;
                            if(Cells[(x + 1) + Width * (y + 1)] == ALIVE)        // 右下
                                count++;
                            if(Cells[x + Width * (y + 1)] == ALIVE)                // 下
                                count++;
                            if(Cells[(x - 1) + Width * (y + 1)] == ALIVE)        // 左下
                                count++;
                            if(Cells[(x - 1) + Width * y] == ALIVE)                // 左
                                count++;
                        }
                        else {
                            if(y == Height - 1) {                            // 下は無い
                                if(Cells[(x - 1) + Width * y] == ALIVE)            // 左
                                    count++;
                                if(Cells[(x - 1) + Width * (y - 1)] == ALIVE)    // 左上
                                    count++;
                                if(Cells[x + Width * (y - 1)] == ALIVE)            // 上
                                    count++;
                                if(Cells[(x + 1) + Width * (y - 1)] == ALIVE)    // 右上
                                    count++;
                                if(Cells[(x + 1) + Width * y] == ALIVE)            // 右
                                    count++;
                            }
                            else {                                            // 上下あり
                                if(Cells[(x - 1) + Width * y] == ALIVE)            // 左
                                    count++;
                                if(Cells[(x - 1) + Width * (y - 1)] == ALIVE)    // 左上
                                    count++;
                                if(Cells[x + Width * (y - 1)] == ALIVE)            // 上
                                    count++;
                                if(Cells[(x + 1) + Width * (y - 1)] == ALIVE)    // 右上
                                    count++;
                                if(Cells[(x + 1) + Width * y] == ALIVE)            // 右
                                    count++;
                                if(Cells[(x + 1) + Width * (y + 1)] == ALIVE)    // 右下
                                    count++;
                                if(Cells[x + Width * (y + 1)] == ALIVE)            // 下
                                    count++;
                                if(Cells[(x - 1) + Width * (y + 1)] == ALIVE)    // 左下
                                    count++;
                            }
                        }
                    }
                }
                switch(count) {
                    case 0:    // 周囲の生命体数が1以下だと死滅
                    case 1: NewGen[x + Width * y] = DEAD;
                            break;
                    case 2:    // 周囲の生命体数が2 - 3の場合は現状維持
                            NewGen[x + Width * y] = Cells[x + Width * y];
                            break;
                    case 3:    // 周囲の生命体数が3の場合は、生命体が誕生する
                            NewGen[x + Width * y] = ALIVE;
                            break;
                    case 4:    // 周囲の生命体数が4以上だと過密で死滅
                    case 5:
                    case 6:
                    case 7:
                    case 8: NewGen[x + Width * y] = DEAD;
                            break;
                }
            }
        }
    }
    void Transition() {
        for(int y = 0; y < Height; y++) {        // 高さ
            for(int x = 0; x < Width; x++) {    // 幅
                Cells[x + Width * y] = NewGen[x + Width * y];
            }
        }
    }
    int GetW() {return Width;}
    int GetH() {return Height;}
    int* GetCells() {return Cells;}
};