C仿黑白棋版XO棋

  两位玩家轮流在棋盘上放置不同颜色的棋子,一位玩家使用黑子,另一位使用白子,棋盘是一个偶数正方形。

  只能将一个棋子放在对手的棋子旁边,使对手在水平、垂直、对角线方向上的棋子变成自己的棋子,游戏结束时,棋子多的玩家获胜。

  如果所有的方格都放置了棋子,游戏结束;如果无法放置棋子将对方的棋子变成自己的,游戏结束。

  分析:

  

  代码:

#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棋,你懂的...\n");
    printf("玩家持O,电脑持X,只能在对方的棋子旁边放置自己的棋子\n"
           "当棋子的横、竖、斜方向有自己的棋子,对方的棋子会变成自己的\n"
           "你可以走第一步,然后与电脑轮流下棋\n"
           "祝好运(别被电脑XX了),按回车开始游戏\n"
           "玩法:输入横竖坐标,例如:2b\n");
    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\n",input);
                    x = atoi(&input[cnt++]);
                    x--;                            // 行减1,转换为二维数组索引
                    //printf("%d\n",x);
                    while( isspace(input[cnt]) )cnt++;
                    y = tolower(input[cnt]);    
                    y -= 'a';                        // 列字母减a
                                            
                    //printf("%c\n",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.\n");
                    }
                }    
            }
            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.\n");
                }
            }
        }
        
        /* 电脑下棋 */
        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.\n");
                }
            }
        }
    }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:\n");
    printf("Computer %d\nUser %d\n",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("\n ");
    /* 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("\n");
    
    /* display the rows */
    for( int row = 0; row < SIZE; row++ ){
        printf("  +");
        for( int col = 0; col < SIZE; col++ ){
            printf("---+");
        }
        printf("\n%2d|", row + 1);
        for( int col = 0; col < SIZE; col++){
            printf(" %c |", board[row][col]);
        }
        printf("\n");
    }
    printf("  +");
    
    /* display the bottom */
    for( int col = 0; col < SIZE; col++ ){
        printf("---+");
    }
    printf("\n");
}
/* **********************************************************
 * 对每一空格搜寻周围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;
}
View Code

 

  编译:

  gcc reversi.c -std=c99

posted @ 2015-07-10 16:27  葡萄不吐皮  阅读(606)  评论(0编辑  收藏  举报