見出し画像

ライフゲームで在来と省エネ型ソースコード

ライフゲームで在来と省エネ型ソースコード


2024年9月17初稿

エッセイ『現在のデーターセンターに置ける省エネ型コン
ピューターを考察』
の補足の為に具体的なソースコードとし
て「ライフゲーム」と言う良く知られている物を使用!

ライフゲームでは初期状態のみでその後の状態が決定される
碁盤のような格子があり、一つの格子はセル(細胞)と呼ば
れる。各セルには8つの近傍のセルがある (ムーア近傍) 。
各セルには「生」と「死」の2つの状態があり、あるセルの
次のステップ(世代)の状態は周囲の8つのセルの今の世代
における状態により決定される。

セルの生死は次のルールに従う。

誕生
死んでいるセルに隣接する生きたセルがちょうど3つあれば、
次の世代が誕生する。
生存
生きているセルに隣接する生きたセルが2つか3つならば、
次の世代でも生存する。
過疎
生きているセルに隣接する生きたセルが1つ以下ならば、
過疎により死滅する。
過密
生きているセルに隣接する生きたセルが4つ以上ならば、
過密により死滅する。
下に中央のセルにおける次のステップでの生死の例を示す。
生きているセルは■、死んでいるセルは□で表す。

セルの生死ルール

生きているセルは■、死んでいるセルは□で表す。

1.教科書的なソースコード

/*ライフゲームで在来型ソースコード*/

/*ライフゲームで在来型CPU使用例在来型ソースコード*/

#include <stdio.h>                      /* 標準的なC言語システムヘッダ */

#define HSIZE 1000                      /* 水平方向サイズが1000*/
#define VSIZE 1000                      /* 垂直方向サイズが1000*/

typedef unsigned char   CELL;           /* 生死情報型名 */

CELL    stage[1000000];                 /* ライフゲームの実現ステージとし縦横1000×1000サイズ領域 */


/* ステージをクリア≪全て生者が無い状態に初期化≫  */

void    ClearStage(void)                /* 仮引数も関数返値も無い */
{
    int     i;                          /* カウンタ:インデックス */

    for( i = 0; i < 1000000; i++ ){     /* お馴染みforループ構文で1000000回繰り返す */
        stage[i] = 0;                   /* ライフゲームの実現ステージに生者が無い状態=0セット */
    }
}


/* ライフゲームの実現ステージ≪1次元データ配列の記録領域だが2次元と見なす≫縦横を */
/* 2次元座標XY指定で位置の生死セル状態を取出する関数 */

int     getCELL( int x, int y ){        /* 仮引数で座標XY指定 */
    return( stage[ x + y * HSIZE] );    /* 1次元データを2次元と見なしてアクセスしてデータ取り出し */
}


/* ライフゲームの実現ステージ≪1次元データ配列の記録領域だが2次元と見なす≫縦横を */
/* 2次元座標XY指定で位置の生死セル状態変更(セット)する関数 */

void    putCELL( int x, int y, int d ){ /* 仮引数で座標XY指定と生死データ指定、関数返値は無い */
    stage[ x + y * HSIZE] = d;          /* 1次元データを2次元と見なしてアクセスしてデータを */
                                        /* 状態変更(セット) */
}


/* ライフゲームの一世代進行≪世代交代≫ */
/* ★備考★極、教科書で記載する様なソースコード */

void    generationalChange(void)        /* 仮引数も関数返値も無い */
{
    int     x;          /* 横(水平或はX座標)方向の位置 */
    int     y;          /* 縦(垂直或はY座標)方向の位置 */
    int     sum;        /* 注視点の生死判定する隣接セル生死把握の為の生セル合計 */

    for( y = 0; y < VSIZE; y++ ){               /* 2重ループの外側「縦(垂直)方向Y」増加ループ */
        for( x = 0; x < HSIZE; x++ ){           /* 2重ループの内側「横(水平)方向X」増加ループ */
            sum = getCELL( x - 1, y - 1 )       /* 注視点の斜め左上隣 */
               += getCELL( x, y - 1 )           /* 注視点の上隣 */
               += getCELL( x + 1, y - 1 )       /* 注視点の斜め右上隣 */
               += getCELL( x - 1, y )           /* 注視点の左隣 */
               += getCELL( x + 1, y )           /* 注視点の右隣 */
               += getCELL( x - 1, y + 1 )       /* 注視点の斜め左下隣 */
               += getCELL( x, y + 1 )           /* 注視点の下隣 */
               += getCELL( x + 1, y + 1 );      /* 注視点の斜め右下隣と注視点周辺生セル合計 */
            if( 3 == sum ){                     /* セル誕生条件なら */
                putCELL( x, y, 1 );             /* 誕生≪セルの値を「1」にセット≫ */
            }else if( 1 <= sum ){               /* 過疎条件ならば */
                putCELL( x, y, 0 );             /* 死滅≪セルの値を「0」にセット≫ */
            }else if( 4 >= sum ){               /* 過密条件ならば */
                putCELL( x, y, 0 );             /* 死滅≪セルの値を「0」にセット≫ */
            }                                   /* if構文の終端 */
        }                                       /* 内側「横(水平)方向X」増加ループ終端 */
    }                                           /* 外側「縦(垂直)方向Y」増加ループ終端 */
}


/* ライフゲームの遊び方 */

void    example1(void)                          /* 例文1 */
{
    char    buf[100];                           /* 印刷用文字列バッファ */
    int     i;                                  /* インデックス・カウンタ */
    int     x;                                  /* X座標 */
    int     y;                                  /* Y座標 */

    ClearStage();                               /* 全て死の世界 */
    putCELL( 1, 1, 1 );                         /* 生者をセット */
    putCELL( 2, 1, 1 );                         /* 生者をセット */
    putCELL( 3, 1, 1 );                         /* 生者をセット */
    putCELL( 1, 2, 1 );                         /* 生者をセット */
    putCELL( 1, 3, 1 );                         /* 生者をセット */
    for( y = 0; y < 100; ){                     /* 先頭(上)から100行印刷ループ */
        for( i = 0; i < 100; i++ ){             /* 印刷用文字列バッファを */
            buf[i] = 0;                         /* 0クリア */
        }                                       /* */
        for( x = 0; x < 100; ){                 /* 先頭(最左側)から100セル印刷ループ */
            if( 0 == getCELL( x, y ) ){         /* セルに死者しか無い */
                buf[x] = ' ';                   /* 文字「空白」をバッファにセット */
            }else{                              /* セルに生者発見 */
                buf[x] = '*';                   /* 文字「アスタリスク」をバッファにセット */
            }                                   /* if構文終端 */
        }                                       /* for構文(X座標)終端 */
        printf( "%s\n", buf );                  /* 文字バッファを印刷 */
    }                                           /* for構文(Y座標)終端 */
    generationalChange();                       /* ライフゲームの一世代進行 */
    for( y = 0; y < 100; ){                     /* 先頭(上)から100行印刷ループ */
        for( i = 0; i < 100; i++ ){             /* 印刷用文字列バッファを */
            buf[i] = 0;                         /* 0クリア */
        }                                       /* */
        for( x = 0; x < 100; ){                 /* 先頭(最左側)から100セル印刷ループ */
            if( 0 == getCELL( x, y ) ){         /* セルに死者しか無い */
                buf[x] = ' ';                   /* 文字「空白」をバッファにセット */
            }else{                              /* セルに生者発見 */
                buf[x] = '*';                   /* 文字「アスタリスク」をバッファにセット */
            }                                   /* if構文終端 */
        }                                       /* for構文(X座標)終端 */
        printf( "%s\n", buf );                  /* 文字バッファを印刷 */
    }                                           /* for構文(Y座標)終端 */
}

在来型CPUでの在来型ソースコードで取り敢えず
ライフゲームのプログラムを作成して見ました!
省エネ型は、引き続き、このエッセイに記載しますが、
先ずは、理解して頂く為にここまでとします!

2.私の画像処理ライブラリに多用しているポイント多用のソースコード

/* ライフゲームの一世代進行≪世代交代≫ */
/* ★備考★私が画像処理ライブラリ開発に使用した高速化処理ソースコード */

void    generationalChange(void)        /* 仮引数も関数返値も無い */
{
    int     x;          /* 横(水平或はX座標)方向の位置カウンタ */
    int     y;          /* 縦(垂直或はY座標)方向の位置カウンタ */
    CELL*   px;         /* 横(水平或はX座標)方向の位置をポインタ変数表現 */
    CELL*   py;         /* 縦(垂直或はY座標)方向の位置をポインタ変数表現 */
    int     sum;        /* 注視点の生死判定する隣接セル生死把握の為の生セル合計 */

    py = stage;                                 /* ポインタ原点をセット */
    for( y = VSIZE; --y >= 0; py -= HSIZE ){    /* 2重ループの外側「縦(垂直)方向Y」増加ループ */
        px = py;                                /* 「横(水平)方向X」ポインタ原点をセット */
        for( x = HSIZE; --x >= 0; px-- ){       /* 2重ループの内側「横(水平)方向X」増加ループ */
        sum = *(px - 1 - HSIZE )                /* 注視点の斜め左上隣 */
           += *(px - HSIZE )                    /* 注視点の上隣 */
           += *(px + 1 - HSIZE )                /* 注視点の斜め右上隣 */
           += *(px - 1 )                        /* 注視点の左隣 */
           += *(px x + 1 )                      /* 注視点の右隣 */
           += *(px - 1 + HSIZE )                /* 注視点の斜め左下隣 */
           += *(px + HSIZE )                    /* 注視点の下隣 */
           += *(px+ 1 + HSIZE );                /* 注視点の斜め右下隣 */
            if( 3 == sum ){                     /* セル誕生条件なら */
                *px = 1;                        /* 誕生≪セルの値を「1」にセット≫ */
            }else if( 1 <= sum ){               /* 過疎条件ならば */
                *px = 0;                        /* 死滅≪セルの値を「0」にセット≫ */
            }else if( 4 >= sum ){               /* 過密条件ならば */
                *px = 0;                        /* 死滅≪セルの値を「0」にセット≫ */
            }                                   /* if構文の終端 */
        }                                       /* 内側「横(水平)方向X」増加ループ終端 */
    }                                           /* 外側「縦(垂直)方向Y」増加ループ終端 */
}


文末

この記事が気に入ったらサポートをしてみませんか?