目录
整体思路(兵分三路)
游戏菜单界面
菜单实现选择
游戏核心内容
1. 声明初始化和打印函数
2. 玩家下棋
3. 电脑下棋
4. 判断对局输赢
游戏运行实现 (打游戏咯)
结果示例
1. 测试游戏的逻辑 ----- test.c
三子棋实现的模块 2. 游戏函数的声明 ----- game.h
3. 游戏函数的实现 ----- game.c
众所周知,一个游戏的菜单界面必不可少,内容无非就有 玩 和 退出 ,这时候,我们可以通过自定义一个函数来实现我们的菜单。
void menu()
{
printf("*******************************\n");
printf("******* 1. 开始游戏 *******\n");
printf("******* 0. 退出游戏 *******\n");
printf("*******************************\n");
}
我们可以通过选择数字来确认自己想玩还是不想玩,这时候就要用到 switch 语句来实现。
但假如玩完了一个对局后还想玩怎么办,可以通过使用 do while 来实现。我们可以将输入的数字来作为循环判断的条件,只要输入的数字为非零(即我们不想退出游戏),系统就判定循环条件为真,那么while就自然判定为继续循环。
int main()
{
int input = 0;
do
{
menu();
scanf("%d", &input);
switch (input)
{
case 1:
printf("开始三子棋游戏\n");
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,请重新选择\n");
break;
}
} while (input);
}
a. 输入1即开始游戏
b. 0退出游戏
c. 非零则会让你重新选择
代码执行截图:
我们知道,三子棋棋盘本质上是一个二维数组,我们可以通过其来实现棋盘的初始化和打印,即将棋盘初始化为空格。
1. 声明初始化和打印函数
通过char board[ ][ ] 来存储二维数组的数据, 通过全局定义ROW 和COL,提高代码的效率,后期还需多次使用行列值,或者作为修改代码的基础,如五子棋的实现。
//符号的定义
#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);
然后在game.c 文件中对函数进行实现
// 1. 初始化空格
void InitBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
// 2. 打印棋盘
void DisplayBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
// 将 " %c |" 作为数组每一项
printf(" %c ", board[i][j]);
if (j < col - 1)//除去最后一列 | 的打印
printf("|");
}
printf("\n");
if (i < row - 1)//除去最后一行 ---| 的打印
{
int j = 0;
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)//除去最后一列 | 的打印
printf("|");
}
printf("\n");
}
}
}
代码执行截图:
2. 玩家下棋
接下来实现 玩家下棋
我们首先要知道,棋盘的坐标与二维数组的坐标并不相同,我们下棋时是使用棋盘的坐标,而不是数组的坐标。即棋盘的(1,1)对应于数组的(0,0),所以我们要判断输入坐标的合法性。首先,我们要判断其输入范围,并且还要考虑到坐标被占用和坐标超出输入范围这两种情况。
1. 可以通过判断棋盘是否有 " "(空格)来输入 " * " 棋子。
2. 棋盘的行跟列坐标的是从 1 开始,到 定义过后的 ROW 和 COL 结束。 即可以分析出其坐标范围为 1 —— row , 1 —— col 。
3. 可以通过对棋盘坐标进行减一的运算存储到对应的二维数组坐标。
在此之前,要对相关函数在game.h进行声明,之后开始实现。
// 玩家下棋
void PlayerMove(char board [ROW][COL],int row,int col);
// 3. 玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int 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] == ' ')// (1,1) 坐标对应的是 board[0][0]
{
board[x - 1][y - 1] = '*';//玩家下 *
break;
}
else
{
printf("坐标被占用,请重新输入\n");
}
}
else
{
printf("坐标有误,请重新输入\n");
}
}
}
代码执行截图:
3. 电脑下棋
要实现电脑下棋,可以引用 rand()随机生成函数(随机字面理解就可以下哪就下哪,不会判断对局情况,即不会阻碍你棋路,老夫目前只会创建小白痴电脑,还不会创建大神级别电脑的算法,请大家多多包涵哈),引用这个函数前还需引用 srand((unsigned int)time(NULL))对其进行初始化。两个函数实现分别需引用
坐标占用情况同 玩家下棋 一致
电脑的落子也需要范围。我们不妨用 rand() 对 row 和 col 进行取余,%row、%col 生成的范围就为 0 - row、0 - col ,生成的下标不会大于其行列数本身,所以也就不需要判断其合法性。
在此之前,要对相关函数在game.h进行声明,之后开始实现。
//电脑下棋
void ComputerMove(char board[ROW][COL], int row,int col);
//4. 电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col)
{
printf("电脑下棋:>\n");
while (1)
{
int x = rand() % row;
int y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';//电脑下 #
break;
}
}
}
4. 判断对局输赢
对局结果情况无非就三种:
我们先定义一下不同的对局结果该返回什么
1. 玩家获得胜利 - *
2. 电脑获得胜利 - #
3. 平局 - D
我们可以自定义一个函数确认棋盘是否满了。满了返回 0,没满返回 1
int IsFull(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')
{
return 0;//棋盘没满
}
}
}
return 1;//棋盘满了
}
在此之前,要对相关函数在game.h进行声明,之后开始实现。
//判断游戏是否有输赢
char IsWin(char board[ROW][COL], int row,int col);
char IsWin(char board[ROW][COL], int row, int col)
{
int i = 0;
//判断三行
for (i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ')//除去三个空格连成一线的情况
{
return board[i][1];
}
}
//判断三列
for (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')//除去三个空格连成一线的情况
{
return board[1][i];
}
}
//判断对角线
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')//除去三个空格连成一线的情况
{
return board[1][1];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')//除去三个空格连成一线的情况
{
return board[1][1];
}
//判断平局 - 判断棋盘是否满了
//如果棋盘满了返回1,不满返回0
int ret = IsFull(board, row, col);
if (ret == 1)
{
return 'D';
}
//继续
return 'C';
}
void game()
{
char board[ROW][COL];
InitBoard(board, ROW, COL);
DisplayBoard(board, ROW, COL);
char ret = 0;//接收游戏状态
while (1)
{
//a.玩家下棋
PlayerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);// 下棋成功后打印棋盘
//判断玩家是否赢得游戏
ret = IsWin(board, ROW, COL);
if (ret != 'C')
break;
//b.电脑下棋
ComputerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);// 下棋成功后打印棋盘
//判断电脑是否赢得游戏
ret = IsWin(board, ROW, COL);
if (ret != 'C')
break;
}
if (ret == '*')
{
printf("恭喜你,打败了最强AI! (^ O ^)\n");
}
else if (ret == '#')
{
printf("不会吧,连小白痴人机也打不过? (——_——)||\n");
}
else
{
printf("高手过招,旗鼓相当\n");
}
DisplayBoard(board, ROW, COL);// 对局结果展示打印棋盘
}
代码执行截图:
以上就是三子棋的全部内容,老夫水平限制,目前实现不了高阶的棋盘游戏,本人也是第一次写博客和实现三子棋,若有什么错误也望请大佬们多多建议与指导。