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

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

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

  分析:

  

  代码:

#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. aapt&adb笔记

    aapt 查看安装包信息aapt list apk路径* aapt list xxx/app-debug.apk 查看apk文件信息并保存到本地(> 重定向符) * aapt list xx/a ...

  2. Spring中Bean的基本概念

    一.Bean的定义 <beans…/>元素是Spring配置文件的根元素,<beans…/>元素可以包含多个<bean…/>子元素,每个<bean…/> ...

  3. iptables-1基本知识和工作原理

    一.简介1.iptables的定义:防火墙分为硬件防火墙和软件防火墙.iptables是软件防火墙,工作在OSI的第三.四层,是从操作系统层面对网络流量进行监控和防护.延伸:(1)Linux系统内核集 ...

  4. hash文件-对文件进行数字签名

    (一)windows自带hash命令: certutil -hashfile D:\1.exe MD5              #  md5的hash值为32位certutil -hashfile ...

  5. 二十三、mysql索引管理详解

    一.索引分类 分为聚集索引和非聚集索引. 聚集索引 每个表有且一定会有一个聚集索引,整个表的数据存储在聚集索引中,mysql索引是采用B+树结构保存在文件中,叶子节点存储主键的值以及对应记录的数据,非 ...

  6. 2019.7月-前端面试总结(H5+C3+JS+ES6+Vue+浏览器)

    第二次面试 HTML HTML5中的新标签,举例一下 canvas绘画,本地离线存储localStorage,sessionStorage,video和audio元素,语义化元素,表单类型(date, ...

  7. Spring Boot 笔记 (1) - Maven、基本配置、Profile的使用

    一. Spring Boot 简介 开箱即用的一站式 Java EE 解决方案 Spring 技术栈的大整合 核心问题 暂时无法回答 Spring Boot 和 SOA 有什么区别? Spring B ...

  8. redis哨兵配置 总结

    本文内容涵盖 windows下单机部署redis多实例(docker.linux下的配置也可参考本文) redis主从配置 redis哨兵配置 以spring boot redis demo下一个存a ...

  9. 使用awstats分析nginx日志

    1.awstats介绍 本文主要是记录centos6.5下安装配置awstats,并统计nginx访问日志 1.1 awstats介绍 awstats是一款日志统计工具,它使用Perl语言编写,可统计 ...

  10. QT5无法定位程序输入点 于动态链接库QtCore5.dll的解决

    本人新手刚接触QT5,今天在写程序时,在QtCreator中可以运行,但是单独运行.exe文件时报错 之后发现是因为我之前在path路径中添加了MinGw,导致里面也有Qt库.但是我编译的时候用的是安 ...