忍者ブログ
なんとなくだらだらと。方向性はまだ決まってない。 当方のプログラムでは、山田巧さん作成のDXライブラリを利用させていただいてます。 本サイト http://homepage2.nifty.com/natupaji/DxLib/index.html DX Library Copyright (C) 2001-2008 Takumi Yamada.
[63] [62] [61] [60] [59] [58] [57] [56] [55] [54] [53]
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

やったね、たえちゃん!


DXライブラリと言えば、ウインドウモードでの動作とマウスの反応の遅さにうんざり
してたんだけど、このバージョンアップでスッキリ解決!

DXライブラリ内で使用しているDirectXのバージョンが7.1から9.0に上がったとのこと。
3D関連の関数がすごい増えてるみたい。まだちょっとしか見てないけど。
今まで作ったプログラムに関しては、そのまんまで動く。
コンパイルやりなおすだけで、処理落ちなしですごい快適に動くようになった。

そろそろ自分でDirectX用のライブラリ作らないとと思ってたんだけど、これで
もうしばらくはDXライブラリで遊べる。


v010

ダウンロード http://hiyayakko.sarashi.com/MaruBatu/MB011.zip (2009.09.06)


さて、お膳立てもできたことだし、CPUの思考ルーチンに入ろうか。

まずは、自分にリーチがかかってるとき、「次にここに置いたら勝ち」の状態で
手番がまわってきたら・・・
迷わずそこに置いて問題ないよな。

次に相手がリーチかけてきたとき。
これも放置したら次のターンで相手が勝つことになるので、全力で阻止。

進むべき道をいちど言葉にして、目標地点を確認しよう。

main.cpp



