三子棋想必大家小时候都有和小伙伴们一起玩过吗,今天咬咬带大家一起来用c语言写一个简单的三子棋小游戏!
三子棋顾名思义,玩家和电脑在一个类似井字的棋盘上轮流下子,先让自己的三个子连成一条线的一方获得胜利:
首先在vs中创建一个头文件,两个源文件:
我们将基本的游戏框架放入三子棋.c
将游戏中需要用到的函数声明放入game.h
将函数的实现放入game.c
首先打开游戏出现一个菜单,输入1开始游戏,输入0退出游戏,输入其他的重新输入,所以我们可以用一个do while循环和一个menu函数来实现:
#define _CRT_SECURE_NO_WARNINGS 1
#include
void menu()
{
printf("*************************\n");
printf("***** 1.开始游戏 *****\n");
printf("***** 0.退出游戏 *****\n");
printf("*************************\n");
printf("请选择>:\n");
}
int main()
{
int input = 0;
do
{
menu();
scanf("%d", &input);
switch (input)
{
case 0:
printf("游戏结束\n");
break;
case 1:
// game();
break;
default:
printf("选择错误请重新输入\n");
break;
}
} while(input);
现在运行代码进行简单的测试:
已经达到了我们的预想,接下来把函数整理一下,在game.h中声明,在game.c中实现,在三子棋.c中使用:
整理完毕,后面每个函数我都会像这样一样存放,不再一一展示。
接下来就是对game函数也就是游戏主体的实现了,要想玩这款游戏肯定要先做出棋盘。
先大致设想一下棋盘是不是就大概是一个3行3列的数组所以我们可以先设定一个数组:
char board[3][3] = { 0 };
这样写的话如果想要改行数或者列数时,就要把后面出现的所有3改一遍,非常麻烦,所以我们在game.h定义一下行和列分别为row和col:
char board[row][col] = { 0 };
接下来我们刚开始游戏的时候要先初始化棋盘,保证每个位置都是空位可以放子,我现在设定空位用空格来表示,用一个initboard函数来实现棋盘的初始化:
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] = ' ';//遍历整个数组将每个元素变为空格
}
}
}
这个函数实现是放在game.c里的
接下来棋盘初始化了我们是不是应该将棋盘打印出来让我们看一下,所以我们可以写一个displayboard函数来实现展示棋盘:
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++)
{
printf("%c", board[i][j]);
}
printf("\n");//打印一行后换行
}
}
现在我们测试一下能否打印出空格:
可以看到输入1后打印出了3×3的空格,可是这样的棋盘太过简陋,我想要优化一下下面是我的设想:
| |
---|---|---
| |
---|---|---
| |
现在我为了更直观把落子的地方用*号代替:
* | * | *
---|---|---
* | * | *
---|---|---
* | * | *
这样的棋盘是不是玩起来更加方便呢,现在就是用代码来实现这个棋盘,这个棋盘看起来复杂,其实我们可以分析一下:
所以我们将这个棋盘分为3块:
每一块都由一行数据行一行分割行组成,只有最后一块没有分割行,所以我们可以先打印数据行,再打印分割行,最后一块不打印分割行:
数据行: * | * | * 注意*为数据,初始化为空格
分割行:---|---|---
void displayboard(char board[ROW][COL], int row, int col)//展示棋盘
{
int i = 0;
for (i = 0; i < row; i++)
{
printf(" %c | %c | %c \n",board[i][0],board[i][1],board[i][2]);//数据行
if (i < row - 1)//保证最后一行不打印分割行
printf("---|---|---\n");//分割行
}
}
运行一下代码测试一下棋盘:
已经满足了我们的设想,接下来就是玩家下子了,就需要写一个playermove函数来实现玩家落子:
void playermove(char board[ROW][COL], int row, int col)
{
printf("玩家下棋\n");
while (1)
{
printf("请选择你的下棋坐标>:\n");
int x, 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");
}
}
现在玩家下完了,接下来是电脑落子,同样写一个computermove函数来实现,这里我们把电脑弄笨一点,随机落子,这就需要用到rand函数了:
void computermove(char board[ROW][COL], int row, int col)
{
printf("电脑下棋>;\n");
int x, y = 0;
while (1)
{
x = rand() % row;//生成0-2的随机数
y = rand() % col;//生存0-2的随机数
if (board[x][y] == ' ')//确保该地可以落子
{
board[x][y] = '*';//电脑下子*
break;
}
}
}
使用rand函数记得在game.h中加上两个头文件:
#include
#include
并且在最开始前加上一句:
srand((unsigned int)time(NULL));
例如现在在我的三子棋.c中:
#include "game.h"
char board[ROW][COL] = { 0 };
void game()
{
initboard(board, ROW, COL);//初始化棋盘
displayboard(board, ROW, COL);//展示棋盘
playermove(board, ROW, COL);//玩家落子
computermove(board, ROW, COL);//电脑落子
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));//随机数种子
do
{
menu();
scanf("%d", &input);
switch (input)
{
case 0:
printf("游戏结束\n");
break;
case 1:
game(board,ROW,COL);
break;
default:
printf("选择错误请重新输入\n");
break;
}
} while(input);
return 0;
}
好,按照逻辑来讲玩家下棋电脑下棋后应该展示一下棋盘所以
void game()
{
initboard(board, ROW, COL);//初始化棋盘
displayboard(board, ROW, COL);//展示棋盘
playermove(board, ROW, COL);//玩家落子
computermove(board, ROW, COL);//电脑落子
displayboard(board, ROW, COL);//展示棋盘
}
现在运行代码测试一下:
目前一切正常!
好现在要做电脑和玩家轮流下棋,其实是不是只要将一次玩家下棋和电脑下棋放入一个while循环里就行了:
void game()
{
initboard(board, ROW, COL);//初始化棋盘
displayboard(board, ROW, COL);//展示棋盘
while(1)
{
playermove(board, ROW, COL);//玩家落子
computermove(board, ROW, COL);//电脑落子
displayboard(board, ROW, COL);//展示棋盘
}
}
像这样每次落子后我们是不是要进行一次判断输赢,来决定是否结束游戏,这时候可以写一个iswin函数来实现:
在这个函数内部,为了逻辑清晰,如果玩家赢返回一个#,电脑赢返回一个*,还未分出胜负返回一个c,棋盘填满平局返回一个q:
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][0]!= ' ')//横向连线成功
return board[i][0];//返回对应的棋子
}
int j = 0;
for (j = 0; j < col; j++)
{
if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[0][j] != ' ')//竖向连线成功
return board[0][j];//返回对应的棋子
}
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[2][2] != 0)// \连线成功
return board[0][0];//返回对应的棋子
else if (board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[0][2] != 0)// /连线成功
return board[0][2];//返回对应的棋子
for (i = 0;i < row; i++)
{
for (j = 0; j < col; j++)
{
if (isfull(board,ROW,COL))//棋盘满了
return 'q';//平局返回q
else
return 'c';//未分出胜负游戏继续
}
}
}
棋盘是否满了,我们用一个函数来判断,也就是isfull,现在我们来实现一下这个函数:
int isfull(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++)
{
if (board[i][j] == ' ')//找到空格棋盘没满
return 0;//返回0为假,没有平局
}
}
return 1;//循环结束没找到空格,返回1为真,平局
}
函数内部完成了,我们是不是应该在函数外部接受一下返回的值,来产生结果:
void game()
{
initboard(board, ROW, COL);//初始化棋盘
displayboard(board, ROW, COL);//展示棋盘
while (1)
{
playermove(board, ROW, COL);//玩家落子
displayboard(board, ROW, COL);//展示棋盘
char ret = iswin(board, ROW, COL);//判断输赢
if (ret == '#')
{
printf("玩家胜利\n");
break;
}
else if (ret == '*')
{
printf("电脑胜利\n");
break;
}
else if (ret == 'q')
{
printf("平局\n");
break;
}
else if (ret == 'c')
{
//游戏继续不作出指令
}
computermove(board, ROW, COL);//电脑落子
displayboard(board, ROW, COL);//展示棋盘
iswin(board, ROW, COL);//判断输赢
if (ret == '#')
{
printf("玩家胜利\n");
break;
}
else if (ret == '*')
{
printf("电脑胜利\n");
break;
}
else if (ret == 'q')
{
printf("平局\n");
break;
}
else if (ret == 'c')
{
//游戏继续不作出指令
}
}
}
上面是game函数内部,现在所有功能都已经完成,每一次落子后都会先判断输赢返回一个值,再根据这个值确认是否结束游戏,若继续游戏则展示棋盘,一直循环,直到返回的值导致游戏结束。
现在整个游戏就已经完成了,我现在将整个代码发一下:
game.h
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include
#define ROW 3
#define COL 3
void menu();//菜单
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);//电脑落子
char iswin(char board[ROW][COL], int row, int col);//判断输赢
int isfull(char board[ROW][COL], int row, int col);//判断平局
game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include"game.h"
void menu()
{
printf("*************************\n");
printf("***** 1.开始游戏 *****\n");
printf("***** 0.退出游戏 *****\n");
printf("*************************\n");
printf("请选择>:\n");
}
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;
for (i = 0; i < row; i++)
{
printf(" %c | %c | %c \n",board[i][0],board[i][1],board[i][2]);//数据行
if (i < row - 1)//保证最后一行不打印分割行
printf("---|---|---\n");//分割行
}
}
// * | * | *
//---|---|---
// * | * | *
//---|---|---
// * | * | *
void playermove(char board[ROW][COL], int row, int col)
{
printf("玩家下棋\n");
while (1)
{
printf("请选择你的下棋坐标>:\n");
int x, 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");
}
}
void computermove(char board[ROW][COL], int row, int col)
{
printf("电脑下棋>;\n");
int x, y = 0;
while (1)
{
x = rand() % row;//生成0-2的随机数
y = rand() % col;//生存0-2的随机数
if (board[x][y] == ' ')//确保该地可以落子
{
board[x][y] = '*';//电脑下子*
break;
}
}
}
int isfull(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++)
{
if (board[i][j] == ' ')//找到空格棋盘没满
return 0;//返回0为假,没有平局
}
}
return 1;//循环结束没找到空格,返回1为真,平局
}
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][0]!= ' ')//横向连线成功
return board[i][0];//返回对应的棋子
}
int j = 0;
for (j = 0; j < col; j++)
{
if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[0][j] != ' ')//竖向连线成功
return board[0][j];//返回对应的棋子
}
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[2][2] != 0)// \连线成功
return board[0][0];//返回对应的棋子
else if (board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[0][2] != 0)// /连线成功
return board[0][2];//返回对应的棋子
for (i = 0;i < row; i++)
{
for (j = 0; j < col; j++)
{
if (isfull(board,ROW,COL))//棋盘满了
return 'q';//平局返回q
else
return 'c';//未分出胜负游戏继续
}
}
}
三子棋.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
char board[ROW][COL] = { 0 };
void game()
{
initboard(board, ROW, COL);//初始化棋盘
displayboard(board, ROW, COL);//展示棋盘
while (1)
{
playermove(board, ROW, COL);//玩家落子
displayboard(board, ROW, COL);//展示棋盘
char ret = iswin(board, ROW, COL);//判断输赢
if (ret == '#')
{
printf("玩家胜利\n");
break;
}
else if (ret == '*')
{
printf("电脑胜利\n");
break;
}
else if (ret == 'q')
{
printf("平局\n");
break;
}
else if (ret == 'c')
{
//游戏继续不作出指令
}
computermove(board, ROW, COL);//电脑落子
displayboard(board, ROW, COL);//展示棋盘
iswin(board, ROW, COL);//判断输赢
if (ret == '#')
{
printf("玩家胜利\n");
break;
}
else if (ret == '*')
{
printf("电脑胜利\n");
break;
}
else if (ret == 'q')
{
printf("平局\n");
break;
}
else if (ret == 'c')
{
//游戏继续不作出指令
}
}
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));//随机数种子
do
{
menu();
scanf("%d", &input);
switch (input)
{
case 0:
printf("游戏结束\n");
break;
case 1:
game(board,ROW,COL);
break;
default:
printf("选择错误请重新输入\n");
break;
}
} while(input);
return 0;
}
现在进行一把游戏来测试一下:
代码成功跑起来了。
那么三子棋游戏现在就已经写完了,赶快自己动手来写一个自己的三子棋小游戏吧。