awkで三目並べ

今回もawkでゲームを作ります。
いわゆる三目並べです。
人間同士の戦いのみです。
AI導入はどなたがお願いします。

BEGIN{
    system("clear");
    # ターミナルの設定を保存して変更
    "stty -g" | getline old_stty
    close("stty -g")
    # cbreak:Enterなしで入力,-echo:入力文字を入力しない
    system("stty cbreak -echo")

    # 配列の初期化
    for(i=0; i < 3; i++){
        for(j = 0; j < 3; j++){
            state[i,j] = "";
        }
    }


    activeCell[0] = 0;
    activeCell[1] = 0;
    player = "X";
    win_player = player;


    while(1) {
        # 画面をクリアしてから描画
        system("clear");
        printf("%s", renderGame(state,activeCell,player));
        key = getch();
        if(key == "q") break;
        move(key,state,activeCell);
        if(isWinState(state)){
            print "end";
            break;
        }
   }

    # 復元
    system("stty " old_stty)
}
function getch(     key,cmd){
    # 1文字だけを直接取得(/dev/tty から直接 dd で抜く)
    cmd = "dd bs=1 count=1 2>/dev/null"
    if ((cmd | getline key) > 0) {
        # パイプを毎回閉じることで、バッファをクリアし「今」の入力を取る
        close(cmd)
        return key;
    } else {
        close(cmd)
    }
}

function move(key,state,activeCell){
    if(key == "w" && activeCell[0] > 0) activeCell[0]--;
    if(key == "s" && activeCell[0] < 2) activeCell[0]++;
    if(key == "a" && activeCell[1] > 0) activeCell[1]--;
    if(key == "d" && activeCell[1] < 2) activeCell[1]++;

    if(key == " "){
        if(state[activeCell[0],activeCell[1]] == ""){
            state[activeCell[0],activeCell[1]] = player;
            if(player == "X")
                player = "O";
            else
                player = "X";
        }
    }
}
function renderGame(state,activeCell,player,    output,i,j,cell,val){

    output = "Player:" player "(WASD move,Space mark,Q quit)\n";
    for(i = 0; i <= 2; i++){
        output = output "|";
        for(j = 0; j <= 2; j++){
            val = state[i,j];
            if(val == ""){
                cell = " ";
            }else{
                cell = val;
            }
            if(activeCell[0] == i && activeCell[1] == j){
                cell = "-" cell "-";
            }else{
                cell = " " cell " ";
            }
            output = output cell "|";
        }
        output = output "\n";
    }
    return output;
}
function isWinState(state,  i,j,blankQuares){
    for(i = 0; i < 3; i++){
        if(state[i,0] == win_player && state[i,1] == win_player && state[i,2] == win_player){
            print win_player "win";
            return 1;
        }
    }
    for(j = 0; j <3; j++){
        if(state[0,j] == win_player && state[1,j] == win_player && state[2,j] == win_player){
            print win_player "win";
            return 1;
        }
    }
    if(state[0,0] == win_player && state[1,1] == win_player && state[2,2] == win_player) {
        print win_player "win";
        return 1;
    }
    if(state[2,0] == win_player && state[1,1] == win_player && state[0,2] == win_player) {
        print win_player "win";
        return 1;
    }
    blankQuares = 0;
    for(i=0; i < 3; i++){
        for(j = 0; j < 3; j++){
            if(state[i,j] == "")
                blankQuares++;
        }
    }
    if(blankQuares == 0){
        print "DRAW!";
        return 1;
    }
    win_player = player;
}

今回はgawkでもmawkでも動作するようにしております。
awkはテキスト処理がメインのプログラミング言語ですが、このようなコマンドライン上のゲームも作ることができます。
いきなり高度なゲームを作るよりは、まずはこのような簡単なゲーム作りから始めてみるのはいかがでしょうか?

awkでテキストアニメーション

以前、斎藤さんの本

www.shoeisha.co.jp

