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

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

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

  分析:

  

  代码:

#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] = {}; // 存放字符
bool moves[SIZE][SIZE] = {false}; // 对应坐标点是否可放置棋子
int row = ;
int col = ;
char again = ;
int no_of_games = ;
int no_of_moves = ;
int invalid_moves = ; // 每走一步,将值设置为0,连续2子无效,结束游戏
int comp_score = ;
int user_score = ;
bool next_player = true;
char y = ;
int x = ;
char input[SIZE] = {}; printf("XXOO棋,你懂的...\n");
printf("玩家持O,电脑持X,只能在对方的棋子旁边放置自己的棋子\n"
"当棋子的横、竖、斜方向有自己的棋子,对方的棋子会变成自己的\n"
"你可以走第一步,然后与电脑轮流下棋\n"
"祝好运(别被电脑XX了),按回车开始游戏\n"
"玩法:输入横竖坐标,例如:2b\n");
scanf("%c",&again); do{ // 外层循环,初始化每一次游戏
next_player = !next_player; // 控制玩家和电脑轮流下棋
no_of_moves = ; /* 初始化 */
for( row = ; row < SIZE; row++){
for( col = ; col < SIZE; col++ ){
board[row][col] = BLANK;
}
}
int mid = SIZE / ;
board[mid - ][mid - ] = board[mid][mid] = PLAYER_C;
board[mid - ][mid] = board[mid][mid - ] = 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 = ;
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 >= && y >= && 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 < ){
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 = ;
computer_move(board,moves,COMP_C);
no_of_moves++;
}
else{
if( ++invalid_moves < ){
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 < );
display(board);
comp_score = user_score = ;
for( row = ; row < SIZE; row++){
for( col = ; 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 ;
}
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 = ; col < SIZE; col++ ){
printf(" %c", col_label + col);
}
printf("\n"); /* display the rows */
for( int row = ; row < SIZE; row++ ){
printf(" +");
for( int col = ; col < SIZE; col++ ){
printf("---+");
}
printf("\n%2d|", row + );
for( int col = ; col < SIZE; col++){
printf(" %c |", board[row][col]);
}
printf("\n");
}
printf(" +"); /* display the bottom */
for( int col = ; col < SIZE; col++ ){
printf("---+");
}
printf("\n");
}
/* **********************************************************
* 对每一空格搜寻周围8个格子(或者更少),是否有对手的棋子
* 如果有,沿着对手棋子的横、竖、斜方向查找自己的棋子;
* 找到则可以在此空格落子,否则设置为false
* **********************************************************/
int valid_moves(char board[][SIZE], bool moves[][SIZE], char player){
int rowdelta = ;
int coldelta = ;
int x = ;
int y = ;
int no_of_moves = ; char opponent = (player == PLAYER_C) ? COMP_C : PLAYER_C;
for( int row = ; row < SIZE; row++ ){
for( int col = ; col < SIZE; col++ ){
moves[row][col] = false;
}
}
for( int row = ; row < SIZE; row++ ){
for( int col = ; col < SIZE; col++ ){
if(board[row][col] != BLANK){
continue;
}
for( rowdelta = -; rowdelta <= ; rowdelta++ ){
for( coldelta = -; coldelta <= ; coldelta++ ){ /* 跳过越界的坐标和当前空格 */
if( row + rowdelta < || row + rowdelta >= SIZE ||
col + coldelta < || col + coldelta >= SIZE ||
( == rowdelta && == coldelta ) ){
continue;
}
/* 找到对手的棋子 */
if( opponent == board[row + rowdelta][col + coldelta] ){
x = row + rowdelta;
y = col + coldelta;
/* 沿着当前方向查找自己的棋子 */
for( ; ; ){
x += rowdelta;
y += coldelta;
if( x < || x >= SIZE || y < || 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 = ;
int coldelta = ;
int x = ;
int y = ;
char opponent = (player == PLAYER_C) ? COMP_C : PLAYER_C; board[row][col] = player;
for( rowdelta = -; rowdelta <= ; rowdelta++ ){
for( coldelta = -; coldelta <= ; coldelta++ ){
if( row + rowdelta < || row + rowdelta >= SIZE ||
col + coldelta < || col + coldelta >= SIZE ||
( == rowdelta && == coldelta ) ){
continue;
}
/* 找到了对手的棋子,沿此方向继续查找 */
if( opponent == board[row + rowdelta][col + coldelta] ){
x = row + rowdelta;
y = col + coldelta;
for( ; ; ){
x += rowdelta;
y += coldelta;
if( x < || x >= SIZE || y < || 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 = ;
int best_col = ;
int new_score = ;
int score = ;
char temp_board[SIZE][SIZE];
bool temp_moves[SIZE][SIZE]; char opponent = (player == PLAYER_C) ? COMP_C : PLAYER_C;
for( int row = ; row < SIZE; row++ ){
for( int col = ; 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 = ;
char opponent = (player == PLAYER_C) ? COMP_C : PLAYER_C; for( int row = ; row < SIZE; row++ ){
for( int col = ; 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] = {};
int score = ;
int new_score = ;
for( int row = ; row < SIZE; row++ ){
for( int col = ; 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

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

  1. 用Dart写的黑白棋游戏

    2013年11月,Dart语言1.0稳定版SDK发布,普天同庆.从此,网页编程不再纠结了. 在我看来,Dart语法简直就是C#的升级版,太像了.之所以喜欢Ruby的一个重要理由是支持mixin功能,而 ...

  2. js+canvas黑白棋

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  3. 51nod 1368:黑白棋 二分图最大匹配

    1368 黑白棋 题目来源: TopCoder 基准时间限制:1 秒 空间限制:131072 KB 分值: 160 难度:6级算法题  收藏  取消关注 有一个N*M的棋盘(1<=N,M< ...

  4. python3+tkinter实现的黑白棋,代码完整 100%能运行

    今天分享给大家的是采用Python3+tkinter制作而成的小项目--黑白棋 tkinter是Python内置的图形化模块,简单易用,一般的小型UI程序可以快速用它实现,具体的tkinter相关知识 ...

  5. Ubuntu 14 安装 “宋体,微软雅黑,WPS Office的symbol、wingdings、wingdings 2、wingdings 3、webding字体,Consolas雅黑混合版编程字体” 等 Windows 7 下的字体

    Windows平台下,“宋体”.“微软雅黑”.“Courier New(编程字体)”用的比较多,看的也习惯了.那如何在 Ubuntu下也安装这些字体呢? 操作步骤如下: 第一步:从 Windows 7 ...

  6. [CareerCup] 8.8 Othello Game 黑白棋游戏

    8.8 Othello is played as follows: Each Othello piece is white on one side and black on the other. Wh ...

  7. 黑白棋游戏 (codevs 2743)题解

    [问题描述] 黑白棋游戏的棋盘由4×4方格阵列构成.棋盘的每一方格中放有1枚棋子,共有8枚白棋子和8枚黑棋子.这16枚棋子的每一种放置方案都构成一个游戏状态.在棋盘上拥有1条公共边的2个方格称为相邻方 ...

  8. bzoj 2281 [Sdoi2011]黑白棋(博弈+组合计数)

    黑白棋(game) [问题描述] 小A和小B又想到了一个新的游戏. 这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色. 最左边是白色棋子,最右边是黑色棋子,相邻的棋子颜色 ...

  9. C#黑白棋制作~

    前些天自己复习一下C#语言 做了个黑白棋,望大家看一下,可能有些bug嘿嘿 链接如下 http://files.cnblogs.com/files/flyingjun/%E9%BB%91%E7%99% ...

随机推荐

  1. stm32 USART_IT_IDLE中断 一帧数据

    USART_IT_IDLE中断,是串口收到一帧数据后,发生的中断.也可以叫做一包数据 USART_IT_IDLE和USART_IT_RXNE区别 当接收到1个字节,会产生USART_IT_RXNE中断 ...

  2. 笔谈OpenGL ES(二)

    昨晚回家也看了OpenGL ES 2.0 iOS教程的第一篇,对于其中涉及的一些基本知识罗列下,虽然自己做iOS开发一年多了,但是对于一些细节没有注意,真正的把自己当成“应用”工程师了 ,不仅要会用, ...

  3. 【代码片段】定时记录CPU使用率并保存为CSV

    原文链接 : [https://blog.zhoutao123.com/#/blog/article/64])(https://blog.zhoutao123.com/#/blog/article/6 ...

  4. nginx+uwsgi+django+supervisor+mysql+redis

    目录 1. 概述 3 2. 安装与配置 3 2.1 django项目与应用创建 3 2.2 uwsgi安装与配置 6 2.3 supervisor安装与配置 8 2.4 nginx安装与作为反向代理服 ...

  5. [openssl] 使用openssl生成证书

    使用openssl生成带域名的证书,SAN,subjectAltName, subject alternative name, DNS. 1. 生成私钥 openssl genrsa - 2. 编写配 ...

  6. 【转】高性能网络编程1----accept建立连接

    最近在部门内做了个高性能网络编程的培训,近日整理了下PPT,欲写成一系列文章从应用角度谈谈它. 编写服务器时,许多程序员习惯于使用高层次的组件.中间件(例如OO(面向对象)层层封装过的开源组件),相比 ...

  7. Proxmox 命令使用方法

    proxmox 虚拟机使用命令介绍 qm <command> <vmid> [OPTIONS]                                          ...

  8. ISCC之Re2

    硬核rust逆向 首先去学了一天rust...我TMD IDA打开,跟踪主函数 看一下伪代码,发现有一串密文 跟进去发现一串数据,猜测有可能是flag的加密数据,于是回头去分析算法 发现一个关键点 i ...

  9. MySQL加锁分析 (转)

    参考:MySQL 加锁处理分析.该文已经讲的很详尽了,也易懂,下面仅仅是个人做的总结. 一. 背景 1.1 隔离级别 1.2 加锁过程 逐条处理,逐条加锁. 1.3 两阶段锁2PL 1.4 gap锁 ...

  10. LeetCode - 206、反转链表

    反转一个单链表. 示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL /** * 列表定 ...