/* コンピュータ上で人間どうしが対局するプログラム*/
#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 )
/*------------------------------------------------------------------*/
/* 構造体 */
/*------------------------------------------------------------------*/
/* 棋譜*/
typedef struct {
int color;
int x;
int y;
} type_log;
/*------------------------------------------------------------------*/
/* 関数 */
/*------------------------------------------------------------------*/
/* メイン関数*/
int main( int argc, char *argv[] );
/* 碁盤の初期化*/
void InitializeBoard( int board[][BOARD_SIZE] );
/* 碁盤を表示する*/
void DisplayBoard( int board[][BOARD_SIZE] );
/* 着手位置の入力*/
void ThinkMove( int board[][BOARD_SIZE], int color, int *x, int *y );
/* 画面から数値を入力*/
void InputCoordinate( int color, 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 );
/* 勝敗の判定*/
int CountScore( void );
/* 碁盤に石を置く*/
void SetStone( int board[][BOARD_SIZE], int color, int x, int y );
/* 同じ色または盤外ならばTRUEを返す*/
int IsColorOrOut( int board[][BOARD_SIZE], int x, int y, int color );
/* 囲まれた石を取り除く*/
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 );
/* 棋譜に記録*/
void RecordMove( int color, int x, int y );
/*------------------------------------------------------------------*/
/* 変数 */
/*------------------------------------------------------------------*/
/* 碁盤の表示のための文字*/
static char stone[] = { '+', '@', 'O', '?' };
/* 手数*/
static int move;
/* アゲハマ*/
static int black_prisoner;
static int white_prisoner;
/* 劫の位置*/
static int ko_x;
static int ko_y;
/* 劫が発生した手数*/
static int ko_num;
/* 棋譜(499手まで覚える) */
static type_log logData[500];
/* 合法手かどうか調べるのに使う*/
static int checkBoard[BOARD_SIZE][BOARD_SIZE];
/*------------------------------------------------------------------*/
/* メイン関数 */
/*------------------------------------------------------------------*/
int
main( int argc, char *argv[] )
{
int board[BOARD_SIZE][BOARD_SIZE]; /* 碁盤*/
int xBlack, yBlack; /* 黒の着手位置*/
int xWhite, yWhite; /* 白の着手位置*/
int score; /* 黒地−白地 */
/* 碁盤の初期化*/
InitializeBoard( board );
printf( "Sample Program Start\n" );
xBlack = yBlack = 999; /* 最初は以外の数字を書いておく*/
xWhite = yWhite = 999; /* 最初は以外の数字を書いておく*/
/* アゲハマ*/
black_prisoner = 0;
white_prisoner = 0;
/* 手数*/
move = 1;
/* 終局するまでループ*/
while( 1 ){
/*------*/
/* 黒番*/
/*------*/
/* 碁盤の表示*/
DisplayBoard( board );
/* 黒の着手位置を入力*/
ThinkMove( board, BLACK, &xBlack, &yBlack );
/* 黒が投了なら白の勝ち*/
if( xBlack >= (BOARD_SIZE-1) || yBlack >= (BOARD_SIZE-1) ){
printf( "Black Resign. White Win.\n" );
break;
}
/* 黒白ともにパスなら地を数えて勝者を表示*/
if( ( xBlack < 1 || yBlack < 1 ) && ( xWhite < 1 || yWhite < 1 ) ){
score = CountScore();
if( score > 0 ){
printf( "Black Win\n" ); /* 黒が多ければ黒の勝ち*/
}else if( score < 0 ){
printf( "White Win\n" ); /* 黒が少なければ白の勝ち*/
}else{
printf( "Draw\n" ); /* 同数ならば引分け*/
}
break;
}
/* 座標が〜なら碁盤に石を置く*/
SetStone( board, BLACK, xBlack, yBlack );
/* 棋譜に記録*/
RecordMove( BLACK, xBlack, yBlack );
/* 手数が増える*/
move++;
/*------*/
/* 白番*/
/*------*/
/* 碁盤の表示*/
DisplayBoard( board );
/* 白の着手位置を入力*/
ThinkMove( board, WHITE, &xWhite, &yWhite );
/* 白が投了なら黒の勝ち*/
if( xWhite >= (BOARD_SIZE-1) || yWhite >= (BOARD_SIZE-1) ){
printf( "White Resign. Black Win.\n" );
break;
}
/* 黒白ともにパスなら地を数えて勝者を表示*/
if( ( xBlack < 1 || yBlack < 1 ) && ( xWhite < 1 || yWhite < 1 ) ){
score = CountScore();
if( score > 0 ){
printf( "Black Win\n" ); /* 黒が多ければ黒の勝ち*/
}else if( score < 0 ){
printf( "White Win\n" ); /* 黒が少なければ白の勝ち*/
}else{
printf( "Draw\n" ); /* 同数ならば引分け*/
}
break;
}
/* 座標が〜なら碁盤に石を置く*/
SetStone( board, WHITE, xWhite, yWhite );
/* 棋譜に記録*/
RecordMove( WHITE, xWhite, yWhite );
/* 手数が増える*/
move++;
}
printf( "Sample Program End\n" );
return EXIT_SUCCESS;
}
/*------------------------------------------------------------------*/
/* 碁盤の初期化 */
/*------------------------------------------------------------------*/
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++ ){
printf( " %c", stone[board[y][x]] );
}
printf( "\n" );
}
printf( "\n" );
}
/*------------------------------------------------------------------*/
/* 着手位置の入力 */ */
/*------------------------------------------------------------------*/
void
ThinkMove( int board[][BOARD_SIZE], int color, int *x, int *y )
{
int inputX, inputY;
while( 1 ){
/* 着手位置の入力*/
InputCoordinate( color, &inputX, &inputY );
if( inputX > 0 && inputX < (BOARD_SIZE-1) &&
inputY > 0 && inputY < (BOARD_SIZE-1) ){
/* 座標が〜ならば合法手がどうか調べる*/
if( CheckLegal( board, color, inputX, inputY ) == TRUE ){
break;
}
}else{
break;
}
}
*x = inputX;
*y = inputY;
}
/*------------------------------------------------------------------*/
/* 画面から数値を入力 */
/* X座標が〜ならばY座標も入力する */
/* X座標がより小さければパスとみなし, Y座標は入力しない */
/* X座標がより大きければ投了とみなし, Y座標は入力しない */
/*------------------------------------------------------------------*/
void
InputCoordinate( int color, int *x, int *y )
{
int val;
char str[256];
printf( "\n" );
if( color == BLACK ){
printf( "Please Input Black Coordinates.\n" );
}else{
printf( "Please Input White Coordinates.\n" );
}
printf( " Pass -> 0, Quit -> 20\n" );
/* X座標の入力*/
while( 1 ){
printf( "InputX:" );
fflush( stdout );
val = scanf( "%s", str );
*x = atoi(str);
if( val == 1 ){
break;
}
}
if( *x >= 1 && *x < (BOARD_SIZE-1) ){
/* X座標が〜なのでY座標の入力*/
while( 1 ){
printf( "InputY:" );
fflush( stdout );
val = scanf( "%s", str );
*y = atoi(str);
if( val == 1 ){
break;
}
}
}else if( *x < 1 ){
/* X座標がより小さいのでパスとみなし, Y座標は入力しない*/
*y = 0;
}else{
/* X座標がより大きいので投了とみなし, Y座標は入力しない*/
*y = 20;
}
}
/*------------------------------------------------------------------*/
/* 合法手かどうか調べる */
/*------------------------------------------------------------------*/
int
CheckLegal( int board[][BOARD_SIZE], int color, int x, int y )
{
/* 空点じゃないと置けません*/
if( board[y][x] != SPACE ){
return( FALSE );
}
/* 一手前に劫を取られていたら置けません*/
if( move > 1 ){
if( ko_x == x && ko_y == y && ko_num == (move-1) ){
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 );
}
/*------------------------------------------------------------------*/
/* 勝敗の判定 */
/* このプログラムでは地を数えていません */
/* アゲハマの多い方を勝ちと判定しています */
/*------------------------------------------------------------------*/
int
CountScore( void )
{
int black_score;
int white_score;
/* 碁盤上の地を数えるべきところだが省略*/
black_score = 0;
white_score = 0;
/* アゲハマを加える*/
black_score += black_prisoner;
white_score += white_prisoner;
/* 黒−白を返す*/
return( black_score - white_score );
}
/*------------------------------------------------------------------*/
/* 碁盤に石を置く */
/*------------------------------------------------------------------*/
void
SetStone( int board[][BOARD_SIZE], int color, int x, int y )
{
int prisonerN; /* 取り除かれた石の数(上)*/
int prisonerE; /* 取り除かれた石の数(右)*/
int prisonerS; /* 取り除かれた石の数(下)*/
int prisonerW; /* 取り除かれた石の数(左)*/
int prisonerAll; /* 取り除かれた石の総数*/
int koFlag; /* 劫かどうか*/
/* 座標(x,y)に石を置く*/
board[y][x] = color;
/* 置いた石は相手に囲まれているか*/
if( IsColorOrOut( board, x, y-1, reverseColor( color ) ) == TRUE &&
IsColorOrOut( board, x-1, y, reverseColor( color ) ) == TRUE &&
IsColorOrOut( board, x+1, y, reverseColor( color ) ) == TRUE &&
IsColorOrOut( board, x, y+1, reverseColor( color ) ) == TRUE ){
/* 囲まれているので劫かもしれない*/
koFlag = TRUE;
}else{
/* 囲まれていないので劫ではない*/
koFlag = FALSE;
}
/* 取り除かれた石の数*/
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;
/* 置いた石の隣に同じ色の石がなく, 取り除かれた石も1つならば劫*/
if( koFlag == TRUE && prisonerAll == 1 ){
/* 劫の発生した手数を覚える*/
ko_num = move;
/* 劫の座標を覚える*/
if( prisonerE == 1 ){
/* 取り除かれた石が右*/
ko_x = x+1;
ko_y = y;
}else if( prisonerS == 1 ){
/* 取り除かれた石が下*/
ko_x = x;
ko_y = y+1;
}else if( prisonerW == 1 ){
/* 取り除かれた石が左*/
ko_x = x-1;
ko_y = y;
}else if( prisonerN == 1 ){
/* 取り除かれた石が上*/
ko_x = x;
ko_y = y-1;
}
}
/* アゲハマの更新*/
if( prisonerAll > 0 ){
if( color == BLACK ){
black_prisoner += prisonerAll;
}else if( color == WHITE ){
white_prisoner += prisonerAll;
}
}
}
/*------------------------------------------------------------------*/
/* board[y][x] == color または盤外ならばTRUEを返す */
/*------------------------------------------------------------------*/
int
IsColorOrOut( int board[][BOARD_SIZE], int x, int y, int color )
{
if( x < 1 || x > (BOARD_SIZE-2) || y < 1 || y > (BOARD_SIZE-2) ){
return( TRUE );
}
if( board[y][x] == color ){
return( TRUE );
}
return( FALSE );
}
/*------------------------------------------------------------------*/
/* 座標(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 );
}
/*------------------------------------------------------------------*/
/* 棋譜に記録 */
/*------------------------------------------------------------------*/
void
RecordMove( int color, int x, int y )
{
/* ここでは手までに制限*/
if( move < 500 ){
logData[move].color = color;
logData[move].x = x;
logData[move].y = y;
}
}
/*---------------------- < end of program > ------------------------*/
[BACK]
[HOME]