1. 三子棋
1.1 设计思路
首先说明本人使用的编译器是Visual Studio 2022。在本次设计三子棋及多子棋小游戏中,我准备将主体代码用一个头文件game.h和两个源文件game.c和test.c实现。其中game.h包含游戏函数的声明,game.c是游戏函数的实现,而test.c是用来测试游戏函数的。
我的设计思路如下:
(1)首先设计一个游戏菜单,用户可以通过游戏菜单的说明进行相应的游戏操作
(2)用二维数组创建一个棋盘,将棋盘初始化并且打印棋盘
(3)用二维数组记录每次玩家落子和电脑落子(用随机数解决)的状态
(4)每次玩家落子和电脑落子后,打印棋盘,判断是玩家赢,电脑赢,平局,还是继续游戏。
1.2 具体实现
1.2.1 设计游戏菜单
void menu()
{
printf("*****************************\n");
printf("******** 1. play *********\n");
printf("******** 0. exit *********\n");
printf("*****************************\n");
}
我们在test.c文件中写一个menu()函数,使用printf()函数打印菜单,玩家输入1时开始游戏,输入0时退出游戏。
因为要使用printf()函数,所以我们在game.h中引入头文件stdio.h。
#include<stdio.h>
因为玩家玩好一局游戏后,可能还想继续玩。所以这里我采用了do-while结构,同时用了switch语句来实现用户做出相应的选择后执行相应的功能。
int main()
{
int input = 0;
do
{
menu(); //打印菜单
printf("请选择:>");
scanf("%d", &input); //用户输入相应选择
switch (input)
{
case 1:
printf("开始游戏\n");
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,重新选择!\n");
break;
}
} while (input);
return 0;
}
1.2.2 设计棋盘
1.2.2.1 设计棋盘大小
这里我们用二维数组创建一个棋盘,棋盘的大小(行和列)用宏定义实现。使用宏定义能改变棋盘的大小,也为后面实现多子棋做铺垫。
#define ROW 3
#define COL 3
我们将二维数组先初始化为0,在test.c文件中写一个game()函数,在game()函数中实现整个游戏功能。
void game()
{
char board[ROW][COL] = {
0 };
}
同时我们对原先main()函数中的switch语句中的case 1:部分进行修改——将printf("开始游戏\n")更改成game()函数。
int main()
{
int input = 0;
do
{
menu(); //打印菜单
printf("请选择:>");
scanf("%d", &input); //用户输入相应选择
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,重新选择!\n");
break;
}
} while (input);
return 0;
}
我们之后就要不断扩展game()函数的功能。
1.2.2.2 初始化棋盘
我们将棋盘初始化为空格,提供落子空间。
在game.h文件中进行InitBoard()的函数声明:
void InitBoard(char board[ROW][COL], int row, int col);
在game.c文件中进行InitBoard()的函数实现:
void InitBoard(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
for (int j = 0; j < col; j++)
board[i][j] = ' ';
}
同时在test.c文件的game()函数中增加相应内容:
void game()
{
char board[ROW][COL] = {
0 };
InitBoard(board, ROW, COL);
}
1.2.2.3 打印棋盘
这里我们要设计一个棋盘,我的想法是实现一个如下图的棋盘。
要实现这样一个棋盘,我们可以把问题简化成打印数据和打印分割线。
首先我们在game.h文件中进行DisplayBoard()的函数声明:
void DisplayBoard(char board[ROW][COL], int row, int col);
在game.c文件中进行DisplayBoard()的函数实现:
void DisplayBoard(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
//1. 打印数据
for (int j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
printf("|");
}
printf("\n");
//2. 打印分割线
if (i < row - 1)
{
for (int j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
printf("\n");
}
}
}
当玩家选择1时就能看到如图的棋盘。
我们同时在test.c文件中的game()函数中增加相应内容:
void game()
{
char board[ROW][COL] = {
0 };
InitBoard(board, ROW, COL);
DisplayBoard(board, ROW, COL);
}
1.2.3 设计下棋步骤
1.2.3.1 玩家下棋
在game.h文件中进行PlayerMove()的函数声明:
void PlayerMove(char board[ROW][COL], int row, int col);
玩家下棋时,落子在棋盘上,所以我们需要设置x,y两个变量表示玩家落子的位置。落子需要在二维数组不越界的条件下,所以我使用了if语句判断坐标是否合法,在坐标合法的情况下,如果棋盘对应位置没有落子(即为空格),玩家就可依落子。我们将玩家的落子标记为'*'。因为要贴近人们的习惯,所以我将左上角的坐标标成1 1而不是0 0。因为玩家要多次落子,所以我们在最外面加一个while(1)的循环,当玩家落子完后,我们就break退出循环。
在game.c文件中进行PlayerMove()的函数实现:
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] == ' ')//可以落子,
{
//这里用x-1.y-1是因为规则定义左上角为1 1,
board[x - 1][y - 1] = '*'; //而数组存储的第一个元素下标是0 0,所以行和列都需减去1
break;
}
else//不能落子
{
printf("坐标被占有,不能落子,重新输入坐标\n");
}
}
else//非法
{
printf("坐标非法,重新输入\n");
}
}
}
同时我们想知道玩家落子完后棋盘的状态,我们可以在玩家每次落子后打印棋盘的状态。所以在test.c的game()函数中调用PlayerMove()函数和DisplayBoard()函数。
void game()
{
char board[ROW][COL] = {
0 };
InitBoard(board, ROW, COL); //初始化棋盘
DisplayBoard(board, ROW, COL); //打印棋盘
PlayerMove(board, ROW, COL); //玩家下棋
DisplayBoard(board, ROW, COL); //打印棋盘
}
选择1后,玩家如果输入1 1,则在棋盘的左上角就会出现*f符号。
1.2.3.2 电脑下棋
在game.h文件中进行ComputerMove()的函数声明:
void ComputerMove(char board[ROW][COL], int row, int col);
电脑下棋时,落子在棋盘上,所以我们也需要设置x,y两个变量表示玩电脑落子的位置。这里我使用了rand()随机数函数,通过rand()%row,获得0~row-1的值,通过rand()%col,获得0~col-1的值,从而确保落子的位置不越界,棋子合法落在棋盘上。从我们将玩家的落子标记为'#'。因为电脑要多次落子,所以我们在最外面加一个while(1)的循环,当电脑落子完后,我们就break退出循环。
因为要使用rand()函数,所以我们先简单了解下这个函数,这个函数的头文件是stdlib.h。
这个函数会返回一个范围在0~RAND_MAX(至少是32767)的伪随机整数。
在调用rand()函数产生随机数前,我们可以先使用srand()函数设置随机数种子(seed)。 如果没有设置随机数种子, rand()在调用时会自动设随机数种子为1。随机数种子相同,每次产生的随机数也会相同。
srand()函数也包含在stdlib.h头文件中。
我们还需要使用time()函数,该函数的头文件是time.h。
time()函数功能是获取当前时间,并将其转换为time_t类型的值。
其中,timet *time 是一个指向time t 类型变量的指针,用于存储获取到的时间值。如果t为NULL,则表示不需要存储时间值,只需要返回当前时间的time_t类型值。
因为我们的程序中需要使用rand()、srand()、time()这三个函数,所以我们要在game.h中引入相应的头文件。
#include<stdlib.h>
#include<time.h>
我们需要在test.c的main函数中添加代码:
srand((unsigned int)time(NULL));
/*用于生成随机数种子。
srand()函数接受一个unsigned int整型参数,它被用来初始化随机数生成器的种子。
time(NULL)函数返回当前时间的秒数,并将其转换为无符号整数值,然后作为种子传递给srand函数。
这样做的目的是使每次程序执行时都生成不同的随机序列。*/
接下来我们在game.c文件中进行DisplayBoard()的函数实现:
void ComputerMove(char board[ROW][COL], int row, int col)
{
int x = 0; //0~row-1
int y = 0; //0~col-1
printf("电脑下棋:>\n");
while (1)
{
x = rand() % row;
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
同时我们想知道电脑落子完后棋盘的状态,我们可以在电脑每次落子后打印棋盘的状态。所以在test.c的game()函数中调用PlayerMove()函数和DisplayBoard()函数。
void game()
{
char board[ROW][COL] = {
0 };
InitBoard(board, ROW, COL); //初始化棋盘
DisplayBoard(board, ROW, COL); //打印棋盘
PlayerMove(board, ROW, COL); //玩家下棋
DisplayBoard(board, ROW, COL); //打印棋盘
ComputerMove(board, ROW, COL); //电脑下棋
DisplayBoard(board, ROW, COL); //打印棋盘
}
1.2.3.3 设计判断输赢的函数
当玩家和电脑下完棋时,我们要判断输赢。这里我们使用'*'表示玩家赢,'#'表示电脑赢,'Q'表示平局,'C'表示继续游戏。
在game.h文件中进行IsWin()的函数声明:
char IsWin(char board[ROW][COL], int row, int col);
三子棋游戏的目标是在一个3x3的棋盘上先将自己的棋子连成一条直线的玩家获胜。在判断输赢时,需要检查横向、纵向和对角线上是否存在连续的三个相同棋子。如果以上三种情况都不存在,而且棋盘已经放满,那么游戏结束,平局。
我们先在game.h中声明判断棋盘是否放满的IsFull()函数:
int IsFull(char board[ROW][COL], int row, int col);
要判断棋盘是否放满,非常简单,我们只要使用两层for循环遍历一下棋盘,如果有棋盘格的状态为空格,这说明没有放。当完整遍历完后,如果所有棋盘格的状态都不会空格,说明放满了。
我们在game.c文件中实现IsFull()函数:
int IsFull(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
if (board[i][j] == ' ')
return 0;
}
}
return 1;
}
我们通过for循环分别遍历行和列判断是否有三个棋子连成一条直线,同时通过if语句判断主对角线和副对角线是否有三个棋子连成一条直线。若以上都没有,我们检查一下棋盘是否放满,若放满则是平局,否则我们继续游戏。
在game.c文件中实现判断输赢的函数IsWin():
char IsWin(char board[ROW][COL], int row, int col)
{
//赢
//行
for (int i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
return board[i][0];
}
//列
for (int i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
return board[0][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];
//平局
if (IsFull(board, row, col))
{
return 'Q';
}
//继续
return 'C';
}
因为玩家和电脑要依次下棋直到分出输赢,所以我们在外层要加一个while(1)的循环。同时我们需要使用一个变量ret来记录游戏进程和游戏结果,如果ret值为'C'表示继续游戏,否则退出游戏。通过最后ret的值判断输赢。如果ret值为'*'表示玩家赢,ret值为'#'表示电脑赢,ret值为'Q'表示平局。
所以t我们在test.c文件中实现game()函数:
void game()
{
char board[ROW][COL] = {
0 };
InitBoard(board, ROW, COL);
//打印棋盘
DisplayBoard(board, ROW, COL);
char ret = 0;
while (1)
{
//下棋
//玩家下棋
PlayerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
//判断输赢
ret = IsWin(board, ROW, COL);
if (ret != 'C')
break;
//电脑下棋
ComputerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
//判断输赢
ret = IsWin(board, ROW, COL);
if (ret != 'C')
break;
}
if (ret == '*')
printf("玩家赢\n");
else if (ret == '#')
printf("电脑赢\n");
else
printf("平局\n");
}
1.3 完整代码
1.3.1 game.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#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);
//判断棋盘是否放满
int IsFull(char board[ROW][COL], int row, int col);
//判断输赢
//玩家赢 - '*'
//电脑赢 - '#'
//平局 - 'Q'
//继续 - 'C
char IsWin(char board[ROW][COL], int row, int col);
1.3.2 game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
//初始化棋盘为空格
void InitBoard(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
for (int j = 0; j < col; j++)
board[i][j] = ' ';
}
//打印棋盘
void DisplayBoard(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
//1. 打印数据
for (int j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
printf("|");
}
printf("\n");
//2. 打印分割线
if (i < row - 1)
{
for (int j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
printf("\n");
}
}
}
//玩家下棋
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] == ' ')//可以落子
{
board[x - 1][y - 1] = '*';
break;
}
else//不能落子
{
printf("坐标被占有,不能落子,重新输入坐标\n");
}
}
else//非法
{
printf("坐标非法,重新输入\n");
}
}
}
//电脑随机下棋
void ComputerMove(char board[ROW][COL], int row, int col)
{
int x = 0; //0~row-1
int y = 0; //0~col-1
printf("电脑下棋:>\n");
while (1)
{
x = rand() % row;
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
//判断棋盘是否放满
int IsFull(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
if (board[i][j] == ' ')
return 0;
}
}
return 1;
}
//判断输赢
char IsWin(char board[ROW][COL], int row, int col)
{
//赢
//行
for (int i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
return board[i][0];
}
//列
for (int i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i]&&board[0][i]!=' ')
return board[0][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];
//平局
if (IsFull(board,row,col))
{
return 'Q';
}
//继续
return 'C';
}
1.3.3 test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void menu()
{
printf("*****************************\n");
printf("******** 1. play *********\n");
printf("******** 0. exit *********\n");
printf("*****************************\n");
}
void game()
{
char board[ROW][COL] = {
0 };
InitBoard(board, ROW, COL);
//打印棋盘
DisplayBoard(board, ROW, COL);
char ret = 0;
while (1)
{
//下棋
//玩家下棋
PlayerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
//判断输赢
ret = IsWin(board, ROW, COL);
if (ret != 'C')
break;
//电脑随机下棋
ComputerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
//判断输赢
ret = IsWin(board, ROW, COL);
if (ret != 'C')
break;
}
if (ret == '*')
printf("玩家赢\n");
else if (ret == '#')
printf("电脑赢\n");
else
printf("平局\n");
}
int main()
{
int input = 0;
srand((unsigned int) time(NULL));
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,重新选择!\n");
break;
}
} while (input);
return 0;
}
2. 多子棋
2.1 思路分析和代码改进
前面实现三子棋的判断输赢中我们使用了如下代码:
char IsWin(char board[ROW][COL], int row, int col)
{
//赢
//行
for (int i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
return board[i][0];
}
//列
for (int i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
return board[0][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];
//平局
if (IsFull(board, row, col))
{
return 'Q';
}
//继续
return 'C';
}
我们发现这段代码有一定的局限性,当是n子棋(n>3)时,上述代码就不适用了,所以我们需要进行改进。
(1)对于行的判断,我们可以用i和j两个变量进行两重for循环,外层用i遍历行数,内层用j从0遍历到列数-1,两两判断一行中两个相邻的数组元素,如果不相等或者有没放棋子的棋盘格,我们使用break退出。每次遍历完一行时,进行判断,如果j==列数-1,说明这一行有n个棋子相连。
(2)对于列的判断,我们可以用j和i两个变量进行两重for循环,外层用j遍历列数,内层用i从0遍历到行数-1,两两判断一列中两个相邻的数组元素,如果不相等或者有没放棋子的棋盘格,我们使用break退出。每次遍历完一列时,进行判断,如果i==行数-1,说明这一列有n个棋子相连。
(3)对于主对角线的判断,我们可以用i和j两个变量进行两重for循环,外层用i遍历从0到行数-1,内层用j从0遍历到1,两两判断主对角线上两个相邻的数组元素,如果不相等或者有没放棋子的棋盘格,我们使用break退出。当遍历完主对角线时,进行判断,如果j==列数-1,说明主对角线有n个棋子相连。
(4)对于副对角线的判断,我们可以用i和j两个变量进行两重for循环,外层用i遍历从0到行数-1,内层用j从列数-1遍历到1,两两判断副对角线上两个相邻的数组元素,如果不相等或者有没放棋子的棋盘格,我们使用break退出。当遍历完副对角线时,进行判断,如果i==行数-1,说明副对角线有n个棋子相连。
char IsWin(char board[ROW][COL], int row, int col)
{
//赢
//行
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
j = 0;
for (j = 0; j < col - 1; j++)
{
if (board[i][j] != board[i][j + 1] || board[i][j] == ' ')
break;
}
if (j == col - 1)
return board[i][j];
}
//列
i = 0;
j = 0;
for (j = 0; j < col; j++)
{
i = 0;
for (i = 0; i < row - 1; i++)
{
if (board[i][j] != board[i + 1][j] || board[i][j] == ' ')
break;
}
if (i == row - 1)
return board[i][j];
}
//主对角线
i = 0;
j = 0;
for (i = 0; i < row - 1; i++)
{
j = 0;
for (j = 0; j < col - 1; j++)
{
if (board[i][j] != board[i + 1][j + 1] || board[i][j] == ' ')
break;
}
if (j == col - 1)
return board[i][j];
}
//副对角线
i = 0;
j = 0;
for (i = 0; i < row - 1; i++)
{
j = 0;
for (j = col - 1; j > 0; j--)
{
if (board[i][j] != board[i + 1][j - 1] || board[i][j] == ' ')
break;
}
if (i == row - 1)
return board[i][j];
}
//平局
if (IsFull(board, row, col))
{
return 'Q';
}
//继续
return 'C';
}
为了方便测试,我们此时宏定义ROW为5,COL为5
#define ROW 5
#define COL 5
2.2 完整代码
2.2.1 game.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 5
#define COL 5
//初始化棋盘
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);
//判断棋盘是否放满
int IsFull(char board[ROW][COL], int row, int col);
//判断输赢
//玩家赢 - '*'
//电脑赢 - '#'
//平局 - 'Q'
//继续 - 'C
char IsWin(char board[ROW][COL], int row, int col);
2.2.2 game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
//初始化棋盘为空格
void InitBoard(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
for (int j = 0; j < col; j++)
board[i][j] = ' ';
}
//打印棋盘
void DisplayBoard(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
//1. 打印数据
for (int j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
printf("|");
}
printf("\n");
//2. 打印分割线
if (i < row - 1)
{
for (int j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
printf("\n");
}
}
}
//玩家下棋
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] == ' ')//可以落子
{
board[x - 1][y - 1] = '*';
break;
}
else//不能落子
{
printf("坐标被占有,不能落子,重新输入坐标\n");
}
}
else//非法
{
printf("坐标非法,重新输入\n");
}
}
}
//电脑随机下棋
void ComputerMove(char board[ROW][COL], int row, int col)
{
int x = 0; //0~row-1
int y = 0; //0~col-1
printf("电脑下棋:>\n");
while (1)
{
x = rand() % row;
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
int IsFull(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int 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 = 0;
int j = 0;
for (i = 0; i < row; i++)
{
j = 0;
for (j = 0; j < col - 1; j++)
{
if (board[i][j] != board[i][j + 1] || board[i][j] == ' ')
break;
}
if (j == col - 1)
return board[i][j];
}
//列
i = 0;
j = 0;
for (j = 0; j < col; j++)
{
i = 0;
for (i = 0; i < row - 1; i++)
{
if (board[i][j] != board[i + 1][j] || board[i][j] == ' ')
break;
}
if (i == row - 1)
return board[i][j];
}
//主对角线
i = 0;
j = 0;
for (i = 0; i < row - 1; i++)
{
j = 0;
for (j = 0; j < col - 1; j++)
{
if (board[i][j] != board[i + 1][j + 1] || board[i][j] == ' ')
break;
}
if (j == col - 1)
return board[i][j];
}
//副对角线
i = 0;
j = 0;
for (i = 0; i < row - 1; i++)
{
j = 0;
for (j = col - 1; j > 0; j--)
{
if (board[i][j] != board[i + 1][j - 1] || board[i][j] == ' ')
break;
}
if (i == row - 1)
return board[i][j];
}
//平局
if (IsFull(board, row, col))
{
return 'Q';
}
//继续
return 'C';
}
2.2.3 test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void menu()
{
printf("*****************************\n");
printf("******** 1. play *********\n");
printf("******** 0. exit *********\n");
printf("*****************************\n");
}
void game()
{
char board[ROW][COL] = {
0 };
InitBoard(board, ROW, COL);
//打印棋盘
DisplayBoard(board, ROW, COL);
char ret = 0;
while (1)
{
//下棋
//玩家下棋
PlayerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
//判断输赢
ret = IsWin(board, ROW, COL);
if (ret != 'C')
break;
//电脑下棋
ComputerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
//判断输赢
ret = IsWin(board, ROW, COL);
if (ret != 'C')
break;
}
if (ret == '*')
printf("玩家赢\n");
else if (ret == '#')
printf("电脑赢\n");
else
printf("平局\n");
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,重新选择!\n");
break;
}
} while (input);
return 0;
}
3. 总结
到这里,我们的三子棋及多子棋小游戏的设计就结束了,通过设计该游戏,我增加了对二维数组和循环结构的理解,也熟悉了随机数函数的使用,学习使用了宏定义,提高了自定义函数的编写能力和分析问题的能力。
希望通过后续学习,不断提高代码能力和分析解决问题的能力。由于本人是大一学生,知识水平有限,本文如果有错误和不足之处,还望各位大佬多多指出并提出建议!