で紹介されていたawkでテキストアニメーションのソースコードです。 元のコードは読みにくい形でしたので整形して掲載いたします。
しかし、こんな短いプログラムで奇麗なテキストアニメーションが出るんですね。
このコードの作者はawkテトリスも作っており、まさに凄腕ハッカーです。

#! /usr/bin/awk -f
# $Id: blobs.awk,v 1.4 2006/01/31 23:14:38 tnn Exp $

# AWK eyecandy. resize your terminal emulator for speed/resolution.
# (c) 2004 Tobias Nygren <tnn+blobs-awk@nygren.pp.se>

# uncomment this line if your awk is mean
# function fflush(e) {}

function f(m,           n){
    o = + x - X / 2 - cos(a * m) * 30;
    p=y- Y / 2 - sin(a * n) *9;
    return sqrt (o * o + p * p);
}
BEGIN {
    c = "stty size";
    c | getline;
    close (c);
    X = $2;
    Y = $1 - 1;
    for(;;){
        a += +.002;
        d="    ead    beef    ";
        printf("" "tnn@netilium.o"     "rg   \033"  "[H"     );
        #@    ninja
        fflush(stdout);;
        for(y = 0;y++ < Y;) {
            for (x=0 ;x++< X;){
                printf ("%c", 32+(f(30 ,40) *f(0 +12,   17)/  3/(1 +f(19 ,+23 )))%  64)
            }
        }
    }
}

awkでこんなことも出来るのか!と感動します。
現在、プログラミング言語AWKで一から勉強中ですが、古い言語ながら未だに新たな発見の多い言語です。

awkでライフゲーム(リアルタイム処理)

以前のブログの記事で、ライフゲームアルゴリズムを紹介しました。

utthi-fumi.hatenablog.com

utthi-fumi.hatenablog.com

今回は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!

awkでRPGゲーム

ゲームでプログラミングとなると、大抵はjavascriptで作ることが多いと思います。
キーボード操作やマウス操作が絡んできますからね。
awkでも、リアルタイムでキーボード操作ができれば、ゲームを作ることができます。
キーボード操作そのものはシェルスクリプトになります。
簡単なRPGゲーム(?)を作成してみました。
いきなり、ドラクエの最後のボスとの直接対決からスタートします。
wキーが上に移動、sキーが下に移動します。
ぜひ、最後の魔王を倒して、世界に平和をもたらしてください。

#! /usr/bin/gawk -f
# rpg.awk


function getch(     cmd,k){
    cmd="bash -c 'read -r -s -n 1 ke;echo $ke'"
    cmd | getline k;
    close(cmd)
    fflush()
    return k
}
function cls(){
    printf("\033[H\033[J")
}

#[6-1]ゲームを初期化する関数を宣言する
function Init(){
    #[6-1-1]プレイヤーのステータスを初期化する
    characters[CHARACTER_PLAYER]["hp"]    = monsters[MONSTER_PLAYER]["hp"];
    characters[CHARACTER_PLAYER]["maxHp"] = monsters[MONSTER_PLAYER]["maxHp"];
    characters[CHARACTER_PLAYER]["mp"]    = monsters[MONSTER_PLAYER]["mp"];
    characters[CHARACTER_PLAYER]["maxMp"] = monsters[MONSTER_PLAYER]["maxMp"];
    characters[CHARACTER_PLAYER]["attack"] = monsters[MONSTER_PLAYER]["attack"];
    characters[CHARACTER_PLAYER]["name"]  = monsters[MONSTER_PLAYER]["name"];

}

