游戏规则
有如下图的一个棋盘,一方下白子,一方下黑子,直到出现第一个三点一线,游戏结束!
创建棋盘
我们要设计这个游戏,首先就出现几个问题。
如何设计棋盘呢? 创建一个3*3的二维数组,每个元素是一个 char类型。
用‘x’表示黑子(玩家1),用‘o’表示白子(玩家2),用‘ ’(空格)表示空白,这样,棋盘就设计好了。
游戏流程
1、创建棋盘,并且初始化~ 把所有的位置都设为空格~
做两个循环就可以啦,一个控制行,一个控制列
void init(char chess[MAX_ROW][MAX_COL])
{
for (int row = 0; row < MAX_ROW; row++)
{
for (int col = 0; col < MAX_COL; col++)
{
chess[row][col] = ' ';
}
} //注意这里MAX_ROW 和MAX_COL的值,虽然我们知道是三,但还是要进行宏定义,这样可以避免重复的3的意义,提高代码的可读性
}
2、打印棋盘~
我们需要做一个打印函数;
一是要把chess[row][col]打印出来;
二是要把棋盘作美化;
void print(char chess[MAX_ROW][MAX_COL])
{
printf("+---+---+---+\n");
for (int row = 0; row < MAX_ROW; row++)
{
printf("|");
for (int col = 0; col < MAX_COL; col++)
{
printf(" %c |", chess[row][col]);
}
printf("\n+---+---+---+\n");
}
}
我们来看一下效果:
是不是很可观呢?
3、玩家进行落子~ 我们创建的是二维数组,就让玩家输入一组坐标(row,col)进行落子~
玩家进行落子,是不是玩家一次,电脑一次,玩家一次……这是一个循环呀!
但这里我们还需要注意的问题是:玩家会不会胡乱输入呀?有两种情况:
1.输入的位置超出chess数组范围,就是下到棋盘外面去了;
2.输入的位置之前以及有子了;
这就需要我们进行合法性判定了;
那怎么落子啊? 输入对应位置坐标,将该位置的棋盘初始化成‘*’就好了
void playerMove(char chessBoard[MAX_ROW][MAX_COL])
{
printf("玩家落子....\n");
while (1)
{
printf("请输入坐标(row col): ");
int row = 0;
int col = 0;
scanf("%d %d", &row, &col);
// 进行合法性判定
//是否越界,合法继续,不合法重新输入
if (row < 0 || row >= MAX_ROW || col < 0 || col >= MAX_COL)
{
printf("您输入的坐标非法! 请重新输入!\n");
continue;
}
//是否有子
if (chessBoard[row][col] != ' ')
{
printf("您输入的位置已经有子了, 请重新输入!\n");
continue;
}
// 进行落子~~
chessBoard[row][col] = 'x';
break;
}
}
4、判定获胜~
判定胜负有三种情况,玩家胜,电脑胜,和棋!
1.胜负:遍历所有行,所有列,还有对角线,有对应的三个数不为空格且相等就说明游戏结束了,我们返回这条线上的任意一个文章,如果是‘x’,就说明玩家胜,如果是‘o’,就是电脑胜了
2.和棋:判定标准就是,只要棋盘满了就和棋了。遍历棋盘所有位置,不是空格就满了。
这里我们分别设置一个函数来判断!来看操作:
// 返回 1 表示满了, 返回 0 表示没满
int isFull(char chessBoard[MAX_ROW][MAX_COL])
{
// 遍历棋盘, 看看有没有空格. 有空格就是没满~~
for (int row = 0; row < MAX_ROW; row++)
{
for (int col = 0; col < MAX_COL; col++)
{
if (chessBoard[row][col] == ' ')
{
return 0;
}
}
}
return 1;
}
// 此处约定,
// 如果返回 x, 表示 玩家获胜
// 如果返回 o, 表示 电脑获胜
// 如果返回 ' ', 表示胜负未分, 还要继续下棋
// 如果返回 q, 表示和棋
char isGameOver(char chessBoard[MAX_ROW][MAX_COL])
{
// 扫描所有的行, 所有的列, 以及两个对角线~~
for (int row = 0; row < MAX_ROW; row++)
{
if (chessBoard[row][0] != ' '
&& chessBoard[row][0] == chessBoard[row][1]
&& chessBoard[row][0] == chessBoard[row][2])
{
return chessBoard[row][0];
}
}
for (int col = 0; col < MAX_COL; col++)
{
if (chessBoard[0][col] != ' '
&& chessBoard[0][col] == chessBoard[1][col]
&& chessBoard[0][col] == chessBoard[2][col])
{
return chessBoard[0][col];
}
}
if (chessBoard[0][0] != ' '
&& chessBoard[0][0] == chessBoard[1][1]
&& chessBoard[0][0] == chessBoard[2][2])
{
return chessBoard[0][0];
}
if (chessBoard[0][2] != ' '
&& chessBoard[0][2] == chessBoard[1][1]
&& chessBoard[0][2] == chessBoard[2][0])
{
return chessBoard[0][2];
}
// 判定是否和棋
if (isFull(chessBoard))
{
return 'q';
}
// 胜负未分
return ' ';
}
5、电脑进行落子~(随机落子)
电脑怎么进行落子呀?把某个位置(空位置)初始化成‘o’就好了
这里我们需要注意两个关键词: 随机 空位置
看到空位置,我们就知道进行合法性判断啦,不能落在以及有子的位置。那我们为什么不判断落子的位置是否越界呢?
这就需要注意到随机啦,上次的猜数字游戏中我们谈到,使用rand()函数可以自定义随机数产生的范围,还记得用法吗? rand()%rand_max求0~rand_max的随机值; rand()% (Y-X+1)+X;求 X~Y的随机值
注意这样产生的随机数是固定的,如果需要每次运行都产生不同的随机数,我们就需要借助时间戳了。引入随机数种子srand((unsigned int )time(NULL));即可
void computerMove(char chessBoard[MAX_ROW][MAX_COL])
{
while (1) {
int row = rand() % MAX_ROW;
int col = rand() % MAX_COL;
if (chessBoard[row][col] != ' ')
{
// 这个位置已经有子了
continue;
}
chessBoard[row][col] = 'o';
break;
}
}
6、判定获胜~
代码同上,逻辑上这一步存在的意义是:玩家落子完,判断胜负;电脑落子完,判断胜负;
完整实现
#define MAX_ROW 3
#define MAX_COL 3
void init(char chess[MAX_ROW][MAX_COL]) {
for (int row = 0; row < MAX_ROW; row++) {
for (int col = 0; col < MAX_COL; col++) {
chess[row][col] = ' ';
}
}
}
void print(char chess[MAX_ROW][MAX_COL]) {
printf("+---+---+---+\n");
for (int row = 0; row < MAX_ROW; row++) {
printf("|");
for (int col = 0; col < MAX_COL; col++) {
printf(" %c |", chess[row][col]);
}
printf("\n+---+---+---+\n");
}
}
void playerMove(char chessBoard[MAX_ROW][MAX_COL]) {
printf("玩家落子....\n");
while (1) {
printf("请输入坐标(row col): ");
int row = 0;
int col = 0;
scanf("%d %d", &row, &col);
// 进行合法性校验, 判定用户输入的内容是否是合法的
// 如果不合法, 就让用户重新输入
if (row < 0 || row >= MAX_ROW || col < 0 || col >= MAX_COL) {
// 就是不合法, 于是要让用户重新输入
printf("您输入的坐标非法! 请重新输入!\n");
continue;
}
// 假设用户输入了1, 1, 但是 1 1 位置已经有子了~~
if (chessBoard[row][col] != ' ') {
// 该位置已经有子了
printf("您输入的位置已经有子了, 请重新输入!\n");
continue;
}
// 进行落子~~
chessBoard[row][col] = 'x';
break;
}
}
void computerMove(char chessBoard[MAX_ROW][MAX_COL]) {
while (1) {
int row = rand() % MAX_ROW;
int col = rand() % MAX_COL;
if (chessBoard[row][col] != ' ') {
// 这个位置已经有子了
continue;
}
chessBoard[row][col] = 'o';
break;
}
}
// 返回 1 表示满了, 返回 0 表示没满
int isFull(char chessBoard[MAX_ROW][MAX_COL]) {
// 遍历棋盘, 看看有没有空格. 有空格就是没满~~
for (int row = 0; row < MAX_ROW; row++) {
for (int col = 0; col < MAX_COL; col++) {
if (chessBoard[row][col] == ' ') {
return 0;
}
}
}
return 1;
}
// 此处约定,
// 如果返回 x, 表示 玩家获胜
// 如果返回 o, 表示 电脑获胜
// 如果返回 ' ', 表示胜负未分, 还要继续下棋
// 如果返回 q, 表示和棋
char isGameOver(char chessBoard[MAX_ROW][MAX_COL]) {
// 扫描所有的行, 所有的列, 以及两个对角线~~
for (int row = 0; row < MAX_ROW; row++) {
if (chessBoard[row][0] != ' '
&& chessBoard[row][0] == chessBoard[row][1]
&& chessBoard[row][0] == chessBoard[row][2]) {
return chessBoard[row][0];
}
}
for (int col = 0; col < MAX_COL; col++) {
if (chessBoard[0][col] != ' '
&& chessBoard[0][col] == chessBoard[1][col]
&& chessBoard[0][col] == chessBoard[2][col]) {
return chessBoard[0][col];
}
}
if (chessBoard[0][0] != ' '
&& chessBoard[0][0] == chessBoard[1][1]
&& chessBoard[0][0] == chessBoard[2][2]) {
return chessBoard[0][0];
}
if (chessBoard[0][2] != ' '
&& chessBoard[0][2] == chessBoard[1][1]
&& chessBoard[0][2] == chessBoard[2][0]) {
return chessBoard[0][2];
}
// 判定是否和棋
if (isFull(chessBoard)) {
return 'q';
}
// 胜负未分
return ' ';
}
int main()
{
// 不建议使用全局变量
// 搜索树
char chessBoard[MAX_ROW][MAX_COL];
// 1. 对棋盘进行初始化
init(chessBoard);
char winner = ' ';
while (1) {
// 2. 打印棋盘
print(chessBoard);
// 3. 玩家落子
playerMove(chessBoard);
// 4. 判定胜负
winner = isGameOver(chessBoard);
if (winner != ' ') {
// 游戏结束
break;
}
// 5. 电脑落子
computerMove(chessBoard);
// 6. 判定胜负
winner = isGameOver(chessBoard);
if (winner != ' ') {
// 游戏结束
break;
}
}
if (winner == 'x') {
printf("恭喜你赢了!\n");
}
else if (winner == 'o') {
printf("你咋连人工智障都下不过!\n");
}
else {
printf("你和人工智障五五开!\n");
}
system("pause");
return 0;