awkでライフゲーム(リアルタイム処理)
以前のブログの記事で、ライフゲームのアルゴリズムを紹介しました。
今回はawkでライフゲームをリアルタイムで動くプログラムを作りたいと思います。
BEGIN{ # [2]定数を定義 FIELD_WIDTH = 12; # [2-1]フィールドの幅を定義する FIELD_HEIGHT = 12 # [2-2]フィールドの高さを定義する FPS = 1000; # [2-3]1秒当たりの更新回数を定義する INTERVAL = 1000 / FPS; # [2-4]更新間隔(ミリ秒)を定義する # [3]変数を定義 field[0][0] = 0;field[0][1] = 1;field[0][2] = 0; field[1][0] = 0;field[1][1] = 0;field[1][2] = 1; field[2][0] = 1;field[2][1] = 1;field[2][2] = 1; lastClock = systime(); # [4-5-5]前回の経過時間を宣言する while(1){ newClock = systime(); # [4-5-7]現在の経過時間を宣言する # [4-5-8]前回の経過時間から、待機時間が経過していなければ if(newClock < lastClock + INTERVAL){ continue; # [4-5-9]待機時間に戻る } # [4-5-10]前回経過時間を現在の経過時間で更新する lastClock = newClock; DrawField(); # [4-5-11]フィールドを描画する関数を呼び出す # getch(); # [4-5-12]キーボード入力を待つ StepSimulation(); # [4-5-13]シミュレーションを進める } } # [4] 関数を宣言 function cls(){ printf("\033[H\033[J"); } function getch( cmd,k){ cmd="bash -c 'read -r -s -n 1 ke;echo $ke'" cmd | getline k; close(cmd) fflush() return k } # [4-1]フィールドを描画する関数 function DrawField(){ cls(); # [4-1-1]画面をクリアする # [4-1-2]フィールドのすべての行を反復する for(y = 0; y < FIELD_HEIGHT; y++){ # [4-1-3]フィールドのすべての列を反復する for(x = 0; x < FIELD_WIDTH; x++){ # [4-1-4]セルが生きていれば「■」を、死んでいれば「 」を描画する printf("%s",field[y][x] ? "■" : " "); } printf("\n"); # [4-1-5]1行描画するごとに改行する } } # [4-2]対象のセルと隣接する生きたセルの数を取得する関数 function GetLivingCellscount(_x,_y, x,y){ count = 0; # [4-2-1]生きているセルを数えるカンターを宣言 # [4-2-2]対象のセルの上下1マスを反復する for(y = _y - 1; y <= _y + 1; y++){ # [4-2-3]上下にループさせない場合は、行が範囲内かどうかを判定する # if((y < 0) || (y >= FIELD_HEIGHT)){ # continue; # [4-2-4]範囲外の行なのでスキップする # } # [4-2-5]上下にループしたY座標を宣言 roopedY = (FIELD_HEIGHT + y) % FIELD_HEIGHT; #print "y=",y,"roopedY=",roopedY,"x=",x,"roopedX=",roopedX,"count=",count; # [4-2-6]対象のセルの左右1マスを反復する for(x = _x + -1; x <= _x + 1; x++){ # [4-2-7]左右にループさせない場合は、列が範囲内かどうかを判定する # if((x < 0) || (x >= FIELD_WIDTH)){ # continue; # [4-2-8]範囲外の列なのでスキップする # } # [4-2-9]左右にループしたX座標を宣言する roopedX = (FIELD_WIDTH + x) % FIELD_WIDTH; # [4-2-10]対象の座標が、中心のセルと同じかどうかを判定する if((roopedX == _x) && (roopedY == _y)){ continue; # [4-2-11]対象の座標をスキップする } # [4-2-12]対象のセルが生きていれば1を、死んでいれば0を加算する count += field[roopedY][roopedX]; } } return count; # [4-2-13]生きているセルの数を返す } # [4-3]1ステップ分のシミュレーションを実行する関数 function StepSimulation(){ # [4-3-2]すべての行を反復する for(y = 0; y < FIELD_HEIGHT; y++){ # [4-3-3]すべての列を反復する for(x = 0; x < FIELD_WIDTH; x++){ # [4-3-4]対象のセルと隣接する、生きているセルの数を宣言 livingCellCount = GetLivingCellscount(x,y); # [4-3-5]隣接する生きたセルの数で分岐する if(livingCellCount <= 1){ # [4-3-5]1個なら # [4-3-6]対象のセルを死滅させる nextField[y][x] = 0; }else if(livingCellCount == 2){ # [4-3-7]2個なら # [4-3-8]現状維持 nextField[y][x] = field[y][x]; }else if(livingCellCount == 3){ # [4-3-9]3個なら # [4-3-10]対象のセルを誕生/生存させる nextField[y][x] = 1; }else{ # [4-3-11]4つ以上なら # [4-3-12]対象のセルを死滅させる nextField[y][x] = 0; } } } for(y = 0; y < FIELD_HEIGHT; y++){ for(x = 0; x < FIELD_WIDTH; x++){ field[y][x] = nextField[y][x]; } } }
awkで大きなプログラムを作る場合、変数をローカル変数になっているかどうか、きちんと確認する必要があります。
(私もこれにハマってしまい、バグを見つけるのに苦労しました)
utthi_fumi is awker!