#include #include #include #include #include #include "MfcKatsunariDoc.h" //#define BOARD_SIZE 11 //#define PURE_BOARD_SIZE 9 //#define SPACE 0 //#define BLACK 1 //#define WHITE 2 #//define OB 3 #define TRUE 1 #define FALSE 0 typedef int BOOL; int Ban[BOARD_SIZE][BOARD_SIZE]; int Eval[BOARD_SIZE][BOARD_SIZE]; int ko_x,ko_y,ko_num; static void ColorClear(int size); //static int WhichColor(int x,int y,int BoardSize,int Ban[BOARD_SIZE][BOARD_SIZE]); //static int Keisei(int Ban[BOARD_SIZE][BOARD_SIZE]); /*int mcts(int *x, int *y, int Ban[BOARD_SIZE][BOARD_SIZE], int Eval[BOARD_SIZE][BOARD_SIZE], int color, int move);*/ int mcts(int* x, int* y, int pos_array[BOARD_SIZE*BOARD_SIZE], int color, int size, int ko_x , int ko_y, int playout, int komi); #define BL_AREA 7 #define WH_AREA 8 #define BL_DEAD 17 #define WH_DEAD 18 //extern "C" void initAll(); // 全体の初期化 void initAll() { // 実は、ここでsrandしても意味がないらしい。 // というのは、initAllは思考の本体と別スレッドで動くからで、どうもスレッド毎にsrandしないといけないようだ。 srand((unsigned)time(NULL)); _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_CHECK_ALWAYS_DF|_CRTDBG_LEAK_CHECK_DF); } // 既に盤上のこの位置をチェック済みかどうか。 int check[BOARD_SIZE][BOARD_SIZE]; // x,yの位置にあるcolor色の石を、隣接する石も含めて再帰的に取り除き、取り除いた石の数を返す int DoRemoveRecursive(int x,int y,int color,int board[BOARD_SIZE][BOARD_SIZE],int size) { int ret=0; if (check[y][x]) return 0; check[y][x]=1; if (y<1 || x<1 || x>size/*PURE_BOARD_SIZE*/||y>size/*PURE_BOARD_SIZE*/) return 0; if( board[y][x] == color ){ if (x>1) { ret+=DoRemoveRecursive(x-1, y, color,board,size); } if (y>1) { ret+=DoRemoveRecursive(x, y-1, color,board,size); } if (xsize/*PURE_BOARD_SIZE*/||y>size/*PURE_BOARD_SIZE*/) return TRUE; if (board[y][x]==SPACE) return FALSE; if( board[y][x] == color ){ if (x>1) { if (!CheckRemoveRecursive(x-1, y, color,board, size)) { return FALSE; } } if (y>1) { if (!CheckRemoveRecursive(x, y-1, color,board, size)) { return FALSE; } } if (x1 && board[y][x-1]==opp && CheckRemove(x-1,y,opp,board)) ) return FALSE; // if ( (y>1 && board[y-1][x]==opp && CheckRemove(x,y-1,opp,board)) ) return FALSE; // if ( (x PURE_BOARD_SIZE || x < 1 || y > PURE_BOARD_SIZE || y < 1 ){ // return( FALSE ); /* FALSE=0 */ // } // パス(x,yともに0)はいつでもOK。 // if( (x == 0) || (y == 0) ){ // パス // return( TRUE ); // } // 何か既に置いてあったら置けない // if (Ban[y][x]!=SPACE) return FALSE; // コウのチェック:コウなら置けない // if (ko_x==x && ko_y==y && ko_num==move-1) return FALSE; // 自殺手のチェック:自殺手なら置けない // if (checkSuicide(x,y,color,board)) return FALSE; // return TRUE; //} //extern "C" int setStoneOnGameBoard(int x,int y,int color,int move); // ユーザが指した手および自分の指した手を盤に置く // 盤上の指定された位置x,yにcolor色の石を置く。 // 必要なら、それによって取られる石を取り除いたり、コウになっているかどうかのチェックもする。 int setStoneOnGameBoard(int x,int y,int color,int move,int size) { int ret=0; int tmpBoard[BOARD_SIZE][BOARD_SIZE]; // 敵の色 int opp=(color==WHITE)?BLACK:WHITE; // 石は、ひとつだけ(隣接する同じ色の石がない)か? BOOL isSingleStone=TRUE; if (Ban[y-1][x]==color || Ban[y+1][x]==color || Ban[y][x+1]==color || Ban[y][x-1]==color) { isSingleStone=FALSE; } memcpy(tmpBoard,Ban,sizeof(Ban)); // 石を置いてみる Ban[y][x]=color; // 置いたことによって、取り除かれる石がいくつあるか数えながら石を取り除く if (CheckRemove(x+1,y,opp,Ban,size)) { ret+=DoRemove(x+1,y,opp,Ban,size); } if (CheckRemove(x-1,y,opp,Ban,size)) { ret+=DoRemove(x-1,y,opp,Ban,size); } if (CheckRemove(x,y+1,opp,Ban,size)) { ret+=DoRemove(x,y+1,opp,Ban,size); } if (CheckRemove(x,y-1,opp,Ban,size)) { ret+=DoRemove(x,y-1,opp,Ban,size); } // 石が一つだけで、取った石の数が1つならば、コウ if (ret==1 && isSingleStone) { // コウの起きた手番 ko_num=move; // どこを取った?取った位置ko_x,ko_yがコウで次の手番の着手禁止点になる。 if (Ban[y][x+1]==SPACE && tmpBoard[y][x+1]!=SPACE) { ko_x=x+1; ko_y=y; } if (Ban[y][x-1]==SPACE && tmpBoard[y][x-1]!=SPACE) { ko_x=x-1; ko_y=y; } if (Ban[y+1][x]==SPACE && tmpBoard[y+1][x]!=SPACE) { ko_x=x; ko_y=y+1; } if (Ban[y-1][x]==SPACE && tmpBoard[y-1][x]!=SPACE) { ko_x=x; ko_y=y-1; } } // 一応、取った石の数を返しているが、UIの方でも処理しているので実は何でも良い return ret; } //extern "C" void clearGameBoard(); // 盤をクリアする void clearGameBoard(int boardSize) { int x,y; ko_x=ko_y=ko_num=0; for(y=0;y= color*3) { // さらに斜め方向に3つ以上「石があるか、または盤外」ならば眼形。 return TRUE; } } return FALSE; } // 自分の地かどうかチェックする //int checkMyJi(int x,int y,int color) //{ // int tmpBoard[BOARD_SIZE][BOARD_SIZE]; // memcpy(tmpBoard,Ban,sizeof(Ban)); // 最初に、この関数を呼んで、地の形を認識させる // Keisei(tmpBoard); // 次に、x,yの位置がどちらの色の地(または中立)か判定する。 // if (WhichColor(x,y,PURE_BOARD_SIZE,tmpBoard)==color) { // return TRUE; // } // return FALSE; //} //extern "C" char *selectNextMove(int *x,int *y,int *eval,int color,int move,int kind); // 現在の盤を見て次の一手を返す char *selectNextMove(int *x,int *y,int *eval,int color,int move/*,int kind*/,int ko_x_in, int ko_y_in, int ko_move, int size, int playout, int komi) { int xx,yy; // int retx,rety; // int val; int r; int pos_array[BOARD_SIZE*BOARD_SIZE]; if (ko_move==move-1) { ko_x = ko_x_in; ko_y = ko_y_in; }else{ ko_x = 0; ko_y = 0; } // ここで乱数のシードを初期化する。 /*srand((unsigned)time(NULL));*/ // checkMyJiのための初期化 /*ColorClear();*/ // ルール上新たに石を置けないところは-1,自分の地になっているか、眼形をつぶしてしまうところは-1000 // それ以外ならランダムな数値を入れる /*for(yy=1;yy<=PURE_BOARD_SIZE;yy++) { for(xx=1;xx<=PURE_BOARD_SIZE;xx++) { if (checkSetStoneGameBoard(xx,yy,color,move)) { if (checkMetubushi(xx,yy,color) || checkMyJi(xx,yy,color)) { Eval[yy][xx]=-1000; } else { Eval[yy][xx]=rand()%256; } } else { Eval[yy][xx]=-1; } } }*/ // 上記だけではランダムになりきらないので、さらに乱数を適当に加える /*for(r=0;r<50;r++) { yy=(rand()%PURE_BOARD_SIZE)+1; xx=(rand()%PURE_BOARD_SIZE)+1; // でもやはり眼は潰さない。 if (checkMetubushi(xx,yy,color)) continue; // 相手の地には加点しない if (checkMyJi(xx,yy,color==BLACK?WHITE:BLACK)) continue; // 打てる場所かどうかチェックして、 if (checkSetStoneGameBoard(xx,yy,color,move)) { Eval[yy][xx]+=rand()%256; } }*/ // モンテカルロ木探索 /*mcts(x, y, Ban, Eval, color, move);*/ /* 入力位置情報変換 */ r = 0; for(yy=0;yyval) { val=Eval[yy][xx]; rety=yy; retx=xx; } } } *x=retx; *y=rety;}*/ // *eval=val; *eval = 0; return "らんだむ"; // 返り値は、選んだ根拠。らんだむに選んでいるので"らんだむ"。 } //extern "C" int copyEvaluation(int buf[][BOARD_SIZE]); // selextNextMoveの後、盤上の各指し手の評価値を返す void copyEvaluation(int buf[BOARD_SIZE][BOARD_SIZE], int size) { int x,y; for(y=0;y