一、基本逻辑
1.打印菜单界面,并实现进入或退出游戏的功能。
2.用二维数组来创建棋盘并对二维数组初始化。
3.在数组元素周围插入横竖线并打印实现简易的图形化效果。
4.玩家落子(玩家输入坐标的方式表示棋子的位置,o表示玩家棋子)。
5.电脑落子(产生随机数,x表示电脑落子)。
6.在每次玩家和电脑落子后都判断一次胜负关系(赢/输/平局/继续)。
7.根据胜负关系判断游戏是否继续进行。
void game()
{
char reason = 0;//接收判断输赢的返回值
char chessboard[ROW][COL] = {0};//用二维数组来存放棋盘信息
initialize(chessboard, ROW, COL);//将二维数组元素初始化为空格
board(chessboard, ROW, COL);//图形化棋盘
while (1)
{
player(chessboard, ROW, COL);//玩家先下棋
board(chessboard, ROW, COL);
reason = iswin(chessboard, ROW, COL);//判断玩家是否输赢
if (reason != 'c')
{
break;
}
computer(chessboard, ROW, COL);//电脑下棋
board(chessboard, ROW, COL);
reason = iswin(chessboard, ROW, COL);//判断电脑是否赢
if (reason != 'c')
{
break;
}
}
if (reason == 'o')
printf("玩家赢\n");
else if (reason == 'x')
printf("电脑赢\n");
else
printf("平局\n");
}
二、具体实现
1.打印菜单界面及进出游戏
void menu()
{
printf("**************************\n");
printf("* 1----play *\n");
printf("* 0----exit *\n");
printf("**************************\n");
}
void test()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();//打印菜单
printf("请选择:\n");
scanf("%d", &input);
switch (input)
{
case 1:
game();//游戏算法实现
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,请重新选择:\n");
break;
}
}
while (input);
{
;
}
}
2.创建并初始化棋盘及实现简易图形化
首先创建二维数组:
char chessboard[ROW][COL] = {0};//用二维数组来存放棋盘信息
这里用了宏定义的方式来设置棋盘的尺寸:
#define ROW 3
#define COL 3
使用宏定义原因是:提高代码的可读性,也提高了代码的拓展性,在以后想修改棋盘尺寸时会很方便。
初始化棋盘:
void initialize(char chessboard[ROW][COL],int row,int col)//采用遍历的方式将所有元素初始化为空格
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
chessboard[i][j] = ' ';
}
}
}
打印棋盘:
void board(char chessboard[ROW][COL], int row, int col)
{
// | |
// ---|---|---
// | | <———---棋盘样式
// ---|---|---
// | |
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
printf(" %c ", chessboard[i][j]);
if (j < col - 1)
printf("|");
}
printf("\n");
if (i < row - 1)
{
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
printf("\n");
}
}
}
这里为了贯彻上面所提到的代码的可读性与可拓展性,没有选择一行一行的打印棋盘,而是换了一种做法,在我们更改棋盘的尺寸时也可以很好的兼容。
3.玩家落子
棋盘的坐标表示分别为
(1,1)(1,2)(1,3)
(2,1)(2,2)(2,3)
(3,1)(3,2)(3,3)
void player(char chessboard[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("玩家走:\n");
while (1)
{
printf("请输入要下的坐标:\n");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (chessboard[x - 1][y - 1] == ' ')
{
chessboard[x - 1][y - 1] = 'o';
break;
}
else
printf("该坐标被占用,请重新输入: \n");
}
else
printf("坐标非法,请重新输入:\n");
}
}
4.电脑落子
这里电脑的落子,采用了生成随机数的方法,具体方式为调用rand()函数,并在调用rand()函数之前,先用srand()为伪随机数生成器播撒种子,种子采用系统时钟来生成。
首先要声明的头文件有:
#include<time.h>//time()的头文件
#include<stdlib.h>//rand()与srand()的头文件
具体用法:
srand((unsigned int)time(NULL));
x = rand() % row;
y = rand() % col;
要注意的是srand()一定要在rand()之前使用,否则每次随机种子就是一定的,那么产生出来的随机数就是固定的。
这里为了不让棋子的坐标超出棋盘范围,可以让每次的随机数对棋盘的尺寸取模,这样产生的结果只有0~2之间的数,从而产生的坐标范围就不会超出棋盘的大小。
void computer(char chessboard[ROW][COL], int row, int col)
{
printf("电脑走: \n");
int x = 0;
int y = 0;
while (1)
{
x = rand() % row;
y = rand() % col;
if (chessboard[x][y] == ' ')
{
chessboard[x][y] = 'x';
break;
}
}
}
5.判断胜负关系
char iswin(char chessboard[ROW][COL], int row, int col)
{
//返回的四种情况
//o:玩家赢
//x:电脑赢
//f:平局
//c:继续
int i = 0;
int j = 0;
for (i = 0; i < col; i++)
{
//横三行
if (chessboard[i][0] == chessboard[i][1] && chessboard[i][1] == chessboard[i][2] && chessboard[i][1] != ' ')
return chessboard[i][1];
}
for (j = 0; j < row; j++)
{
//竖三列
if (chessboard[0][j] == chessboard[1][j] && chessboard[1][j] == chessboard[2][j] && chessboard[1][j] != ' ')
return chessboard[1][j];
}
//斜两列
if (chessboard[0][0] == chessboard[1][1] && chessboard[1][1] == chessboard[2][2] && chessboard[1][1] != ' ')
return chessboard[1][1];
if (chessboard[0][2] == chessboard[1][1] && chessboard[1][1] == chessboard[2][0] && chessboard[1][1] != ' ')
return chessboard[1][1];
//判断是否棋盘满
if (1 == full(chessboard, row, col))
{
return 'f';
}
return 'c';
}
这里的四种情况分别返回四个不同的字符,然后再判断游戏的结果。
三、游戏效果
玩家赢:
电脑赢:
平局: