/* ファイルから盤面図を読み込み, 黒番の次の一手を返すプログラム*/
#include
#include
#include
#define TRUE 1
#define FALSE 0
#define SPACE 0 /* 空点 */
#define BLACK 1 /* 黒石 */
#define WHITE 2 /* 白石 */
#define OB 3 /* 盤外 */
#define BOARD_SIZE ( 19 + 2 ) /* 碁盤の大きさ */
/* 相手の色 */
#define reverseColor( color ) ( color == BLACK ? WHITE : BLACK )
/*------------------------------------------------------------------*/
/* 関数 */
/*------------------------------------------------------------------*/
/* メイン関数 */
int main( int argc, char *argv[] );
/* 盤面図入力 */
void InputFigure( int board[][BOARD_SIZE] );
/* 碁盤の初期化 */
void InitializeBoard( int board[][BOARD_SIZE] );
/* 碁盤を表示する */
void DisplayBoard( int board[][BOARD_SIZE] );
/* 次の一手を求める */
void ThinkMove( int board[][BOARD_SIZE], int color, int *x, int *y );
/* 盤面の評価 */
int EvalBoard( int board[][BOARD_SIZE] );
/* 地の設定 */
void SetValue( int board[][BOARD_SIZE], int x, int y );
/* 合法手がどうか調べる */
int CheckLegal( int board[][BOARD_SIZE], int color, int x, int y );
/* 自殺手かどうか調べる */
int CheckSuicide( int board[][BOARD_SIZE], int color, int x, int y );
/* チェック用の碁盤をクリア */
void ClearCheckBoard( void );
/* 相手に囲まれているか調べる */
int DoCheckRemoveStone( int board[][BOARD_SIZE],
int color, int x, int y );
/* 碁盤を複写 */
void CopyBoard( int source[][BOARD_SIZE],
int copied[][BOARD_SIZE] );
/* 碁盤に石を置く*/
void SetStone( int board[][BOARD_SIZE], int color, int x, int y );
/* 囲まれた石を取り除く */
int RemoveStone( int board[][BOARD_SIZE],
int color, int x, int y );
/* 囲まれた石を取り除く */
int DoRemoveStone( int board[][BOARD_SIZE],
int color, int x, int y, int prisoner );
/*------------------------------------------------------------------*/
/* 変数 */
/*------------------------------------------------------------------*/
/* 碁盤の表示のための文字 */
static char stone[] = { '+', '@', 'O', '?' };
/* 合法手かどうか調べるのに使う */
static int checkBoard[BOARD_SIZE][BOARD_SIZE];
/*------------------------------------------------------------------*/
/* メイン関数 */
/*------------------------------------------------------------------*/
int
main( int argc, char *argv[] )
{
int board[BOARD_SIZE][BOARD_SIZE]; /* 碁盤 */
int xBlack, yBlack; /* 黒の着手位置 */
/* 盤面図の入力 */
InputFigure( board );
/* 碁盤の表示 */
DisplayBoard( board );
/* 黒の次の一手を求める */
ThinkMove( board, BLACK, &xBlack, &yBlack );
/* 結果の表示 */
printf( "Computer -> (%2d,%2d)\n", xBlack, yBlack );
return EXIT_SUCCESS;
}
/*------------------------------------------------------------------*/
/* 盤面図入力 */
/* ファイル名"figure"というファイルに盤面図が書かれている */
/* 劫による着手禁止点はないものとする */
/*------------------------------------------------------------------*/
void
InputFigure( int board[][BOARD_SIZE] )
{
FILE *fp;
char buf[256];
int x, y, i;
fp = fopen("./figure.txt","rt");
/* ファイルを開く */
if ( !fp ){
fprintf( stderr, "ERROR: file(figure) open fail\n" );
exit(1);
}
/* 碁盤の初期化 */
InitializeBoard( board );
/* 各座標を読む */
for( y=1; y < (BOARD_SIZE-1); y++ ){
buf[0] = '\0';
fgets( buf, 256, fp );
for( x=1, i=0; x < (BOARD_SIZE-1); x++ ){
if( buf[i] == 'O' ){
board[y][x] = WHITE;
}else if( buf[i] == '@' ){
board[y][x] = BLACK;
}else if( buf[i] == '+' ){
board[y][x] = SPACE;
}else{
board[y][x] = SPACE;
}
i++;
}
}
/* ファイルを閉じる */
fclose( fp );
}
/*------------------------------------------------------------------*/
/* 碁盤の初期化 */
/*------------------------------------------------------------------*/
void
InitializeBoard( int board[][BOARD_SIZE] )
{
int x, y;
for( y=1; y < (BOARD_SIZE-1); y++ ){
for( x=1; x < (BOARD_SIZE-1); x++ ){
board[y][x] = SPACE;
}
}
for( y=0; y < BOARD_SIZE; y++ ){
board[y][0]= OB;
board[y][BOARD_SIZE-1] = OB;
board[0][y] = OB;
board[BOARD_SIZE-1][y] = OB;
}
}
/*------------------------------------------------------------------*/
/* 碁盤を表示する */
/*------------------------------------------------------------------*/
void
DisplayBoard( int board[][BOARD_SIZE] )
{
int x, y;
printf( " [ 1 2 3 4 5 6 7 8 910111213141516171819]\n" );
for( y=1; y < (BOARD_SIZE-1); y++ ){
printf( "[%2d] ", y );
for( x=1; x < (BOARD_SIZE-1); x++ ){
int index = board[y][x];
printf( " %c", stone[index] );
}
printf( "\n" );
}
printf( "\n" );
}
/*------------------------------------------------------------------*/
/* 次の一手を求める */
/*------------------------------------------------------------------*/
void
ThinkMove( int board[][BOARD_SIZE],
int color, int *xBlack, int *yBlack )
{
int tmpBoard[BOARD_SIZE][BOARD_SIZE]; /* 複写用碁盤 */
int evalBoard[BOARD_SIZE][BOARD_SIZE]; /* 評価値格納用碁盤 */
int resultX, resultY;
int x, y;
int eval, init_eval, max_eval;
/* 評価値格納用碁盤の初期化 */
for( y=1; y < (BOARD_SIZE-1); y++ ){
for( x=1; x < (BOARD_SIZE-1); x++ ){
evalBoard[y][x] = 0;
}
}
/* 盤面の評価 */
init_eval = EvalBoard( board );
/* 候補手を仮りに盤上に打って評価 */
for( y=1; y < (BOARD_SIZE-1); y++ ){
for( x=1; x < (BOARD_SIZE-1); x++ ){
/* 着手禁止点なら次の点へ */
if( CheckLegal( board, color, x, y ) == FALSE ){
continue;
}
/* 碁盤を複写 */
CopyBoard( board, tmpBoard );
/* 候補手を盤上に打つ */
SetStone( tmpBoard, color, x, y );
/* 着手後の盤面の評価 */
eval = EvalBoard( tmpBoard );
/* 着手前より何目良くなったかを評価値格納用碁盤に記録 */
evalBoard[y][x] = eval - init_eval;
}
}
/* 評価値を表示する */
printf( " [ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19]\n" );
for( y=1; y < (BOARD_SIZE-1); y++ ){
printf( "[%2d] ", y );
for( x=1; x < (BOARD_SIZE-1); x++ ){
printf( "%3d", evalBoard[y][x] );
}
printf( "\n" );
}
/* 評価値が最高のものを選ぶ */
max_eval = 0;
resultX = resultY = 0;
for( y=1; y < (BOARD_SIZE-1); y++ ){
for( x=1; x < (BOARD_SIZE-1); x++ ){
if( max_eval < evalBoard[y][x] ){
max_eval = evalBoard[y][x];
resultX = x;
resultY = y;
}
}
}
*xBlack = resultX;
*yBlack = resultY;
}
/*------------------------------------------------------------------*/
/* 盤面の評価 */
/*------------------------------------------------------------------*/
int
EvalBoard( int board[][BOARD_SIZE] )
{
int blackBoard[BOARD_SIZE][BOARD_SIZE]; /* 黒石の影響範囲 */
int whiteBoard[BOARD_SIZE][BOARD_SIZE]; /* 白石の影響範囲 */
int totalBoard[BOARD_SIZE][BOARD_SIZE]; /* 地 */
int x, y, value;
/* 初期化 */
for( y=1; y < (BOARD_SIZE-1); y++ ){
for( x=1; x < (BOARD_SIZE-1); x++ ){
blackBoard[y][x] = 0;
whiteBoard[y][x] = 0;
totalBoard[y][x] = SPACE;
}
}
for( y=1; y < (BOARD_SIZE-1); y++ ){
for( x=1; x < (BOARD_SIZE-1); x++ ){
if( board[y][x] == BLACK ){
/* 黒石から距離2以内の点にマークを付ける */
SetValue( blackBoard, x-2, y );
SetValue( blackBoard, x-1, y-1 );
SetValue( blackBoard, x-1, y );
SetValue( blackBoard, x-1, y+1 );
SetValue( blackBoard, x, y-2 );
SetValue( blackBoard, x, y-1 );
SetValue( blackBoard, x, y );
SetValue( blackBoard, x, y+1 );
SetValue( blackBoard, x, y+2 );
SetValue( blackBoard, x+1, y-1 );
SetValue( blackBoard, x+1, y );
SetValue( blackBoard, x+1, y+1 );
SetValue( blackBoard, x+2, y );
}else if( board[y][x] == WHITE ){
/* 白石から距離2以内の点にマークを付ける */
SetValue( whiteBoard, x-2, y );
SetValue( whiteBoard, x-1, y-1 );
SetValue( whiteBoard, x-1, y );
SetValue( whiteBoard, x-1, y+1 );
SetValue( whiteBoard, x, y-2 );
SetValue( whiteBoard, x, y-1 );
SetValue( whiteBoard, x, y );
SetValue( whiteBoard, x, y+1 );
SetValue( whiteBoard, x, y+2 );
SetValue( whiteBoard, x+1, y-1 );
SetValue( whiteBoard, x+1, y );
SetValue( whiteBoard, x+1, y+1 );
SetValue( whiteBoard, x+2, y );
}
}
}
/* 地の合計(黒地が多ければプラス,白地が多ければマイナスになる) */
value = 0;
/* 各点がどちらのマークか調べる */
for( y=1; y < (BOARD_SIZE-1); y++ ){
for( x=1; x < (BOARD_SIZE-1); x++ ){
if( board[y][x] == BLACK ){
totalBoard[y][x] = BLACK;
}else if( board[y][x] == WHITE ){
totalBoard[y][x] = WHITE;
}else{
if( blackBoard[y][x] > whiteBoard[y][x] ){
/* 黒からの影響度の方が大きいので白地である */
totalBoard[y][x] = BLACK;
value++;
}else if( blackBoard[y][x] < whiteBoard[y][x] ){
/* 白からの影響度の方が大きいので白地である */
totalBoard[y][x] = WHITE;
value--;
}
}
}
}
return( value );
}
/*------------------------------------------------------------------*/
/* 地の設定 */
/*------------------------------------------------------------------*/
void
SetValue( int board[][BOARD_SIZE], int x, int y )
{
/* 盤上ならば影響度を加算する */
if( x > 0 && x < (BOARD_SIZE-1) && y > 0 && y < (BOARD_SIZE-1) ){
board[y][x] += 1;
}
}
/*------------------------------------------------------------------*/
/* 合法手かどうか調べる */
/* このサンプルプログラムでは劫のチェックは省略 */
/*------------------------------------------------------------------*/
int
CheckLegal( int board[][BOARD_SIZE], int color, int x, int y )
{
/* 空点じゃないと置けません */
if( board[y][x] != SPACE ){
return( FALSE );
}
/* 自殺手なら置けません */
if( CheckSuicide( board, color, x, y ) == TRUE ){
return( FALSE );
}
/* 以上のチェックをすべてクリアできたので置けます */
return( TRUE );
}
/*------------------------------------------------------------------*/
/* 自殺手かどうか調べる */
/*------------------------------------------------------------------*/
int
CheckSuicide( int board[][BOARD_SIZE], int color, int x, int y )
{
int rtnVal;
int opponent; /* 相手の色 */
/* 仮に石を置く */
board[y][x] = color;
/* マークのクリア */
ClearCheckBoard();
/* その石は相手に囲まれているか調べる */
rtnVal = DoCheckRemoveStone( board, color, x, y );
/* 囲まれているならば自殺手の可能性あり */
if( rtnVal == TRUE ){
/* 相手の色を求める */
opponent = reverseColor( color );
/* その石を置いたことにより, 隣の相手の石が取れるなら自殺手ではない */
if( x > 1 ){
/* 隣は相手? */
if( board[y][x-1] == opponent ){
/* マークのクリア */
ClearCheckBoard();
/* 相手の石は囲まれているか? */
rtnVal = DoCheckRemoveStone( board, opponent, x-1, y );
/* 相手の石を取れるので自殺手ではない */
if( rtnVal == TRUE ){
/* 盤を元に戻す */
board[y][x] = SPACE;
return( FALSE );
}
}
}
if( y > 1 ){
/* 隣は相手? */
if( board[y-1][x] == opponent ){
/* マークのクリア */
ClearCheckBoard();
/* 相手の石は囲まれているか? */
rtnVal = DoCheckRemoveStone( board, opponent, x, y-1 );
/* 相手の石を取れるので自殺手ではない */
if( rtnVal == TRUE ){
/* 盤を元に戻す */
board[y][x] = SPACE;
return( FALSE );
}
}
}
if( x < (BOARD_SIZE-2) ){
/* 隣は相手? */
if( board[y][x+1] == opponent ){
/* マークのクリア */
ClearCheckBoard();
/* 相手の石は囲まれているか? */
rtnVal = DoCheckRemoveStone( board, opponent, x+1, y );
/* 相手の石を取れるので自殺手ではない */
if( rtnVal == TRUE ){
/* 盤を元に戻す */
board[y][x] = SPACE;
return( FALSE );
}
}
}
if( y < (BOARD_SIZE-2) ){
/* 隣は相手? */
if( board[y+1][x] == opponent ){
/* マークのクリア */
ClearCheckBoard();
/* 相手の石は囲まれているか? */
rtnVal = DoCheckRemoveStone( board, opponent, x, y+1 );
/* 相手の石を取れるので自殺手ではない */
if( rtnVal == TRUE ){
/* 盤を元に戻す */
board[y][x] = SPACE;
return( FALSE );
}
}
}
/* 盤を元に戻す */
board[y][x] = SPACE;
/* 相手の石を取れないなら自殺手 */
return( TRUE );
}else{
/* 盤を元に戻す */
board[y][x] = SPACE;
/* 囲まれていないので自殺手ではない */
return( FALSE );
}
}
/*------------------------------------------------------------------*/
/* チェック用の碁盤をクリア */
/*------------------------------------------------------------------*/
void
ClearCheckBoard( void )
{
int x, y;
for( y=1; y < (BOARD_SIZE-1); y++ ){
for( x=1; x < (BOARD_SIZE-1); x++ ){
checkBoard[y][x] = FALSE;
}
}
}
/*------------------------------------------------------------------*/
/* 座標(x,y)にあるcolor石が相手に囲まれているか調べる */
/*------------------------------------------------------------------*/
int /* 空点があればFALSEを返し, 空点がなければTRUEを返す */
DoCheckRemoveStone( int board[][BOARD_SIZE], int color, int x, int y )
{
int rtn;
/* その場所は既に調べた点ならおしまい */
if( checkBoard[y][x] == TRUE ){
return( TRUE );
}
/* 調べたことをマークする */
checkBoard[y][x] = TRUE;
/* 何も置かれていないならばおしまい */
if( board[y][x] == SPACE ){
return( FALSE );
}
/* 同じ色の石ならばその石の隣も調べる */
if( board[y][x] == color ){
/* その石の左(x-1,y)を調べる */
if( x > 1 ){
rtn = DoCheckRemoveStone( board, color, x-1, y );
if( rtn == FALSE ){
return( FALSE );
}
}
/* その石の上(x,y-1)を調べる */
if( y > 1 ){
rtn = DoCheckRemoveStone( board, color, x, y-1 );
if( rtn == FALSE ){
return( FALSE );
}
}
/* その石の右(x+1,y)を調べる */
if( x < (BOARD_SIZE-2) ){
rtn = DoCheckRemoveStone( board, color, x+1, y );
if( rtn == FALSE ){
return( FALSE );
}
}
/* その石の下(x,y+1)を調べる */
if( y < (BOARD_SIZE-2) ){
rtn = DoCheckRemoveStone( board, color, x, y+1 );
if( rtn == FALSE ){
return( FALSE );
}
}
}
/* 相手の色の石があった */
return( TRUE );
}
/*------------------------------------------------------------------*/
/* 碁盤を複写 */
/*------------------------------------------------------------------*/
void
CopyBoard( int source[][BOARD_SIZE], int copied[][BOARD_SIZE] )
{
int x, y;
for( y=0; y < BOARD_SIZE; y++ ){
for( x=0; x < BOARD_SIZE; x++ ){
copied[y][x] = source[y][x];
}
}
}
/*------------------------------------------------------------------*/
/* 碁盤に石を置く */
/* このサンプルプログラムでは取った石数は使わない */
/*------------------------------------------------------------------*/
void
SetStone( int board[][BOARD_SIZE], int color, int x, int y )
{
int prisonerN; /* 取り除かれた石の数(上) */
int prisonerE; /* 取り除かれた石の数(右) */
int prisonerS; /* 取り除かれた石の数(下) */
int prisonerW; /* 取り除かれた石の数(左) */
int prisonerAll; /* 取り除かれた石の総数 */
/* 座標(x,y)に石を置く */
board[y][x] = color;
/* 取り除かれた石の数 */
prisonerN = prisonerE = prisonerS = prisonerW = 0;
/* 置いた石の周囲の相手の石が死んでいれば碁盤から取り除く */
if( y > 1 ){
prisonerN = RemoveStone( board, color, x, y-1 );
}
if( x > 1 ){
prisonerW = RemoveStone( board, color, x-1, y );
}
if( y < (BOARD_SIZE-2) ){
prisonerS = RemoveStone( board, color, x, y+1 );
}
if( x < (BOARD_SIZE-2) ){
prisonerE = RemoveStone( board, color, x+1, y );
}
/* 取り除かれた石の総数 */
prisonerAll = prisonerN + prisonerE + prisonerS + prisonerW;
}
/*------------------------------------------------------------------*/
/* 座標(x,y)の石が死んでいれば碁盤から取り除く */
/*------------------------------------------------------------------*/
int /* 碁盤から取り除かれた石数 */
RemoveStone( int board[][BOARD_SIZE], int color, int x, int y )
{
int prisoner; /* 取り除かれた石数 */
/* 置いた石と同じ色なら取らない */
if( board[y][x] == color ){
return( 0 );
}
/* 空点なら取らない */
if( board[y][x] == SPACE ){
return( 0 );
}
/* マークのクリア */
ClearCheckBoard();
/* 囲まれているなら取る */
if( DoCheckRemoveStone( board, board[y][x], x, y ) == TRUE ){
prisoner = DoRemoveStone( board, board[y][x], x, y, 0 );
return( prisoner );
}
return( 0 );
}
/*------------------------------------------------------------------*/
/* 座標(x,y)のcolor石を碁盤から取り除き, 取った石の数を返す */
/*------------------------------------------------------------------*/
int /* アゲハマ */
DoRemoveStone( int board[][BOARD_SIZE],
int color, int x, int y, int prisoner )
{
/* 取り除かれる石と同じ色ならば石を取る */
if( board[y][x] == color ){
/* 取った石の数を1つ増やす */
prisoner++;
/* その座標に空点を置く */
board[y][x] = SPACE;
/* 左を調べる */
if( x > 1 ){
prisoner = DoRemoveStone( board, color, x-1, y, prisoner );
}
/* 上を調べる */
if( y > 1 ){
prisoner = DoRemoveStone( board, color, x, y-1, prisoner );
}
/* 右を調べる */
if( x < (BOARD_SIZE-2) ){
prisoner = DoRemoveStone( board, color, x+1, y, prisoner );
}
/* 下を調べる */
if( y < (BOARD_SIZE-2) ){
prisoner = DoRemoveStone( board, color, x, y+1, prisoner );
}
}
/* 取った石の数を返す */
return( prisoner );
}
/*---------------------- < end of program > ------------------------*/
[BACK]
[HOME]