#[6-2]戦闘シーンの画面を描画する関数を宣言する
function DrawBattleScreen(){
    #[6-2-1]画面をクリアする
    cls();
    # [6-2-2]プレイヤーの名前を表示する
    printf("%s\n",characters[CHARACTER_PLAYER]["name"]);
    # [6-2-3]プレイヤーのステータスを表示する
    printf("HP:%d%d MP:%d%d\n",
           characters[CHARACTER_PLAYER]["hp"],
           characters[CHARACTER_PLAYER]["maxHp"],
           characters[CHARACTER_PLAYER]["mp"],
           characters[CHARACTER_PLAYER]["maxMp"]);
    #[6-2-4]1行空ける
    printf("\n");
    #[6-2-5]モンスターのアスキーアートを描画する
    printf("%s",characters[CHARACTER_MONSTER]["aa"]);
    #[6-2-6]モンスターのHPを表示する
    printf("(HP:%d%d)\n",
           characters[CHARACTER_MONSTER]["hp"],
           characters[CHARACTER_MONSTER]["maxHp"]);
    #[6-2-7]1行空ける
    printf("\n");
}
#[6-3]コマンドを選択する関数を宣言する
function SelectCommand(){
    #[6-3-1]プレイヤーのコマンドを初期化する
    characters[CHARACTER_PLAYER][character_command] = 0;
    #character_command = 0;
    #[6-3-2]コマンドが決定するまでループする
    while(1){
        #[6-3-3]戦闘画面を描画する関数を呼び出す
        DrawBattleScreen();
        #[6-3-4]コマンドの一覧を表示する
        for(i = 0; i < COMMAND_MAX; i++){
            #[6-3-5]選択中のコマンドなら
            if(i == characters[CHARACTER_PLAYER][character_command]){
                #[6-3-6]カーソルを描画する
                printf(">");
            }else{  #[6-3-7]選択中のコマンドでなければ
                printf(" ");
            }
            #[6-3-9]コマンドの名前を表示する
            printf("%s\n",commandNames[i]);
        }
        #[6-3-10]入力されたキーによって分岐する
        switch(getch()){
            case "w":   #[6-3-11]wキーが押されたら
            #[6-3-12]上のコマンドに切り替える
            characters[CHARACTER_PLAYER][character_command]--;
            #character_command--;
            break;
            case "s":   #[6-3-13]sキーが押されたら
            #[6-3-14]下のコマンドに切り替える
            characters[CHARACTER_PLAYER][character_command]++
            #character_command++;
            break;
            default:#[6-3-15]上記以外のキーが押されたら
            return; #[6-3-16]関数を抜ける

        }
        #[6-3-17]カーソルを上下にループさせる
        characters[CHARACTER_PLAYER][character_command] = (COMMAND_MAX + characters[CHARACTER_PLAYER][character_command]) % COMMAND_MAX;
    }
}

#[6-4]戦闘シーンの関数を宣言する
function Battle(_monster){
    #[6-4-1]モンスターのステータスを初期化する
    characters[CHARACTER_MONSTER]["hp"]    = monsters[_monster]["hp"];
    characters[CHARACTER_MONSTER]["maxHp"] = monsters[_monster]["maxHp"];
    characters[CHARACTER_MONSTER]["mp"]    = monsters[_monster]["mp"];
    characters[CHARACTER_MONSTER]["maxMp"] = monsters[_monster]["maxMp"];
    characters[CHARACTER_MONSTER]["name"]  = monsters[_monster]["name"];
    characters[CHARACTER_MONSTER]["attack"]  = monsters[_monster]["attack"];
    characters[CHARACTER_MONSTER]["aa"]    = monsters[_monster]["aa"];

    #[6-4-2]プレイヤーの攻撃対象をモンスターに設定する
    characters[CHARACTER_PLAYER]["target"] = CHARACTER_MONSTER;
    #[6-4-3]モンスターの攻撃対象をプレイヤーに設定する
    characters[CHARACTER_MONSTER]["target"] = CHARACTER_PLAYER;
    #[6-4-3]モンスターの攻撃対象をプレイヤーに設定する

    #[6-4-4]戦闘シーンの画面を描画する関数を呼び出す
    DrawBattleScreen();
    #[6-4-5]戦闘シーンの最初のメッセージを表示する
    printf("%sがあらわれた!\n",characters[CHARACTER_MONSTER]["name"]);
    #[6-4-6]キーボード入力を待つ
    getch();
    #[6-4-7]戦闘シーンが終了するまでループする
    while(1){
        #[6-4-8]コマンドを選択する関数を呼び出す
        SelectCommand();
        #[6-4-9]各キャラクターを反復する
        for(i = 0; i < CHARACTER_MAX; i++){
            #[6-4-10]戦闘シーンの画面を描写する関数を呼び出す
            DrawBattleScreen();
            switch(characters[i][character_command]){
                case 0:    #[6-4-12]戦う
                printf("%sのこうげき!\n",characters[i]["name"]);
                getch();
                #[6-4-15]敵に与えるダメージを計算する
                damage = 1 + int(rand() * 1000) % characters[i]["attack"];
                #[6-4-16]敵にダメージを与える
                characters[characters[i]["target"]]["hp"] -= damage;
                #[6-4-17]敵のHPが負の値になったかどうかを判定する
                if(characters[characters[i]["target"]]["hp"] < 0){
                    #[6-4-18]敵のHPを0にする
                    characters[characters[i]["target"]]["hp"] = 0;
                }
                #[6-4-19]戦闘シーンの画面を再描画する関数を呼び出す
                DrawBattleScreen();
                #[6-4-20:敵にダメージを与えたメッセージを表示する
                printf("%s%dのダメージ!\n",\
                       characters[characters[i]["target"]]["name"],\
                       damage);
                #[6-4-21]キーボード入力を待つ
                getch();
                break;
                case 1:    #[6-4-22]回復
                #[6-4-23]MPが足りるかどうかを判定する
                if(characters[i]["mp"] < SPELL_COST){
                    #[6-4-24]MPが足りないメッセージを表示する
                    printf("MPがたりない!\n");
                    #[6-4-25]キーボード入力を待つ
                    getch();
                    #[6-4-26]呪文を唱える処理を抜ける
                    break;
                }
                #[6-4-27]MPを消費させる
                characters[i]["mp"] -= SPELL_COST;
                #[6-4-28]画面を再描画する
                DrawBattleScreen();
                #[6-4-29]回復するメッセージを表示する
                printf("%sは回復することにした!\n",characters[i]["name"]);
                #[6-4-30]キーボード入力を待つ
                getch();
                #[6-4-31]HPを回復させる
                characters[i]["hp"] = characters[i]["maxHp"];
                #[6-4-32]戦闘シーンの画面を再描画する
                DrawBattleScreen();
                #[6-4-33]HPが回復したメッセージを表示する
                printf("%sのきずがかいふくした!\n",characters[i]["name"]);
                #[6-4-34]キーボード入力を待つ
                getch();
                break;
                case 2:    #[6-4-35]逃げる
                #[6-4-36]逃げ出したメッセージを表示する
                printf("%sはにげだした!\n",characters[i]["name"]);
                #[6-4-37]キーボード入力を待つ
                getch();
                #[6-4-38]戦闘処理を抜ける
                return;
                break;
            }
            #[6-4-39]攻撃対象を倒したかどうかを判定する
            if(characters[characters[i]["target"]]["hp"] <= 0){
                #[6-4-40]攻撃対象によって処理を分岐させる
                switch(characters[i]["target"]){
                    #[6-4-41]プレイヤーなら
                    case 0:
                    #[6-4-42]プレイヤーが死んだメッセージを表示する
                    printf("あなたはしにました");
                    break;
                    #[6-4-43]モンスターなら
                    case 1:
                    #[6-4-44]モンスターのアスキーアートを何も表示しないよう書き換える
                    characters[characters[i]["target"]]["aa"] = "";
                    #[6-4-45]戦闘シーンの画面を再描画する関数を呼び出す
                    DrawBattleScreen();

                    #[6-4-46]モンスターを倒したメッセージを表示する
                    printf("%sをたおした!\n",\
                           characters[characters[i]["target"]]["name"]);
                    break;
                }
                #[6-4-47]キーボード入力を待つ
                getch();
                #[6-4-48]戦闘シーンの関数を抜ける
                return;
            }
        }
    }
}

