一:游戏的介绍
二:1>游戏文件的创立 2>游戏代码各部分的实现讲解 3>游戏的运行
三:完整代码的展示
三子棋的介绍
三子棋是一种民间传统游戏,又叫九宫棋、圈圈叉叉棋、一条龙、井字棋等。游戏分为双方对战,双方依次在9宫格棋盘上摆放棋子,率先将自己的三个棋子走成一条线就视为胜利,而对方就算输了,但是三子棋在很多时候会出现和棋的局面。
C语言实现三子棋
首先我们需要明白游戏的实现需要分模块完成,因此请大家跟随我的思路来看,完整代码会放到最后
1>文件的创立
1>>首先我们需要创建三个文件,第一个为头文件**“game.h"用于函数的声明,第二个为”test.c“用于游戏整体逻辑的连接,第三个为"game.c”**用于函数的实现
2>游戏代码各部分的实现讲解
1>>所需模块的顺序及流程展示
#include <stdio.h>
#include "game.h"
void menu()
{
printf("*************************\n");
printf("***** 1. play *****\n");
printf("***** 0. exit *****\n");
printf("*************************\n");
}
int main()
{
test();
return 0;
}
创建好图样这时候我们就需要让玩家选择1.玩游戏还是 0.退出游戏,所以我们需要输入数字input进行判断,即
void test()
{
srand((unsigned int)time(NULL));
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);
}
2>>正式进入游戏部分
如果玩家选择1.则进入游戏,因此我们创建了game()函数
打印棋盘三行三列我们会用到二维数组,为了后续的方便,我们将行和列分别用#define定义!
因此我们在**“game.h”**中进行定义,即
#define ROW 3
#define COL 3
但是为了能够在另外个文件中能够使用#define 定义的行和列,我们需要在另外两个文件开头加上头文件
#include "game.h"
定义好后我们在test.c的game函数中创建二维数组,但为了更为真实的模拟棋盘,因此用char类型的数组,即
void game()
{
char board[ROW][COL];
char ret = 0;
}
接着便是棋盘的初始化,我们在game()中创建函数InitBoard(),即
//初始化棋盘
InitBoard(board,ROW,COL);
在game.h中进行声明,即
//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col);
在game.c中进行初始化的实现,运用两个for循环初始化,即
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] = ' ';
}
}
}
在内部创建好棋盘后,为了能够让玩家看到棋盘,因此我们需要打印棋盘,因此我们需要在test.c中的game()函数中创建打印棋盘的函数,即
InitBoard(board,ROW,COL);
接着在"game.h"中声明
//打印棋盘
void DisplayBoard(char board[ROW][COL], int row, int col);
在"game.c"中实现棋盘的打印
棋盘打印首先我们需要打印棋盘的框
我们的思路是打印一个二维数组的空格,打印一条竖分界线,一行打印完之后再打印下一行
void DisplayBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{ //为了让竖列也活动起来
/*printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);*/
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("---");
if(j < col - 1)
printf("|");
}
printf("\n");
}
}
}
即这样的效果
到这里我们便做好了铺垫工作,接下来便是让玩家与电脑博弈下棋,因此需要设置如下几个模块
因此和如上几个模块一样,首先需要在test.c中的game()函数中创建玩家移动的函数,在game.h中进行声明,在game.c中进行目的的实现,即
test.c中
//玩家移动
PlayrMoveBoard(board, ROW, COL);
DisplayBoard(board, ROW, COL);
game.h中
//玩家移动
void PlayrMoveBoard(char board[ROW][COL], int row,int col);
game.c中便是玩家移动的精髓
我们的思路是:
1.提醒玩家下棋
2.让玩家输入要下的棋,这时候衍生出三个选择
{
第一:玩家下的是空白的合理棋子
第二:玩家下的是已经下过的棋子
第三:玩家下的坐标超出了棋盘的范围
}
因此我们需要用if语句判断:
在这其中有个细节:我们都知道数组的下标是从0开始的,但是在我们玩家的认识中,棋是从第一行第一列开始的,也就是说玩家输入的第一行其实是我们程序中的第0行,所以我们需要将玩家输入 的坐标x,y减去1
void PlayrMoveBoard(char board[ROW][COL], int row, int col)
{
printf("玩家请下棋");
while (1)
{
printf("请输入要下的坐标:>");
int x = 0;
int y = 0;
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");
}
}
}
玩家下完棋,便是电脑下棋,同上的创立函数以及声明,略过,代码如下:
test.c中
//电脑移动
ComputerMoveBoard(board, ROW, COL);
DisplayBoard(board, ROW, COL);
game.h中
//电脑移动
void ComputerMoveBoard(char board[ROW][COL], int row, int col);
game.h中我们的思路是让电脑在三行三列的棋盘中随机下一个空位置,因此我们这里就用到了随机赋值,时间戳,即rand函数rand(),下面便是rand函数的科普:
这里引用魔戒咕噜侠的文章,链接如下:https://blog.youkuaiyun.com/chikey/article/details/66970397
rand()函数用来产生随机数,但是,rand()的内部实现是用线性同余法实现的,是伪随机数,由于周期较长,因此在一定范围内可以看成是随机的。
rand()会返回一个范围在0到RAND_MAX(至少是32767)之间的伪随机数(整数)。
在调用rand()函数之前,可以使用srand()函数设置随机数种子,如果没有设置随机数种子,rand()函数在调用时,自动设计随机数种子为1。随机种子相同,每次产生的随机数也会相同。
rand()函数需要的头文件是:<stdlib.h>
我们还需要引入头文件“time.h”,利用时间戳时间随机种子,进行取余操作,确保随机数所取范围。
因为这里
time是time_t的形式,所以我们需要强制转化为unsigned int 类型,即
srand((unsigned int)time(NULL));
并且为了达到生成随机数的随机性srand用一次就好,如果放在循环中会导致生成数的不随机
这里需要的数是0,1,2,我们只需要用给给的随机数%3即可
void ComputerMoveBoard(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;
}
}
}
这时候便会出现一个问题,什么时候才结束,因此我们需要判断输赢,电脑胜利,玩家胜利,平局。以及判断的时候应该在每次电脑下棋和玩家下棋后都需要进行一次判断,因为我们不知道谁是最后下棋导致游戏结束的一方。
我们判断胜利的方法是针对不同结局返回不同字符进行判断
怀着这样 的问题和思路,我们进入输赢的判断
1.函数的创立,声明
这里之所以用while(1)的原因是因为判断输赢起码在三步或更多,我们需要在结果没出来之前继续让电脑和玩家下棋,让游戏正常运行,直到结果出来跳出循环
game.c中
char is_win(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][0] != ' ')
{
return board[i][0];
}
}
//判断三列
for (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 (is_full(board, row, col) == 1)
{
return 'Q';
}
//继续
return 'C';
}
在判断过程中针对不同的情景,我们用最朴实无华的判断方法,返回字符到test.c中进行判断输赢,即
if (ret == '#')
{
printf("电脑赢\n");
DisplayBoard(board, ROW, COL);
}
else if (ret == '*')
{
printf("玩家赢\n");
DisplayBoard(board, ROW, COL);
}
else if (ret == 'Q')
{
printf("平局\n");
DisplayBoard(board, ROW, COL);
}
游戏环节
到这里我们试着运行游戏,进行简单刺激的游戏
最终代码
最终代码的展示
test.c逻辑部分
#include <stdio.h>
#include "game.h"
void menu()
{
printf("*************************\n");
printf("***** 1. play *****\n");
printf("***** 0. exit *****\n");
printf("*************************\n");
}
void game()
{
char board[ROW][COL];
char ret = 0;
//初始化棋盘
InitBoard(board,ROW,COL);
//打印棋盘
DisplayBoard(board,ROW,COL);
while (1)
{ //玩家移动
PlayrMoveBoard(board, ROW, COL);
DisplayBoard(board, ROW, COL);
//判断输赢
ret = is_win(board, ROW, COL);
if (ret != 'C')
{
break;
}
//电脑移动
ComputerMoveBoard(board, ROW, COL);
DisplayBoard(board, ROW, COL);
ret = is_win(board, ROW, COL);
if (ret != 'C')
{
break;
}
}
if (ret == '#')
{
printf("电脑赢\n");
DisplayBoard(board, ROW, COL);
}
else if (ret == '*')
{
printf("玩家赢\n");
DisplayBoard(board, ROW, COL);
}
else if (ret == 'Q')
{
printf("平局\n");
DisplayBoard(board, ROW, COL);
}
}
void test()
{
srand((unsigned int)time(NULL));
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);
}
int main()
{
test();
return 0;
}
game.h 头文件函数声明部分
#include <stdio.h>
#include <time.h>
#include <stdlib.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 PlayrMoveBoard(char board[ROW][COL], int row,int col);
//电脑移动
void ComputerMoveBoard(char board[ROW][COL], int row, int col);
//判断输赢
char is_win(char board[ROW][COL], int row, int col);
game.c游戏过程实现部分
#include "game.h"
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] = ' ';
}
}
}
void DisplayBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{ //为了让竖列也活动起来
/*printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);*/
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("---");
if(j < col - 1)
printf("|");
}
printf("\n");
}
}
}
void PlayrMoveBoard(char board[ROW][COL], int row, int col)
{
printf("玩家请下棋");
while (1)
{
printf("请输入要下的坐标:>");
int x = 0;
int y = 0;
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 ComputerMoveBoard(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;
}
}
}
static 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;
}
char is_win(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][0] != ' ')
{
return board[i][0];
}
}
//判断三列
for (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 (is_full(board, row, col) == 1)
{
return 'Q';
}
//继续
return 'C';
}