发布时间:2024-01-06 11:30
需要补充的一点是,每次人/电脑下完棋,我们都肯定是想要看到效果的,所以每次下完棋,我们都需要打印一次棋盘,更新一次棋盘。
并且开始打印的棋盘都是视觉上的空棋盘,但实际上是我们用空格填充的。
棋盘,我们可以用一个二维数组来表示。
下边我们来具体看看怎么实现吧~
1.【打印菜单】
菜单里边肯定有我们选择到底是玩还是不玩吧,所以一定有两个选项.
下边提供一种较为简单的方法:
void menu()
{
printf(\"******************************\\n\");
printf(\"**** 1. play 0.exit ****\\n\");
printf(\"******************************\\n\");
}
2.【打印棋盘】
打印棋盘分为两个阶段,一个是还没有开始下棋的时候,另一个就是已经下的时候。
大体思路分析:
1.我们整体可以分为两个部分,一个是分割信息部分,另一个是非分隔信息部分。
2.很显然我们可以把它看成几个重复的小单元,通过for循环实现
实现的时候注意几个点:①换行②打印的条件——边界都是没有竖行/横线的,所以需要有一个打印分割信息的时候都需要有一个判断条件
void DisplayBoard(char board[ROW][COL], int row, int col)
{
int i, j;
for (i = 0;i < row;i++)
{
for (j = 0;j < col;j++)
{
//打印数据及与其较近的\'|\'
printf(\" %c \",board[i][j]);
if (j < col - 1)
printf(\"|\");
}
printf(\"\\n\");
//打印\'---\'及与其较近的\'|\'
if (i < row - 1)
{
int k = 0;
for (k = 0;k < col;k++)
{
printf(\"---\");
if(k<col-1)
printf(\"|\");
}
printf(\"\\n\");
}
}
}
其实未下棋与下棋是只有一个区别,是棋盘数据元素是空格还是代表电脑或者人的棋子的特殊符号。
所以在一开始打印棋盘的时候,我们还需要另外定义一个初始化棋盘的函数
void InitBoard(char board[ROW][COL], int row, int col)
{
int i, j;
for (i = 0;i < row;i++)
{
for (j = 0;j < col;j++)
{
board[i][j] = \' \';
}
}
}
在人/电脑下棋的时候将下棋位置的坐标修改成其他的元素,然后在此调用打印棋盘的函数,就能够得到想要的打印的结果了。
3.【人下棋】
人下棋是通过选择位置位置坐标来实现的。所以这个函数的实现我们只需要输入坐标,然后修改对应的元素值即可。
但是这个位置可不是随便修改的,有以下三种情况不能够选择,第一,是人原来已经占的位置,第二,是电脑原来占得位置,第三,是超过棋盘所能表示范围的位置。
只有当我们输入的坐标位置的元素是空格的时候,我们才能完成这次操作。
因此,这里我们可以通过一个while的死循环循环来实现,当发现输入的位置表示的元素是空格时我们修改并且跳出循环,否则一直选择位置。
void PlayerMove(char board[ROW][COL], int row, int col)
{
int x = 0, y = 0;
printf(\"玩家请下棋:>\\n\");
//要求在规定范围内,所以需要判断坐标的合理性
while(1)
{
printf(\"请输入坐标:>\");
scanf(\"%d%d\", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x - 1][y - 1] == \' \')
{
board[x - 1][y - 1] = \'*\';
break;
}
else
{
printf(\"坐标被占用,不能下棋,请重新选择其他位置\\n\");
}
}
else
{
printf(\"坐标非法,请重新输入\\n\");
}
}
}
4.【电脑下棋】
电脑下棋与人下棋类似,只不过电脑下棋的位置是我们用随机数产生的特定范围的坐标。
说明:随机数的种子,程序已经一开始种下
void ComputerMove(char board[ROW][COL], int row, int col)
{
printf(\"电脑下棋:>\\n\");
int x = 0, y = 0;
while (1)
{
x = rand() % row;//0~2
y = rand() % col;//0~2
if (board[x][y] == \' \')
{
board[x][y] = \'#\';
break;
}
}
}
5.【判断游戏状态】
我们通过列举将可能回赢的情况一一列举出来,然后进行判断即可。
不过在进行此函数代码书写之前,我们还需要进行判断棋盘是否满函数的定义,为判断是否平局的情况做准备。
char IsWin(char board[ROW][COL], int row, int col)
{
//先判断行
//判断列
//判断对角线
int i, j;
for (i = 0;i < row;i++)
{
for (j = 0;j < col;j++)
{
//其实这里判断的就有些局限了,只能够判断三子棋了
//判断行
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != \' \')
{
return board[i][0];
}
//判断列
if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[0][j] != \' \')
{
return board[0][j];
}
//判断对角线
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != \' \'
|| board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[2][0] != \' \')
{
return board[1][1];
}
}
//没人赢,就要平局——棋盘满了
if (IsFull(board, row, col))
{
return \'Q\';
}
else
{
return \'C\';//继续
}
}
}
int IsFull(char board[ROW][COL], int row, int col)
{
int i, j, tag = 1;
for (i = 0;i < row;i++)
{
for (j = 0;j < col;j++)
{
if (board[i][j] == \' \')
return 0;
}
}
return 1;
}
//game.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
//方便以后更改棋盘大小
#define ROW 3
#define COL 3
//初始化棋盘
void InitBoard(char board[ROW][COL],int row,int col);
//打印棋盘
void DisplayBoard(char board[ROW][COL], int row, int col);
//玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col);
//电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col);
//判断输赢——其实还是在弄数组元素值得判断
//玩家赢-‘*’
//电脑赢-‘#’
//平局-\'Q\'【以上三种都不能够再玩了】
//继续-\'C\'
char IsWin(char board[ROW][COL], int row, int col);
//test.c
//菜单
//打印棋盘
//下棋
#include \"game.h\"
void menu()
{
printf(\"******************************\\n\");
printf(\"**** 1. play 0.exit ****\\n\");
printf(\"******************************\\n\");
}
void game()
{
int ret;
//3*3的数组存放棋盘的信息
// 打印棋盘——下棋了打印空格,不下棋打印符号
//玩家下棋
// 电脑下棋
//判断输赢的过程
char board[ROW][COL] = { 0 };
//初始化棋盘的功能
InitBoard(board,ROW,COL);
//打印棋盘
DisplayBoard(board, ROW, COL);
//下棋
while (1)
{
//玩家部分
PlayerMove(board, ROW, COL);//其实就是对数组的操作
//判断输赢
ret= IsWin(board, ROW, COL);
if (ret != \'C\')
{
break;
}
DisplayBoard(board, ROW, COL);
//电脑部分
ComputerMove(board, ROW, COL);
//判断输赢
ret = IsWin(board, ROW, COL);
if (ret != \'C\')
{
break;
}
DisplayBoard(board, ROW, COL);
}
if (ret == \'#\')
printf(\"电脑赢了\\n\");
else if (ret == \'*\')
printf(\"玩家赢了\\n\");
else if (ret == \'Q\')
printf(\"平局了\\n\");
}
int main()
{
srand((unsigned int)time(NULL));//设置随机数的生成起点
int input;
do
{
menu();//打印菜单
printf(\"请选择:>\");
scanf(\"%d\", &input);
switch (input)
{
case 1:
game();
printf(\"开始游戏\\n\");
break;
case 0:
printf(\"退出游戏\\n\");
break;
default:
printf(\"选择错误,请重新选择\\n\");
break;
}
} while (input);
}
//game.c
#include \"game.h\"
//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col)
{
int i, j;
for (i = 0;i < row;i++)
{
for (j = 0;j < col;j++)
{
board[i][j] = \' \';
}
}
}
//打印棋盘
void DisplayBoard(char board[ROW][COL], int row, int col)
{
int i, j;
for (i = 0;i < row;i++)
{
for (j = 0;j < col;j++)
{
//打印数据
printf(\" %c \",board[i][j]);
if (j < col - 1)
printf(\"|\");
}
printf(\"\\n\");
//打印分割信息
if (i < row - 1)
{
int k = 0;
for (k = 0;k < col;k++)
{
printf(\"---\");
if(k<col-1)
printf(\"|\");
}
printf(\"\\n\");
}
}
}
//玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col)
{
int x = 0, y = 0;
printf(\"玩家请下棋:>\\n\");
//要求在规定范围内,所以需要判断坐标的合理性
while(1)
{
printf(\"请输入坐标:>\");
scanf(\"%d%d\", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x - 1][y - 1] == \' \')
{
board[x - 1][y - 1] = \'*\';
break;
}
else
{
printf(\"坐标被占用,不能下棋,请重新选择其他位置\\n\");
}
}
else
{
printf(\"坐标非法,请重新输入\\n\");
}
}
}
//电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col)
{
printf(\"电脑下棋:>\\n\");
int x = 0, y = 0;
while (1)
{
x = rand() % row;//0~2
y = rand() % col;//0~2
if (board[x][y] == \' \')
{
board[x][y] = \'#\';
break;
}
}
}
//判断输赢
//判断行
//判断列
//判断对角线
int IsFull(char board[ROW][COL], int row, int col)
{
int i, j, tag = 1;
for (i = 0;i < row;i++)
{
for (j = 0;j < col;j++)
{
if (board[i][j] == \' \')
return 0;
}
}
return 1;
}
char IsWin(char board[ROW][COL], int row, int col)
{
//先判断行
//判断列
//判断对角线
int i, j;
for (i = 0;i < row;i++)
{
for (j = 0;j < col;j++)
{
//其实这里判断的就有些局限了,只能够判断三子棋了
//判断行
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != \' \')
{
return board[i][0];
}
//判断列
if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[0][j] != \' \')
{
return board[0][j];
}
//判断对角线
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != \' \'
|| board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[2][0] != \' \')
{
return board[1][1];
}
}
//没人赢,就要平局——棋盘满了
if (IsFull(board, row, col))
{
return \'Q\';
}
else
{
return \'C\';
}
}
}
1.利用宏定义定义棋盘的大小,方便后续的更改
2.分文件编写,.h文件里边放头文件的引用和功能函数的声明,test.c文件里边是游戏整体逻辑的实现,game.c里边放的是游戏函数的定义。
3.棋盘如何打印——分成小块循环控制,还要特别注意边界的控制
4.判断输赢的操作如何实现,同时如何减少代码冗余——分类
5.如何实现人下棋和电脑下棋的操作
解决SpringCloud项目引用SpringCloud Config配置文件无效问题
邀请函|7月10日,九章云极DataCanvas邀您相约世界人工智能大会
GBDT与xgboost :流失预测 shap解释 调参 保存调参好的模型
数据结构 二叉树是什么?看完这篇你就知道了(包含二叉树面试题详解)
使用Scala/Java对Iceberg数据湖的Hive Catalog/Hadoop Catalog/HDFS Path进行表操作
【微服务~原始真解】Spring Cloud —— 什么是负载均衡?
反向代理神器 Nginx Proxy Manager 快速部署(Docker-compose)