#[6-6]プログラムの実行開始点を宣言
BEGIN{
    # [5]変数を定義

    MONSTER_PLAYER = 0; #[3-1-1]プレイヤー
    MONSTER_SLIME  = 1; #[3-1-2]スライム
    MONSTER_BOSS   = 2; #[3-1-3]魔王
    MONSTER_MAX    = 3; #[3-1-4]モンスターの種類の数

    monsters[MONSTER_PLAYER]["hp"]     = 100;
    monsters[MONSTER_PLAYER]["maxHp"]  = 100;
    monsters[MONSTER_PLAYER]["mp"]     = 15;
    monsters[MONSTER_PLAYER]["maxMp"]  = 15;
    monsters[MONSTER_PLAYER]["attack"] = 30;
    monsters[MONSTER_PLAYER]["name"]   = "ゆうしゃ";

    monsters[MONSTER_SLIME]["hp"]     = 3;
    monsters[MONSTER_SLIME]["maxHp"]  = 3;
    monsters[MONSTER_SLIME]["mp"]     = 0;
    monsters[MONSTER_SLIME]["maxMp"]  = 0;
    monsters[MONSTER_SLIME]["attack"] = 2;
    monsters[MONSTER_SLIME]["name"]   = "スライム";
    monsters[MONSTER_SLIME]["aa"]     = "/・Д・\\n"\
                                        "~~~~~~";#アスキーアート
    monsters[MONSTER_BOSS]["hp"]      = 255;
    monsters[MONSTER_BOSS]["maxHp"]   = 255;
    monsters[MONSTER_BOSS]["mp"]      = 0;
    monsters[MONSTER_BOSS]["maxMp"]   = 0;
    monsters[MONSTER_BOSS]["attack"]  = 50;
    monsters[MONSTER_BOSS]["name"]    = "まおう";
    monsters[MONSTER_BOSS]["aa"]      = "  A@A\n"\
                                        "~(▼皿▼)~";


    CHARACTER_PLAYER  = 0;   #[3-2-1]プレイヤー
    CHARACTER_MONSTER = 1;   #[3-2-2]モンスター
    CHARACTER_MAX     = 2;   #[3-2-3]キャラクターの種類


    character_command = 0;

    COMMAND_MAX = 3; #コマンドの種類の数

    # [5-3]コマンドの名前を宣言する
    commandNames[0] = "たたかう";   #[5-3-1]
    commandNames[1] = "かいふく";   #[5-3-2]
    commandNames[2] = "にげる";     #[5-3-3]

    SPELL_COST = 3; #呪文の消費MPを定義する

    #[6-6-1]乱数をシャッフルする
    srand();


    # [6-6-2]ゲームを初期化する関数を呼び出す
    Init();

    # [6-6-3]戦闘シーンの関数を呼び出す
    Battle(MONSTER_BOSS);
    # [6-6-4]キーボード入力を待つ
    getch();

}

私自身、awkでここまで大掛かりなプログラミングをしたのは初めてで、かなり苦労しました。
しかし、awkでもここまで出来ることが分かったのではないでしょうか?

utthi_fumi is game programmer!

ライフゲーム

ライフゲーム

碁盤の目の上に、いくつかの石(生命体)を適当に配置する。これらの生命体は、以下に述べる簡単なルールに従って生き続ける。
それを見て楽しむという単純なゲームである。
盤面では、どの場所も縦・横・斜めに8個の場所と隣り合っているが、もしある場所が空いていて、しかもその場所と隣り合うちょうど3個の場所に生命体が存在するならば、次の世代にはその空いた場所に新しい生命体が誕生する。
一方、すでに存在する生命体については、隣り合う場所に住む生命体が1個以下または4個以上になると、過疎または過密のため、次の世代には死んでしまう。
以下ソース

#include<stdio.h>
#include<stdlib.h>