// CPU思考ルーチン
void CpuTurn()
{
    int bx,by;
    // (1)次に自分が勝てる手があれば迷わずそこへ置く
    if(CheckDouble(game.Player,bx,by)){
        board[by][bx]=game.Player;
        ChangeTurn();
        return;
    }

    // (2)相手からのリーチは阻止
    if(CheckEnemyDouble(game.Player,bx,by)){
        board[by][bx]=game.Player;
        ChangeTurn();
        return;
    }

    while(1){
        bx = GetRand(2);
        by = GetRand(2);

 



骨子はこんな感じ。
いろいろ考えた結果、リーチ状態を調べる関数は、bool成否判断だけではできない感じ。
リーチがかかってたら、次に打つべき位置をbx、byで返すように。


で、実際にリーチ状態かどうか調べる。

main.cpp

// 指名プレイヤーが2連のラインを作ってるか調べる
bool CheckDouble(Board player,int &bx, int &by)
{
    int x,y,ch;
    // 横ラインのチェック
    for(y=0;y<3;y++){
        ch = 0;
        for(x=0;x<3;x++){
            if(board[y][x]==player)ch++;        // 捜査点が対象プレイヤーならch+1
            else if(board[y][x]!=NONE)ch+=3;    // それ以外で空白でもなければこのラインは破棄
        }
        if(ch==2){                              // ch==2 player駒2マス+空白の組み合わせのとき
            for(x=0;x<3;x++){
                if(board[y][x]==NONE){
                    bx = x;
                    by = y;
                    return true;
                }
            }
        }
    }
    // 縦ラインのチェック
    for(x=0;x<3;x++){
        ch = 0;
        for(y=0;y<3;y++){
            if(board[y][x]==player)ch++;        // 捜査点が対象プレイヤーならch+1
            else if(board[y][x]!=NONE)ch+=3;    // それ以外で空白でもなければこのラインは破棄
        }
        if(ch==2){                              // ch==2 player駒2マス+空白の組み合わせのとき
            for(y=0;y<3;y++){
                if(board[y][x]==NONE){
                    bx = x;
                    by = y;
                    return true;
                }
            }
        }
    }
    // 斜めライン(左上→右下)のチェック
    ch=0;
    for(x=0;x<3;x++){
        if(board[x][x]==player)ch++;
        else if(board[x][x]!=NONE)ch+=3;
    }
    if(ch==2){                              // ch==2 player駒2マス+空白の組み合わせのとき
        for(y=0;y<3;y++){
            if(board[y][y]==NONE){
                bx = y;
                by = y;
                return true;
            }
        }
    }
    // 斜めライン(右上→左下)のチェック
    ch=0;
    for(x=0;x<3;x++){
        if(board[x][2-x]==player)ch++;
        else if(board[x][2-x]!=NONE)ch+=3;
    }
    if(ch==2){                              // ch==2 player駒2マス+空白の組み合わせのとき
        for(y=0;y<3;y++){
            if(board[y][2-y]==NONE){
                bx = 2-y;
                by = y;
                return true;
            }
        }
    }
    // ここまで条件に合うもの無し
    return false;
}


なんかダラっと長い、はずかし気味のプログラムになってしまったか。
大きく分けて、「縦チェック」「横チェック」「斜め左上→右下」「斜め右上→左下」の4パターン。
縦チェックだと、まずfor(x=0~2)で調べたいラインを決めて、下に向かってボードの状態を
拾っていく。
調べているプレイヤーの駒が入ってたら、チェック変数chを+1。
これが1ラインで2になったら、そのラインに自分の駒が2個入っているというわけ。
でも、残り1個に相手側の駒が入ってたら、阻止されたラインということで意味無いから
相手側の駒を見つけ次第、チェック変数ch に適当な数を入れてチェックを台無しにしてしまう。

で、ch=2のラインを見つけたら、そのラインの中で空白のマスを探す。
見つけたら、bx、by にその値を入れてtrueを返す。
こういう、for文の途中で抜け出す書き方とか、関数の途中でいろいろ抜け道を作るやり方は
あまりよくないと思います!



それはさておき、これで自分のリーチ状態が判断できたわけだ。
同じように、敵のリーチ状態も調べてみる。
自分(CPU)が○側なら×を、逆なら逆を調べる。
この判断がだらっと長くなるかと思って別関数を用意したけど、そんなこともなかったぜ。
調べるプレイヤーを入れ替えて、先のCheckDouble() 関数を呼ぶ。
何か返ってきたら、盲目的にそこに置いて差し支えなかろう。

main.cpp

// 敵がリーチ状態か調べる
bool CheckEnemyDouble(Board player, int &bx, int &by){
    Board enemy;
    if(player == MARU)enemy=BATU;
    else enemy = MARU;
    if(CheckDouble(enemy,bx,by))return true;
    else return false;
}



今日の思考ルーチンはここまで。
相手のターンにまわす部分を関数にして追い出す。
ここはプレイヤーの行動判断のところでも同じことやってたから、気になってた。

main.cpp

// ターンの入れ替え
void ChangeTurn()
{
    if(game.Player==MARU) game.Player = BATU;
    else game.Player = MARU;

    if(game.Scene == PLAYER_TURN)game.Scene = CPU_TURN;
    else game.Scene = PLAYER_TURN;  // 手番を入れ替える

    game.Turn ++;                   // +1ターン進める
    Judge();                       // 判定

}

void GamePlay()
{
    if(game.MouseClick == true){            // マウスクリックがあったとき
        if((mp.x<0)&&(mp.y<0))return;       // マウスクリックの有効判定
        if(board[mp.y][mp.x]==NONE){        // カーソル位置の盤面が空白なら
            board[mp.y][mp.x]=game.Player;   // 手番のひとのカーソルを置く
            ChangeTurn();
            //if(game.Player==MARU) game.Player = BATU;
            //else game.Player = MARU;
            //if(game.Scene == PLAYER_TURN)game.Scene = CPU_TURN;
            //else game.Scene = PLAYER_TURN;  // 手番を入れ替える
            //game.Turn ++;                   // +1ターン進める
        }
    }
    //Judge();
}
    :
    :

// CPU思考ルーチン
void CpuTurn()
{
    int bx,by;
    // (1)次に自分が勝てる手があれば迷わずそこへ置く
    if(CheckDouble(game.Player,bx,by)){
        board[by][bx]=game.Player;
        ChangeTurn();
        return;
    }

    // (2)相手からのリーチは阻止
    if(CheckEnemyDouble(game.Player,bx,by)){
        board[by][bx]=game.Player;
        ChangeTurn();
        return;
    }

    while(1){
        bx = GetRand(2);
        by = GetRand(2);
        if(board[by][bx]==NONE){
            board[by][bx]=game.Player;   // 手番のひとのカーソルを置く
            ChangeTurn();
            //if(game.Player==MARU) game.Player = BATU;
            //else game.Player = MARU;
            //if(game.Scene == PLAYER_TURN)game.Scene = CPU_TURN;
            //else game.Scene = PLAYER_TURN;  // 手番を入れ替える
            //game.Turn ++;                   // +1ターン進める
            //Judge();
            break;
        }
    }
}
 



あと、いかにもダサい Hantei() 関数名を、Judge() に変更した。
この呼び出しは、普通に考えたらターンの入れ替え時だけでいい。
今まであちこちに書き散らしてたのが恥ずかしくなる。



ブログエントリ
○×ゲームを作る(1)
http://http://hiyayakkoprog.blog.shinobi.jp/Entry/53/

ダウンロードHP
http://hiyayakko.sarashi.com/Marubatu/MaruBatu.html

したらば掲示板
http://jbbs.livedoor.jp/bbs/read.cgi/computer/42268/1251347335/-100

PR


忍者ブログ [PR]
カレンダー
03 2025/04 05
S M T W T F S
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
フリーエリア
バーコード
ブログ内検索
P R
アクセス解析
カウンター