🎇作者:小树苗渴望变成参天大树
💖作者宣言:写好每一篇博客
💦作者gitee:link
快来看三子棋小游戏的实现😁
👑三子棋
✨前言
我们在之前学习了关于数组的一些知识,我们知道了数组怎么创建和使用,今天我将即将一个人机对战的三子棋小游戏,并且我们将采用3-12方阵的任意一种棋盘来玩这个小游戏,使游戏不在单调死板,而且各个功能的实现先不用函数的形式展现,最后看源码的时候大家在去理解,大家来看正文吧!!!
一、🎉三子棋小游戏的介绍
🎊1.1游戏规则的介绍
我们这次所讲的三子棋并不是每个玩家只有三个棋子,而是在棋盘未满的情况下,双方各下一个棋子,当哪一方连成横三个,竖三个或者斜三个相等的时候就胜利了,当棋盘满了还没有谁胜利就是平局,我们接下来看看运行实例:
这样就是平局的情况。那我们要怎么实现这个代码呢??
💫1.2游戏界面的介绍
我们看到运行界面的图片,他是由棋子和棋盘构成的,我们的棋子使用一个数组来存储的,然而棋盘是需要自己去打印的,
那让我们看看棋盘怎么打印:
但这样不太好,把问题给固定死,只能打印33的棋盘,今天我们讲解的是3-12方阵的任意棋盘,如果是1212的方阵我们上面的代码就会出现下面这个问题:
那我们怎么修改代码呢,并且保证棋盘越大的时候我们方便找坐标,那我们是不是需要标记每一行每一列,不至于数。
所以打算把代码改成下面的样子
int i = 0;
int j = 0;
for(i=1;i<=row;i++)
{
printf(" %d ", i);
}//打印行标记
printf("\n");
for (i = 0; i < row; i++)
{
printf("%2d",i+1);//打印列标记
for (j = 0; j < col; j++)
{
//打印每一行的数据;
printf(" %c ", board[i][j]);
if (j < col - 1)
printf("|");
}printf("\n");
if (i < row - 1)
{ //打印分割行
printf(" ");
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
printf("\n");
}
}
打印12*12的棋盘就是这样的,3-12任意的都行
这才是我们想要达到的结果,我们需要做的界面。
💥1.3棋子的初始化介绍
那我们下的棋子放在哪里呢,这个时候就需要我们定义一个数组来存放棋子,数组的大小应该随着棋盘的大小而变化,所我们可以这样做
我们将数组里面先初始化空格,如果初始化为1,就会出现下面的情况
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
{
for (j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
这是初始化为1的结果,显然我们需要初始化为我们看不到空格,才能达到我们想要的结果。
这个时候我们棋盘的准备工作才熬这里结束了,接下来将下棋的一些功能
💢二、三子棋小游戏功能介绍
💌2.1玩家下棋
玩家下棋就需要改变我们数组的值,作为我们的棋子,我们将“*”作为我们玩家的棋子,我们玩家需要输入左边进行下棋,但普通玩家不是我们程序员,不知道下标是从0开始的,所以我们到时候需要把下标减一,但我们也要避免有些玩家随便输入下标,和下在了有子的坐标上造成越界问题和改变对方棋子的问题,所以我们要一个循环和判断,输入不合法就循环进去,输入正确就天厨循环,完成落子。
所以我们的代码如下:
int x = 0;
int y = 0;
while (1)
{
printf("请输入要下的坐标:");
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("输入下标不合法,请重新输入:");
}
}
💝2.2电脑下棋
我们知道就算是电脑下棋,也是通过下标来实现的,并且把电脑下的棋子记作“#”。那我们怎么过的电脑下的坐标呢?我在之前的博客是不是介绍过怎么生成随机数,并且实现了猜数字小i游戏,那我们这里可不可以通过随机数来获得呢?答案是可以的那我们怎么实现呢,看下面的代码:
int x = 0;
int y = 0;
while (1)
{
x = rand() % row;
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
printf("电脑下棋为(%d,%d)\n", x + 1, y + 1);
}
首先我们生成的随机数需要%上行列才能获得对应的下标,以3*3棋盘来说,x,y的值都为0-2的数所以不存在数组越界的情况,但可能会在已经有的棋子上落子,如果有,就进入循环继续生成随机数,所以我们要加一个判断来解决这个问题。
💘2.3棋盘是否为满
这里我以3*3的棋盘画图为例
我们在下棋的时候,如果出现为满就下不了棋了,就为平局,那我们怎么判断棋盘为满呢,如果棋盘为满就返回1,有一个为空,那整个棋盘就不满,返回0;
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;
如果棋盘有空格,就代表棋盘不为满就直接返回1,如果整个棋盘都遍历一遍发现都有棋子,就返回1.
🎨2.4怎么判断输赢
输赢才是i这个游戏的关键所在,也是这个游戏的核心算法,那我们应该怎么去实现这个代码呢?
规定:
玩家赢返回对应的棋子,也就是“*”
电脑赢返回对应的下标,也就是“#”
平局就返回“Q”,
游戏继续就返回“C”
1.我们知道平局的情况就一种,棋盘满的情况,那我们看代码:
if (1 == is_full(board, ROW, COL))
{
return 'Q';
}
返回1就为满,直接俄返回我们的“Q”;
2.不管玩家赢,还是电脑赢都分为三种情况
(1)判断行三个
相信大家看到这个图也明白了怎么实现这个功能了吧。给上正确的代码:
int i = 0;
int j = 0;
for (i = 0; i < row; i++)//判断横三列
{
for (j = 0; j < col; j++)
{
if ((j+2<row)&&(board[i][j] == board[i][j + 1]) &&(board[i][j + 1] == board[i][j + 2] )&& board[i][j] != ' ')
{
return board[i][j];
}
}
}
(2)判断竖三个
和行三个几乎一样,这里博主就不具体展开了,读者看代码对比第一个去理解
for (j= 0; j < col; j++)
{
for (i = 0; i < row; i++)
{
if ((i+2<row)&&(board[i][j] == board[i+1][j] )&& (board[i+1][j] == board[i+2][j]) && board[i][j] != ' ')
{
return board[i][j];
}
}
}
注:不懂的可以私信博主哦!
(3)判断斜对角线
我们来看看代码吧:
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if ((i + 2 < row)&& (j + 2 < row)&&(board[i][j] == board[i+1][j+1]) &&(board[i+2][j+2] == board[i+1][j+1]) && board[i][j] != ' ')
{
return board[i][j];
}
if ((i-2>=0)&&(j + 2 < row)&&(board[i][j] == board[i-1][j+1]) &&( board[i-2][j+2] == board[i-1][j+1] )&& board[i][j] != ' ')
{
return board[i][j];
}
}
}
如果上面一个都没有返回,那么游戏继续:
return 'C';//游戏继续
至此我们将三子棋游戏,整个功能都讲解完毕了,接下来,我们就需要吧框架搭起来,然后来电泳我们实现的这些函数,我们需要使用模块化来实现。
💕三、游戏框架的搭建
1.每个游戏都有一个菜单让选择,不会直接上面就让你开始玩游戏的,那我们就需要做一个简易的菜单
void menu()
{
printf("********************\n");
printf("***1.play 0.exit***\n");
printf("********************\n");
}
2.这时候我们就需要选择了,我们知道选择就会和分支联系起来,我们有if else语句,和switch语句,在这里我们使用switch语句,还要实现玩一次不过瘾的情况可以多次去玩,我们就需要使用循环,这里我将采用do while循环
让我们来看代码:
void test()
{
int input = 0;
do
{
menu();
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 1:
game();//就是我们要实现的游戏函数
break;
case 0:
printf("退出游戏");
break;
default:
printf("输入错误,请重新选择:");
break;
}
} while (input);
}
我们就test();放在主函数里面
int main()
{
test();
return 0;
}
3.那我们游戏功能怎么来凝结在一起呢,我们先要定义一个数组,然后初始化,打印棋盘后在进行游戏,然我们看看带啊吗吧
void game()
{
int ret = 0;
srand((unsigned int)time(NULL));//调用随机函数生成器函数,不懂的可以去看我前面的博客
char board[ROW][COL] = { 0 };//存储数据;
Initboard(board, ROW, COL);//初始化数据内容;
Displayboard(board, ROW, COL);//打印棋盘;
while (1)
{
printf("玩家走:\n");
playerMove(board, ROW, COL);
system("cls");
Displayboard(board, ROW, COL);//打印棋盘;
ret = is_win(board, ROW, COL);//判断是否玩家赢;
if (ret != 'c')//等于C代表游戏继续,跳过这个判断,执行下一步,不然ret肯定等于“*”,“#”,“Q”其中一个,然后跳出循环,执行下面的输赢判断
{
break;
}
printf("电脑走:\n");
system("cls");
competerMove(board, ROW, COL);
Displayboard(board, ROW, COL);//打印棋盘;
ret = is_win(board, ROW, COL);//判断是否电脑赢;
if (ret != 'c')
{
break;
}
}
if (ret == '*')
{
printf("玩家赢!\n");
}
else if (ret == '#')
{
printf("电脑赢!\n");
}
else
{
printf("平局!\n");
}
}
这样我们就把框架给搭建好了
🎄四、游戏的源代码
🧨 test.c(测试模块)
#include"game.c"
void game()
{
int ret = 0;
srand((unsigned int)time(NULL));
char board[ROW][COL] = { 0 };//存储数据;
Initboard(board, ROW, COL);//初始化数据内容;
Displayboard(board, ROW, COL);//打印棋盘;
while (1)
{
printf("玩家走:\n");
playerMove(board, ROW, COL);
system("cls");
Displayboard(board, ROW, COL);//打印棋盘;
ret = is_win(board, ROW, COL);//判断是否玩家赢;
if (ret != 'c')
{
break;
}
printf("电脑走:\n");
system("cls");
competerMove(board, ROW, COL);
Displayboard(board, ROW, COL);//打印棋盘;
ret = is_win(board, ROW, COL);//判断是否电脑赢;
if (ret != 'c')
{
break;
}
}
if (ret == '*')
{
printf("玩家赢!\n");
}
else if (ret == '#')
{
printf("电脑赢!\n");
}
else
{
printf("平局!\n");
}
}
void menu()
{
printf("********************\n");
printf("***1.play 0.exit***\n");
printf("********************\n");
}
void test()
{
int input = 0;
do
{
menu();
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏");
break;
default:
printf("输入错误,请重新选择:");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}
⛳game.h(声明函数模块)
#define ROW 3
#define COL 3
//#define ROWS ROW
//#define COLS COL
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void Initboard(char board[][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 competerMove(char board[ROW][COL], int row, int col);
char is_win(char board[ROW][COL], int row, int col);
🐅game.c(函数定义模块)
#include"game.h"
int is_full(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;
}
void Initboard(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++)
{
board[i][j] = ' ';
}
}
}
}
void Displayboard(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for(i=1;i<=row;i++)
{
printf(" %d ", i);
}
printf("\n");
for (i = 0; i < row; i++)
{
printf("%2d",i+1);
for (j = 0; j < col; j++)
{
//打印每一行的数据;
printf(" %c ", board[i][j]);
if (j < col - 1)
printf("|");
}printf("\n");
if (i < row - 1)
{ //打印分割行
printf(" ");
for (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;
while (1)
{
printf("请输入要下的坐标:");
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("输入下标不合法,请重新输入:");
}
}
}
void competerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
while (1)
{
x = rand() % row;
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
printf("电脑下棋为(%d,%d)\n", x + 1, y + 1);
}
char is_win(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 ((j+2<row)&&(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; i++)
{
if ((i+2<row)&&(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; i++)
{
for (j = 0; j < col; j++)
{
if ((i + 2 < row)&& (j + 2 < row)&&(board[i][j] == board[i+1][j+1]) &&(board[i+2][j+2] == board[i+1][j+1]) && board[i][j] != ' ')
{
return board[i][j];
}
if ((i-2>=0)&&(j + 2 < row)&&(board[i][j] == board[i-1][j+1]) &&( board[i-2][j+2] == board[i-1][j+1] )&& board[i][j] != ' ')
{
return board[i][j];
}
}
}
//判断是否为平局
if (1 == is_full(board, ROW, COL))
{
return 'Q';
}
return 'c';
}
大家如果不懂为啥要模块话可以看一下这个博客link
🪁五、总结
今天博主的三子棋小游戏终于要完工了,这也算是博主独立写的比较长的代码了,也遇到了好多问题,但也一一克服了,如果读者也想实现这个三子棋小游戏,遇到问题了可以慢慢解决,不要担心,这几天博主的课程也是非常多,这也时抽时间按完成的,如果写的不好的地方,还希望大佬们指点出来,希望我的博客能给读者带来一些收获,那博主也就知足了,那我们下期再见,我将讲解扫雷小游戏,也是关于数组方面的实战。