#define N   22                      /*  縦方向  */
#define M   78                      /*  横方向  */
char a[N + 2][M + 2], b[N + 2][M + 2];  /*  盤  */


int main(void){
    int i, j, g;

    a[N / 2][M / 2] = a[N / 2 - 1][M / 2] = a[N / 2 + 1][M / 2]
    = a[N / 2][M / 2 - 1] = a[N / 2 - 1][M / 2 + 1] = 1;        /*  初期状態    */
    for(g = 1; g <= 1000; g++){
        printf("Generation %4d\n",g);                           /*  世代        */
        for(i = 1; i <= N; i++){
            for(j = 1; j <= M; j++){
                if(a[i][j]){
                    printf("*");
                    b[i - 1][j - 1]++;  b[i - 1][j]++;  b[i - 1][j + 1]++;
                    b[i    ][j - 1]++;                  b[i    ][j + 1]++;
                    b[i + 1][j - 1]++;  b[i + 1][j]++;  b[i + 1][j + 1]++;
                }else{
                    printf(".");
                }
            }
            printf("\n");
        }
        for(i = 0; i <= N + 1; i++){
            for(j = 0; j <= M + 1; j++){
                if(b[i][j] != 2){
                    a[i][j] = (b[i][j] == 3);
                }
                b[i][j] = 0;
            }
        }
    }
    return 0;
}

実行はぜひ皆さんの方で試してみてほしい

値の交換

変数a,bの値を交換するには、

a = b;b = a;  /* 駄目 */

では駄目である。余分な変数tempを使って

temp = a;a = b; b = temp;

とする。あるいはビットごとの排他的論理和を使って

b ^= a; a ^= b; b ^= a;

としてもよい。

#include<stdio.h>

void swap(int *x, int *y){
    int temp;

    temp = *x;  *x = *y;    *y = temp;
}
int main(void){
    int a = 1,  b = 2;
    printf("a = %d,b = %d\n",a,b);
    swap(&a, &b);
    printf("a = %d,b = %d\n",a,b);
}

実行してみる

a = 1,b = 2
a = 2,b = 1

簿記3級仕訳問題80本ノック(その1)

10問ずつ掲載しております

末尾の答えを押すと、解答と解説が表示されます。

問題 1

土地100,000円を購入し、仲介手数料2,000円、登記料3,000円とともに小切手を振り出して支払った。

借方科目 金額 貸方科目 金額
土地 105,000 * 当座預金 105,000

■ 土地を購入⇒土地(資産)の増加⇒借方

* 付随費用は固定資産の取得原価に含める

100,000円+2,000円+3,000円=105,000円

■ 小切手を振り出した⇒当座預金(資産)の減少⇒貸方

POINT !

固定資産を取得する際の付随費用には、仲介手数料、登記料、据付費、引取運賃などがあります。これらの付随費用は固定資産の取得原価に含めます。

問題 2

期首において、備品(取得原価1,000円、既償却額600円)を500円で売却し、代金は月末に受け取ることとした。なお、間接法により 記帳している。

借方科目 金額 貸方科目 金額
備品減価償却累計額 600 備品 1,000*
未収入金 500 固定資産売却益 100

■ 備品を売却した⇒備品(資産)の減少⇒貸方

 * 間接法により記帳⇒備品の取得原価1,000円を減らす

■ 間接法により記帳⇒備品減価償却累計額の減少⇒借方

■ 代金は月末に受け取る⇒未収入金(資産)の増加⇒借方

■ 貸借差額⇒貸方⇒固定資産売却益(収益)

  帳簿価額400円(1,000円-600円)よりも高い価額(500円)で売れた⇒売却益

問題 3

得意先島根商会が倒産し、同社に対する売掛金10,000円(前期に発生)が貸し倒れた。なお、貸倒引当金残高が8,000円ある。

借方科目 金額 貸方科目 金額
貸倒引当金 8,000 売掛金 10,000
貸倒損失 2,000

