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};
    int cnt = 0;

    printf("REVERSI\n");
    printf("You can go first on the first game,then we will take turns\n");
    printf("Good luck! Press Enter to start.\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个非空字符 */
                    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;
}

  编译:

  gcc reversi.c -std=c99

时间: 2024-11-11 07:32:50

C仿黑白棋版XO棋的相关文章

人机对战-黑白棋

先大致了解一下黑白棋: 规则 如果玩家在棋盘上没有地方可以下子,则该玩家对手可以连下.双方都没有棋子可以下时棋局结束,以棋子数目来计算胜负,棋子多的一方获胜. 在棋盘还没有下满时,如果一方的棋子已经被对方吃光,则棋局也结束.将对手棋子吃光的一方获胜. 翻转棋类似于棋盘游戏"奥赛罗 (Othello)",是一种得分会戏剧性变化并且需要长时间思考的策略性游戏. 翻转棋的棋盘上有 64 个可以放置黑白棋子的方格(类似于国际象棋和跳棋).游戏的目标是使棋盘上自己颜色的棋子数超过对手的棋子数.

枚举(黑白棋)

/*代码一:DFS+Enum*/ //Memory Time //240K 344MS //本题只要求输出翻转的次数,因此BFS或DFS都适用 #include<iostream> using namespace std; bool chess[6][6]={false};//利用的只有中心的4x4 bool flag; int step; int r[]={-1,1,0,0,0};//便于翻棋操作 int c[]={0,0,-1,1,0}; bool judge_all(void)//判断&

黑白棋

一般棋子双面为黑白两色,故称"黑白棋".因为行棋之时将对方棋子翻转,变为己方棋子,故又称"翻转棋"(Reversi).棋子双面为红.绿色的称为"苹果棋". 棋子:黑白棋棋子每颗由黑白两色组成,一面白,一面黑,共64个(包括棋盘中央的4个).棋子呈圆饼形. 棋盘:黑白棋棋盘由64格的正方格组成,游戏进行时棋子要下在格内.棋盘可分为"角"."边"以及"中腹".现今的棋盘多以8x8较为普遍.

游戏开发(三)——WIN32 黑白棋(二)——AI

今天是第二部分:玩家和AI 玩家主要是实现悔棋的功能 AI主要是搜索.最大最小算法,枝剪算法 1.每一步落子的步骤,为了可以悔棋 typedef struct ReversiStep {     ReversiBitBoard m_LastMap;     ReversiStep& operator= (const ReversiStep& temp)     {         m_LastMap = temp.m_LastMap;         return *this;     }

游戏开发(三)——WIN32 黑白棋(一)——棋局逻辑的设计

今天以黑白棋为例,开始给一个win32的小游戏设计, 这里打算分3部分介绍 1.棋盘,棋局的现实 2.玩家.AI的现实(且听下回分解) 3.游戏画面的现实(且听下下回分解) 其中第一部分为黑白棋游戏的主要逻辑: 1.棋盘,以及棋盘上的棋子的存储形式.这里用到了位图. 2.是否可以落子的判断(黑白棋是只有你落子的位置,在横竖斜八个方向中任意一个方向,能吃掉对方的子,你才可以落在该位置,八个方向都吃不掉对方子的位置是不能下的),以及吃子的逻辑(吃子的逻辑同样是八个方向,两个己方棋子之间夹住的对方棋子

游戏开发(三)——WIN32 黑白棋(三)——游戏画面的现实

整个游戏分3部分介绍. 1.棋局的现实 2.AI的现实 3.游戏画面的现实 提供一下完整项目下载 这是第三部分:画面的显示 这部分其实就比较简单的,说白了就是api的堆砌. 主要了解下windows的消息机制,以及怎么画图 主要是分别封装了下对棋盘,棋子,以及当前轮到谁,当前比分是多少,就是游戏画面上不同的部分的绘制. void DrawReversiBoard(); void DrawReversiPieces(EnumReversiPiecesType type, int row_y, in

黑白棋游戏 (codevs 2743)题解

[问题描述] 黑白棋游戏的棋盘由4×4方格阵列构成.棋盘的每一方格中放有1枚棋子,共有8枚白棋子和8枚黑棋子.这16枚棋子的每一种放置方案都构成一个游戏状态.在棋盘上拥有1条公共边的2个方格称为相邻方格.一个方格最多可有4个相邻方格.在玩黑白棋游戏时,每一步可将任何2个相邻方格中棋子互换位置.对于给定的初始游戏状态和目标游戏状态,编程计算从初始游戏状态变化到目标游戏状态的最短着棋序列. [样例输入] 1111 0000 1110 0010 1010 0101 1010 0101 [样例输出] 4

[某鸥实训记][objective-c][第二天][作业]黑白棋+关灯游戏

自己写的..所以可能没什么逻辑性...可能特别水... 环境为ios SDK8.0 选择的Simulator是iPhone6 创建ios SingleViewApplication..然后再ViewController.m中的代码就是全部了 1 // 2 // ViewController.m 3 // 黑白棋0908 4 // 5 // Created by ******* on 15/9/8. 6 // Copyright (c) 2015年 *******. All rights rese

黑白棋游戏(或是叫再破难关)——稍微用了下状态压缩的bfs

洛谷和CodeVS 上叫做黑白棋游戏,要求输出路径.CodeVS 上没有spj,洛谷上有但是我的输出总是直接报错.最后找到了Vijos 上的再破难关,一样的题,只是不需要输出路径,交了就对了. 1 #include<iostream> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cstdio> 5 #include<vector> 6 #include<queue> 7 usi