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] = {}; // 存放字符
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棋的更多相关文章
- 用Dart写的黑白棋游戏
2013年11月,Dart语言1.0稳定版SDK发布,普天同庆.从此,网页编程不再纠结了. 在我看来,Dart语法简直就是C#的升级版,太像了.之所以喜欢Ruby的一个重要理由是支持mixin功能,而 ...
- js+canvas黑白棋
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- 51nod 1368:黑白棋 二分图最大匹配
1368 黑白棋 题目来源: TopCoder 基准时间限制:1 秒 空间限制:131072 KB 分值: 160 难度:6级算法题 收藏 取消关注 有一个N*M的棋盘(1<=N,M< ...
- python3+tkinter实现的黑白棋,代码完整 100%能运行
今天分享给大家的是采用Python3+tkinter制作而成的小项目--黑白棋 tkinter是Python内置的图形化模块,简单易用,一般的小型UI程序可以快速用它实现,具体的tkinter相关知识 ...
- Ubuntu 14 安装 “宋体,微软雅黑,WPS Office的symbol、wingdings、wingdings 2、wingdings 3、webding字体,Consolas雅黑混合版编程字体” 等 Windows 7 下的字体
Windows平台下,“宋体”.“微软雅黑”.“Courier New(编程字体)”用的比较多,看的也习惯了.那如何在 Ubuntu下也安装这些字体呢? 操作步骤如下: 第一步:从 Windows 7 ...
- [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 ...
- 黑白棋游戏 (codevs 2743)题解
[问题描述] 黑白棋游戏的棋盘由4×4方格阵列构成.棋盘的每一方格中放有1枚棋子,共有8枚白棋子和8枚黑棋子.这16枚棋子的每一种放置方案都构成一个游戏状态.在棋盘上拥有1条公共边的2个方格称为相邻方 ...
- bzoj 2281 [Sdoi2011]黑白棋(博弈+组合计数)
黑白棋(game) [问题描述] 小A和小B又想到了一个新的游戏. 这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色. 最左边是白色棋子,最右边是黑色棋子,相邻的棋子颜色 ...
- C#黑白棋制作~
前些天自己复习一下C#语言 做了个黑白棋,望大家看一下,可能有些bug嘿嘿 链接如下 http://files.cnblogs.com/files/flyingjun/%E9%BB%91%E7%99% ...
随机推荐
- [C#]DataTable转string[]
来源:https://zhidao.baidu.com/question/1754089856824824548.html string[] ary = Array.ConvertAll<Dat ...
- linux设备树的建立过程
为了阐明表示总线.设备和设备驱动程序的各个数据结构之间彼此的关联,它们的注册过程是很有必要的.顺序一定是如下:(1)注册总线---bus_register:(2)注册设备device_register ...
- cloudera manager(CDH)实践
cloudera manager 可以简化 Hadoop 的安装配置过程,自动在集群节点上安 装 hadoop 相关组件,创建用户,并管理各个组件服务.本手册以 cloudera manager 的 ...
- SecureCRT中文乱码解决已设置UTF-8了
参考网址:http://www.iitshare.com/securecrt-chinese-garbled-solution.html 问题描述 SecureCRT与SecureFX的常规选项里面已 ...
- 微信小程序(小游戏)后台开发
小程序开放接口功能,目的是方便小程序接入第三方服务器,比如,商城类小程序,小游戏,需要保存订单数据,玩家信息等.那就需要服务器和数据库, 开发者对于各方关系必须要理清,那就是小程序,用户,开发者服务器 ...
- Buffer Latch Timeout的解析
[问题描述] 我们可能会在数据库的错误日志里,发现这么一条信息: A time-out occurred while waiting for buffer latch -- type 4, bp 00 ...
- Java精通并发-synchronized关键字原理详解
关于synchronized关键字原理其实在当时JVM的学习[https://www.cnblogs.com/webor2006/p/9595300.html]中已经剖析过了,这里从研究并发专题的角度 ...
- JDK源码那些事儿之LinkedBlockingDeque
阻塞队列中目前还剩下一个比较特殊的队列实现,相比较前面讲解过的队列,本文中要讲的LinkedBlockingDeque比较容易理解了,但是与之前讲解过的阻塞队列又有些不同,从命名上你应该能看出一些端倪 ...
- 开源项目阅读笔记--appium+adb
git上搜了几个platform的代码,有一个项目给我感触挺深的. https://github.com/ThomasHansson/Appium-cross-platform-example/tre ...
- LG4213 【模板】杜教筛(Sum)和 BZOJ4916 神犇和蒟蒻
P4213 [模板]杜教筛(Sum) 题目描述 给定一个正整数$N(N\le2^{31}-1)$ 求 $$ans_1=\sum_{i=1}^n\varphi(i)$$ $$ans_2=\sum_{i= ...