なんとなくだらだらと。方向性はまだ決まってない。
当方のプログラムでは、山田巧さん作成のDXライブラリを利用させていただいてます。
本サイト http://homepage2.nifty.com/natupaji/DxLib/index.html
DX Library Copyright (C) 2001-2008 Takumi Yamada.
× [PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
勝ちパターンの計算については、だいたい文章化できたかな?
1.自分のコマの上下左右斜め列に+10点 2.相手のコマの上下左右斜め列に-10点 3.4隅は無条件に+1点 4.中央を開けて○と×がにらみ合いになったときは、残る角に+15点 ※ 5.1列に自分のコマがふたつあるときは、残りの空白列に+100点 ここに置いたら勝ちなので、最優先でここに置く。 6.1列に相手のコマがふたつあるときは、残りの空白列に+80点 ここを残して相手にまわしたら負けるので、条件5の次に優先 このルールで盤面計算しなおして、再検証してみる。 ケース4 対角 いきなりルール3の「角は+1点」忘れてるけど。 このケース4のためにルール4追加したんだから、うまくいってもらわないと困る。 4手目×はリーチ阻止でここ一拓。 5手目の決定も、この新ルールで予想外にうまくいった。 角3つ押さえた形でダブルリーチ。これで勝ち。 ケース3 辺の角 いちばん素直な形じゃないかな。 10点のところが1マス。ここに置いてみる。 4手目の×の人は、リーチ阻止するしかない。 で、5手目は×のリーチ阻止が○側のダブルリーチになる。確定。 ケース2 桂馬飛び これも、この日のために追加したルール3「角は+1点」をフル活用。 3手目は左下隅に確定。 あとは×側リーチ阻止 → ○側リーチ阻止 の、5手目でダブルリーチ。 ケース1 接辺 処理ごまかしてる。 ホントは対角になる右下ではなく左下を優先しないといけないんだけど。 なんかうまく出来てしまった。 4手目の×はリーチ阻止するしかない。 で、5手目はいちばん点数の高い右下でダブルリーチ。すなわち勝利確定。 いいんじゃね? なかなか、いい感じじゃね? プログラム組む前は、いちど仮置きして、×側から評価しないといけないと読んでた。 ここに置いたら相手がこう置く。そう来たらこう返すみたいな感じの3手読み。 それが盤面に点数つけていちばんいいところに置けば済むんだから、うまく出来たと自画自賛。 main.cpp // CPU思考ルーチン void CpuTurn() { int x,y; int bx,by; // 点数評価テーブル int tb[3][3]={0}; int c=-99; // (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; } // 4隅にゲタをはかせる tb[0][0]++; tb[0][2]++; tb[2][0]++; tb[2][2]++; // 2ターン目、×側は中央が空いてたら最優先 if(game.Turn==1)tb[1][1]+=50; // 評価点加点 for(y=0;y<3;y++){ for(x=0;x<3;x++){ if(board[y][x]==game.Player){ for(int i=0;i<3;i++){ tb[y][i]+=10; tb[i][x]+=10; } if(x==y){ tb[0][0]+=10; tb[1][1]+=10; tb[2][2]+=10; } if(((x-y)*(y-x)==-4)||(x==1&&y==1)){ tb[0][2]+=10; tb[1][1]+=10; tb[2][0]+=10; } } else if(board[y][x]!=NONE){ for(int i=0;i<3;i++){ tb[y][i]-=10; tb[i][x]-=10; } if(x==y){ tb[0][0]-=10; tb[1][1]-=10; tb[2][2]-=10; } if(((x-y)*(y-x)==-4)||(x==1&&y==1)){ tb[0][2]-=10; tb[1][1]-=10; tb[2][0]-=10; } } } } // 対角でにらみあいが発生したときは角の優先度を上げる if(((board[0][0]!=NONE)&&(board[1][1]==NONE)&&(board[2][2]!=NONE))|| ((board[0][2]!=NONE)&&(board[1][1]==NONE)&&(board[2][0]!=NONE))) { tb[0][0]+=15; tb[0][2]+=15; tb[2][0]+=15; tb[2][2]+=15; } // 評価点のいちばん高いポイントを探す bx = by = c = -99; for(y=0;y<3;y++){ for(x=0;x<3;x++){ if((board[1][1]!=game.Player)&&(tb[y][x]==0))continue; if((board[y][x]==NONE)&&(tb[y][x]>c)){ bx = x; by = y; c = tb[y][x]; } } } if(c!=-99){ board[by][bx]=game.Player; ChangeTurn(); } else { // ここに来ることはない。はず! while(1){ bx = GetRand(2); by = GetRand(2); if(board[by][bx]==NONE){ board[by][bx]=game.Player; // 手番のひとのカーソルを置く ChangeTurn(); break; } } } } この、冒頭のルールを頭に入れてたら、この意味不明のソースが ちょっとは輝いて見えるようになってると思うがどうか。 ルール再掲載 1.自分のコマの上下左右斜め列に+10点 2.相手のコマの上下左右斜め列に-10点 3.4隅は無条件に+1点 4.中央を開けて○と×がにらみ合いになったときは、残る角に+15点 ※ 5.1列に自分のコマがふたつあるときは、残りの空白列に+100点 ここに置いたら勝ちなので、最優先でここに置く。 6.1列に相手のコマがふたつあるときは、残りの空白列に+80点 ここを残して相手にまわしたら負けるので、条件5の次に優先 で、前に作ったリーチ状態の確認を盤面評価にうまく組み込めるかと目論んでたんだけど、 だらっと長くなったルール1、2、「評価点加点」の部分がさらに長くなりそうなので 前作った部分をそのまま流用することにした。 ここまででCPU思考ルーチンのだいたい8割は説明できたかな。 あと、2手目で中央に置かれたときと×を受け持ったとき用の、いやらしい微調整だけ。 ブログエントリ ○×ゲームを作る(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 |
カレンダー
カテゴリー
フリーエリア
最新記事
(01/29)
(01/28)
(01/26)
(12/28)
(12/27)
(12/25)
(12/20)
(09/09)
(09/09)
(09/09)
(09/08)
(09/08)
(09/08)
(09/06)
(09/05)
(08/27)
(08/27)
(08/27)
(08/25)
(08/23)
ブログ内検索
P R
アクセス解析
カウンター
|