■ 前期の売掛金の貸倒れ(前期の債権には貸倒引当金が設定されている)⇒貸倒引当金(負債)の減少⇒借方

■ 貸倒引当金を超える分⇒貸倒損失(費用)の発生⇒借方

POINT !

前期に発生した売掛金の貸倒れについては、貸倒引当金勘定を減額し、それを超える分は貸倒損失勘定で処理します。

問題 4

現金の実際有高が帳簿残高より54,000円不足していたため、かねて現金過不足勘定で処理しておいたが、その原因を調査したところ、通信費124,000円が記入漏れであること、ならびに保険料の支払額225,000円を354,000円と誤記入していたことが判明した。なお、残 額については原因不明のため、雑損または雑益として処理することとした。

借方科目 金額 貸方科目 金額
通信費 124,000 現金過不足 54,000
雑損 59,000 *2 保険料 129,000*1

■ 通信費の未記帳⇒現金過不足の減少

■ 保険料の修正⇒現金過不足の増加

■ 現金過不足の雑損への振り替え⇒現金過不足の減少

 *1 354,000円-225,000円=129,000円

 *2 54,000円+129,000円-124,000円=59,000円

問題 5

大阪商事から商品1,000,000円を仕入れた。注文時に手付金500,000円を支払っており、差し引いた残額については約束手形を振り出して支払った。

借方科目 金額 貸方科目 金額
仕入 1,000,000 前払金 500,000
支払手形 500,000*

■ 商品の引き取り⇒仕入(費用)の発生⇒借方

■ 手付金を差し引く⇒前払金(資産)の減少⇒貸方

約束手形の振り出し⇒支払手形(負債)の増加⇒貸方

 * 1,000,000円-500,000円=500,000円

問題 6

先月の従業員給料から差し引いた所得税源泉徴収税額190,000円を、現金で納付した。

借方科目 金額 貸方科目 金額
所得税預り金 190,000 現金 190,000

■ 現金で納付⇒現金(資産)の減少⇒貸方

所得税預り金の納付⇒所得税預り金(負債)の減少⇒借方

POINT !

源泉所得税の預り金を預り金勘定で処理することもあります。

問題 7

出張中の社員から、当座預金口座に10,000円が入金されたが、その内容は不明である。

借方科目 金額 貸方科目 金額
当座預金 10,000 仮受金 10,000

当座預金口座に入金⇒当座預金(資産)の増加⇒借方

■ 入金の内容は不明⇒仮受金(負債)の増加⇒貸方

問題 8

松山商事は商品480,000円を売り上げ、代金を山下商事の商品券で受け取った。

借方科目 金額 貸方科目 金額
受取商品券 480,000 売上 480,000

■ 商品の売り上げ⇒売上(収益)の増加⇒貸方

■ 受取商品券の受け取り⇒受取商品券(資産)の増加⇒借方

問題 9 4月27日 会計係は小口現金係から次のような支払いの報告を受けたので、ただちに小切手を振り出して小口現金を補給した。 通信費4,000円、旅費交通費20,000円、消耗品費3,000円

借方科目 金額 貸方科目 金額
通信費 4,000 当座預金 27,000
旅費交通費 20,000
消耗品費 3,000

■ ただちに小切手を振り出して補給⇒ 当座預金(資産)の減少⇒貸方

■ 支払いの報告

  通信費(費用)の発生⇒借方

  旅費交通費(費用)の発生⇒借方

  消耗品費(費用)の発生⇒借方

問題 10 内容不明の仮受金300円は、津田沼商会から注文を受けた際の手付金の受取額100円と水道橋商事に対する掛け代金の回収額200円であ ることが判明した。

借方科目 金額 貸方科目 金額
仮受金 300 前受金 100
    売掛金 200

■ 仮受金(負債)の内容判明⇒仮受金(負債)の減少⇒借方

■ 手付金と判明⇒前受金(負債)の増加⇒貸方

■ 掛け代金の回収と判明⇒売掛金(資産)の減少⇒貸方