三子棋想必大家都不陌生,甚至和小伙伴玩了不知道多少遍,我也不例外。
特别是以前电子产品不普及的时候,那个时候那张纸,画个井字,就可以和小伙伴玩了。
那么今天我将来介绍一下如何用C语言设计简易的三子棋游戏。(我们规定玩家的棋子为’*’,电脑的棋子为’#’)
首先进入游戏,我们需要设计一个菜单内容,大概是下面这个样子:
用四个printf函数即可实现
void menu()
{
printf("#######################\n");
printf("#### 1.play ####\n");
printf("#### 0.exit ####\n");
printf("#######################\n");
}
然后对于选项我们需要做出相应的响应,即玩家选1时开始游戏,玩家选0时结束游戏,玩家输入其他数字则提示玩家重新输入,以保证代码的健壮性,故我们可以用一个switch语句实现,设置一个input变量以接收玩家的输入,而且为了让玩家可以多次游玩,我们使用一个do while语句来保证游戏的重复,代码实现如下:
int main()
{
int input = 0;
do
{
menu();//打印菜单
printf("请选择:\n");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("游戏结束,程序退出\n");
break;
default:
printf("选择错误,请重新选择:\n");
break;
}
} while (input);
return 0;
}
接下来就需要实现这里的game()函数了,首先我们要设计一个棋盘来进行游戏,如何构建一个棋盘呢,首先我们要知道棋盘的大致样子:
从图中我们可以看出三子棋的棋盘有五行组成,那么我们可以用循环来打印出棋盘,这里我们用char型的二维数组存放棋盘中的棋子,代码如下:
//符号的定义,之后更改棋盘大小更加方便
#define ROW 3
#define COL 3
//设置棋盘--二维数组
char board[ROW][COL];
//初始化棋盘
InitBroad(board, ROW, COL);
//打印棋盘
DisplayBroad(board, ROW, COL);
函数实现:
void InitBroad(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] = ' ';
}
}
}
void DisplayBroad(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++)//棋盘列数
{
printf(" %c ", board[i][j]);
if (j < col - 1)//保证棋盘的美观性,最后一列的‘|’不打印
printf("|");
}
printf("\n");//换行
if (i < row - 1)//同意棋盘最后一行的‘--- ’也不打印
for (j = 0; j < col; j++)
printf("--- ");
printf("\n");
}
}
注意这里的数组初始化是必要的,否则数组的打印可能是随机的(如图):
打印出棋盘后就需要实现玩家和电脑的交互了,首先来实现玩家走的部分:
//玩家走
PlayerMove(board, ROW, COL);
DisplayBroad(board, ROW, COL);//每次走完更新一次棋盘
由于数组的下标是从0开始的,而玩家一般认为坐标是总1开始的,故在处理玩家输入的坐标时要-1确保落子的正确性,同时要判断玩家输入的坐标的合法性,是否落在棋盘内且该处无棋子,那么代码的实现就很明显了:
void PlayerMove(char board[ROW][COL], int row, int col)
{
printf("玩家走:\n");
while (1)
{
printf("请输入坐标:\n");
int x = 0;//接收坐标
int y = 0;
scanf("%d %d", &x, &y);
//判断坐标的合法性
if (x >= 1 && x <= row && y >= 1 && y <= col && board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '*';
break;
}
else
{
printf("坐标非法,请重新输入:\n");
}
}
}
对于电脑,我们使用随机数来确定电脑的落子,则需要使用到rand()函数产生随机数,而电脑的落子是有我们设计的,故不需要判断合法性,代码实现与玩家略有不同:
void ComputerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
srand((unsigned int)time(NULL));
printf("电脑走:\n");
while (1)
{
x = rand() % 3;//产生0-2的随机数字作为数组下标
y = rand() % 3;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
最后也是最为关键的步骤就是判断游戏进程,游戏每落下一次子就会产生四种状态,即玩家赢,电脑赢,平局以及游戏继续,不妨令这些状态分别对应四个不同的字符,即玩家赢:返回’*’,电脑赢,返回’#’,平局,返回’Q’,游戏继续,返回’C’,这里我们设计一个返回类型为char型的Judgegame()函数来接收对应的游戏状态,并将返回值赋给ret变量,在每次的落子后判断一下。
PlayerMove(board, ROW, COL);
DisplayBroad(board, ROW, COL);//每次走完更新一次棋盘
//判断游戏状态
ret = Judgegame(board, ROW, COL);
if (ret == '*')
{
printf("玩家赢\n");
break;
}
else if (ret == 'Q')
{
printf("平局\n");
break;
}
//电脑走
ComputerMove(board, ROW, COL);
DisplayBroad(board, ROW, COL);
ret = Judgegame(board, ROW, COL);
if (ret == '#')
{
printf("电脑赢\n");
break;
}
else if (ret == 'Q')
{
printf("平局\n");
break;
}
那么我们来实现一下Judgegame函数,直接上代码:
char Judgegame(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 - 2; j++)
{
if (board[i][j] == board[i][j + 1] && board[i][j + 1] == board[i][j + 2] && board[i][j] != ' ')
{
return board[i][j];
}
}
}
//列相等
for (j = 0; j < col; j++)
{
for (i = 0; i < row - 2; i++)
{
if (board[i][j] == board[i + 1][j] && board[i + 1][j] == board[i + 2][j] && board[i][j] != ' ')
return board[i][j];
}
}
//主对角线相等
for (i = 0; i < row - 2; i++)
{
for (j = 0; j < col - 2; j++)
{
if (board[i][j] == board[i + 1][j + 1] && board[i + 1][j + 1] == board[i + 2][j + 2] && board[i][j] != ' ')
return board[i][j];
}
}
//副对角线相等
for (i = 0; i < row - 2; i++)
{
for (j = col - 1; j > 1; j--)
{
if (board[i][j] == board[i + 1][j - 1] && board[i + 1][j - 1] == board[i + 2][j - 2] && board[i][j] != ' ')
return board[i][j];
}
}
if (IsFull(board, row, col))//判断棋盘是否满,满则平局,不满则游戏继续
return 'Q';
else
return 'C';
}
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;
}
由于三子棋的规则是有三个子连成一条线则判断胜利,故我们穷举出所有的胜利条件,而返回的*和#刚好是我们的棋子,故这里的设计是十分巧妙的,并且为了不把代码写死,我们将判断变为遍历整个棋盘去找出是否有三子连成直线,以便棋盘扩大后的实现。
至此,我们的三子棋游戏已经大致设计完毕了,我们先来一把看看效果:
由于电脑的落子是由随机数产生的,故电脑想要赢是比较难的,只能通过放水来让电脑赢:
最后再来看一下平局:
由于是简易版的三子棋设计,因此就游戏性而言肯定是设计的不够好的,在之后更深入的学习之后,还可以实现电脑的走法更加的完善,而非随机走。
那么这就是这次简易三子棋的C语言程序设计了,
完整的代码
希望大家能够点个赞~