两位玩家轮流在棋盘上放置不同颜色的棋子,一位玩家使用黑子,另一位使用白子,棋盘是一个偶数正方形。
只能将一个棋子放在对手的棋子旁边,使对手在水平、垂直、对角线方向上的棋子变成自己的棋子,游戏结束时,棋子多的玩家获胜。
如果所有的方格都放置了棋子,游戏结束;如果无法放置棋子将对方的棋子变成自己的,游戏结束。
分析:
代码:
#include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <ctype.h> #include <string.h> #define SIZE 6 // 游戏区大小,必须为偶数 #define BLANK ' ' // 空白 #define COMP_C 'X' // 电脑字符 #define PLAYER_C 'O' // 玩家字符 void display(char board[][SIZE]); // 负责显示 int valid_moves(char board[][SIZE], bool moves[][SIZE], char player); // 计算所有走法 void make_move(char board[][SIZE], int row, int col, char player); // 落子后执行转换 void computer_move(char board[][SIZE], bool moves[][SIZE], char player); // 电脑落子 int get_score(char board[][SIZE],char player); // 计算分数 int best_move(char board[][SIZE],bool moves[][SIZE],char player); // 电脑走法 int main(void){ char board[SIZE][SIZE] = {0}; // 存放字符 bool moves[SIZE][SIZE] = {false}; // 对应坐标点是否可放置棋子 int row = 0; int col = 0; char again = 0; int no_of_games = 0; int no_of_moves = 0; int invalid_moves = 0; // 每走一步,将值设置为0,连续2子无效,结束游戏 int comp_score = 0; int user_score = 0; bool next_player = true; char y = 0; int x = 0; char input[SIZE] = {0}; printf("XXOO棋,你懂的... "); printf("玩家持O,电脑持X,只能在对方的棋子旁边放置自己的棋子 " "当棋子的横、竖、斜方向有自己的棋子,对方的棋子会变成自己的 " "你可以走第一步,然后与电脑轮流下棋 " "祝好运(别被电脑XX了),按回车开始游戏 " "玩法:输入横竖坐标,例如:2b "); scanf("%c",&again); do{ // 外层循环,初始化每一次游戏 next_player = !next_player; // 控制玩家和电脑轮流下棋 no_of_moves = 4; /* 初始化 */ for( row = 0; row < SIZE; row++){ for( col = 0; col < SIZE; col++ ){ board[row][col] = BLANK; } } int mid = SIZE / 2; board[mid - 1][mid - 1] = board[mid][mid] = PLAYER_C; board[mid - 1][mid] = board[mid][mid - 1] = COMP_C; do{ // 内层循环,电脑和玩家轮流 display(board); if(next_player = !next_player){ // 玩家先走 if( valid_moves(board, moves, PLAYER_C) ){ /* 接收玩家输入,并判断是否可放置棋子 */ for( ; ; ){ printf("Please enter your move ( row column ):"); fgets(input, SIZE ,stdin); // 控制输入字符个数 fflush(stdin); /* 只读取前2个非空字符 */ int cnt = 0; while( isspace(input[cnt]) )cnt++; //printf("%s ",input); x = atoi(&input[cnt++]); x--; // 行减1,转换为二维数组索引 //printf("%d ",x); while( isspace(input[cnt]) )cnt++; y = tolower(input[cnt]); y -= 'a'; // 列字母减a //printf("%c ",y); if( x >= 0 && y >= 0 && x < SIZE && y < SIZE && moves[x][y] ){ make_move(board,x,y,PLAYER_C); no_of_moves++; break; } else{ printf("Not a valid move,try again. "); } } } else{ if( ++invalid_moves < 2){ printf("You have to pass,press return"); scanf("%c",&again); } else{ printf("Neither of us can go, so the game is over. "); } } } /* 电脑下棋 */ else{ if( valid_moves(board,moves,COMP_C) ){ invalid_moves = 0; computer_move(board,moves,COMP_C); no_of_moves++; } else{ if( ++invalid_moves < 2){ printf("You have to pass,press return"); scanf("%c",&again); } else{ printf("Neither of us can go, so the game is over. "); } } } }while( no_of_moves < SIZE * SIZE && invalid_moves < 2 ); display(board); comp_score = user_score = 0; for( row = 0; row < SIZE; row++){ for( col = 0; col < SIZE; col++ ){ comp_score += board[row][col] == COMP_C; user_score += board[row][col] == PLAYER_C; } } printf("The final score is: "); printf("Computer %d User %d ",comp_score,user_score); printf("Do you want to play aiain (y/n):"); scanf(" %c",&again); }while( 'y' == tolower(again) ); return 0; } void display(char board[][SIZE]){ char col_label = 'a'; printf(" "); /* display the top line such as : a b c d e f .. */ for( int col = 0; col < SIZE; col++ ){ printf(" %c", col_label + col); } printf(" "); /* display the rows */ for( int row = 0; row < SIZE; row++ ){ printf(" +"); for( int col = 0; col < SIZE; col++ ){ printf("---+"); } printf(" %2d|", row + 1); for( int col = 0; col < SIZE; col++){ printf(" %c |", board[row][col]); } printf(" "); } printf(" +"); /* display the bottom */ for( int col = 0; col < SIZE; col++ ){ printf("---+"); } printf(" "); } /* ********************************************************** * 对每一空格搜寻周围8个格子(或者更少),是否有对手的棋子 * 如果有,沿着对手棋子的横、竖、斜方向查找自己的棋子; * 找到则可以在此空格落子,否则设置为false * **********************************************************/ int valid_moves(char board[][SIZE], bool moves[][SIZE], char player){ int rowdelta = 0; int coldelta = 0; int x = 0; int y = 0; int no_of_moves = 0; char opponent = (player == PLAYER_C) ? COMP_C : PLAYER_C; for( int row = 0; row < SIZE; row++ ){ for( int col = 0; col < SIZE; col++ ){ moves[row][col] = false; } } for( int row = 0; row < SIZE; row++ ){ for( int col = 0; col < SIZE; col++ ){ if(board[row][col] != BLANK){ continue; } for( rowdelta = -1; rowdelta <= 1; rowdelta++ ){ for( coldelta = -1; coldelta <= 1; coldelta++ ){ /* 跳过越界的坐标和当前空格 */ if( row + rowdelta < 0 || row + rowdelta >= SIZE || col + coldelta < 0 || col + coldelta >= SIZE || ( 0 == rowdelta && 0 == coldelta ) ){ continue; } /* 找到对手的棋子 */ if( opponent == board[row + rowdelta][col + coldelta] ){ x = row + rowdelta; y = col + coldelta; /* 沿着当前方向查找自己的棋子 */ for( ; ; ){ x += rowdelta; y += coldelta; if( x < 0 || x >= SIZE || y < 0 || y >= SIZE ){ break; } if( BLANK == board[x][y] ){ break; } if( player == board[x][y] ){ moves[row][col] = true; no_of_moves++; break; } } } } } } } return no_of_moves; // 返回值大于0说明该空格可以落子,否则不能 } /* ********************************************************** * 搜寻周围8个格子(或者更少),是否有对手的棋子 * 如果有,沿着对手棋子的所在方向查找自己的棋子, * 出界活在找到空格,跳出循环,在外层循环移动到下一个棋格。 * 如果找到自己的棋子,将该方向上对手的所有棋子变成自己的 * **********************************************************/ void make_move(char board[][SIZE], int row, int col, char player){ int rowdelta = 0; int coldelta = 0; int x = 0; int y = 0; char opponent = (player == PLAYER_C) ? COMP_C : PLAYER_C; board[row][col] = player; for( rowdelta = -1; rowdelta <= 1; rowdelta++ ){ for( coldelta = -1; coldelta <= 1; coldelta++ ){ if( row + rowdelta < 0 || row + rowdelta >= SIZE || col + coldelta < 0 || col + coldelta >= SIZE || ( 0 == rowdelta && 0 == coldelta ) ){ continue; } /* 找到了对手的棋子,沿此方向继续查找 */ if( opponent == board[row + rowdelta][col + coldelta] ){ x = row + rowdelta; y = col + coldelta; for( ; ; ){ x += rowdelta; y += coldelta; if( x < 0 || x >= SIZE || y < 0 || y >= SIZE ){ break; } if( BLANK == board[x][y] ){ break; } /* 找到自己的棋子 */ if( player == board[x][y] ){ /* 沿反方向将对手的棋子替换成自己的 */ while( opponent == board[x-=rowdelta][y-=coldelta] ){ board[x][y] = player; } break; } } } } } } /* ********************************************************** * 计算电脑的所有可能走法,并判断玩家的可能走法, * 选出使玩家分数最低的走法 * **********************************************************/ void computer_move(char board[][SIZE], bool moves[][SIZE], char player){ int best_row = 0; int best_col = 0; int new_score = 0; int score = 100; char temp_board[SIZE][SIZE]; bool temp_moves[SIZE][SIZE]; char opponent = (player == PLAYER_C) ? COMP_C : PLAYER_C; for( int row = 0; row < SIZE; row++ ){ for( int col = 0; col < SIZE; col++ ){ if( !moves[row][col] ){ continue; } memcpy(temp_board,board,sizeof(temp_board)); // 创建副本 make_move(temp_board,row,col,player); // 模拟电脑走法 valid_moves(temp_board,temp_moves,opponent); // 计算玩家走法 new_score = best_move(temp_board,temp_moves,opponent); // 计算玩家得分 if( new_score < score ){ score = new_score; best_row = row; best_col = col; } } } make_move(board,best_row,best_col,player); } /* ********************************************************** * 计算得分,自己的棋子加1分,对手的棋子减1分 * **********************************************************/ int get_score(char board[][SIZE],char player){ int score = 0; char opponent = (player == PLAYER_C) ? COMP_C : PLAYER_C; for( int row = 0; row < SIZE; row++ ){ for( int col = 0; col < SIZE; col++ ){ score -= board[row][col] == opponent; score += board[row][col] == player; } } return score; } /* ********************************************************** * 返回玩家当前有效走法中得分最高的走法 * **********************************************************/ int best_move(char board[][SIZE],bool moves[][SIZE],char player){ //char opponent = (player == PLAYER_C) ? COMP_C : PLAYER_C; char new_board[SIZE][SIZE] = {0}; int score = 0; int new_score = 0; for( int row = 0; row < SIZE; row++ ){ for( int col = 0; col < SIZE; col++ ){ if( !moves[row][col] ){ continue; } memcpy(new_board,board,sizeof(new_board)); // 创建副本 make_move(new_board,row,col,player); // 模拟玩家可能走法 new_score = get_score(new_board,player); // 计算玩家得分 if( score < new_score ){ score = new_score; } } } return score; }
编译:
gcc reversi.c -std=c99