您现在的位置是:首页 >学无止境 >C语言三子棋网站首页学无止境
C语言三子棋
目录
三子棋小游戏制作思路
先看看三子棋是啥样的
游戏界面
为了能让用户有更好的人机交互的体验,我们应该设计一个简洁的游戏菜单,让用户可以通过菜单去玩游戏。如:
void menu()
{
printf("1.play
");
printf("0.exit
");
}
这样 一来,当用户进到这个界面的时候,用户就能知道如何操作这个小游戏了,当然这里作者写的界面是简单的实现,方便介绍。
有了界面之后呢,我们还需要思考一个问题:用户会不会玩完一把还想要继续玩呢?又要重新打开这个游戏?这样太耗时了,而且给用户的体验并不好。我们可以利用循环,每次玩完一把游戏,都重新跳出来这个菜单,因为我们一开始打开游戏,就需要弹出菜单,所以我们可以用do while循环
int input = 0;
do
{
menu();
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
break;
default:printf("输入错误,重新输入
");
break;
}
} while (input);
return 0;
}
这样就能够每次玩完一把都会重新跳出菜单栏了,知道你按0退出为止
如何存储数据
因为有两个玩家进行游戏,每一个玩家都有一种符号用来当作棋子,棋子可以下满 3 * 3个格子,而符号就是我们的字符,所以我们可以用一个字符二维数组arr[3][3],作者建议大家使用宏定义,这样方便以后的维护,比如:以后我们可能不想玩三子棋了,想玩五子棋呢。如果没有宏定义,那么就需要你修改很多的代码。 有了宏定义,我们只需要修改宏定义的行和列就可以了
#define ROW 3 //行
#define ARR 3 //列
char arr[ROW][ARR] = { 0 };
初始化数组
一开始进入游戏,我们是还没有开始落棋子的,所以一开始的棋盘应该是没有任何一个棋子的,也就是棋盘上是空白的,那么什么是空白的呢,当然是 空格 ,所以我们要把这个字符二维数组初始化为 空格(‘ ’)
void Initgame(char arr[ROW][ARR], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
arr[i][j] = ' ';//初始化为空格
}
}
}
棋盘设计
首先我们在来看看这个棋盘,在思考怎么实现这个棋盘
可以看到,这个棋盘其实是由---和 | 组成的。但是我们要怎么去把他实现打印出来呢?
其实我们可以把第一行看成是: 空格+字符+空格+ | 空格+字符+空格+ | 空格+字符+空格
然后下面的分割线可以看成
三个小横杠 + | 三个小横杠 + | 三个小横杠
代码实现
void Print(char arr[ROW][ARR], int row, int col) //row行,col列
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
//打印数据
for (j = 0; j < col; j++)
{
printf(" %c ", arr[i][j]);
if (j < col - 1) //因为|只有两列是需要的
printf("|");
}
printf("
");
//打印分割线
if (i < row - 1)//因为分割线只需要两行有分割线
{
int j = 0;
for ( j= 0; j < col; j++)
{
printf("---"); //每一行有3组---
if (j < col - 1)//只有两列是需要 |
printf("|");
}
printf("
");
}
}
}
现在我们把棋盘实现了,那么就可以进行设计玩家对战了,这里作者设计的是玩家 和 人机的对弈
玩家下棋
落棋子,那是要输入相对于的坐标才能把棋子落到那个坐标那里。首先我们需要考虑的是,用户输入的坐标合不合法,如果不合法,那就提示用户重新输入坐标。然后,思考如何能够更容易适应更多的用户的思维输入坐标。我们知道,数组的下标的从0开始的,那么知道这个知识的只有程序员嘛,大多数用户都是不知道的。比如第一个 格子 的坐标,在我们程序员眼中肯定是知道它就是数组 arr[0][0] 也就是坐标 (0 ,0),但是没有学过编程知识的用户都是会第一时间的潜意识认为第一个格子 坐标就是(1,1)。所以,我们需要在代码中设定好,当用户输入1的适合,那么我们让它变成0, 其实也就是在原来的基础上 - 1 就可以了,此外我们还需要考虑输入的坐标是否已经有了棋子,如果有了棋子,那么也要提示用户,让用户重新输入坐标
void player(char arr[ROW][ARR], int row, int col)
{
printf("玩家下棋:
");
int x = 0;
int y = 0;
while (1)
{
printf("请输入坐标,以空格隔开:");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)//检查坐标是否合法
{
if (arr[x - 1][y - 1] == ' ')//可以落子
{
arr[x - 1][y - 1] = '*';//玩家用符号*
break;
}
else
{
printf("此坐标已落棋子,请重新输入坐标
");
}
}
else
{
printf("坐标非法,请重新输入
");
}
}
}
运行结果:
现在,玩家下棋已经程序设计好了,接下来我们还要设计 电脑玩家
人机下棋
和设计玩家下棋是差不多的原理。人机下棋我们是预想不到它会如何去思考的,所以在这里我们可以给人机玩家 落子 的方式设定为一个随机的坐标。用随机值函数需要在main函数中加入srand((unsigned int)time(NULL))来初始化随机值,当然也要加上对应的头文件,include<stdlib.h> include<time.h>
void computerplayer(char arr[ROW][ARR], int row, int col)
{
printf("人机下棋:
");
int x = 0;
int y = 0;
while (1)
{
x = rand() % row;
y = rand() % col;
if (arr[x][y] == ' ')
{
arr[x][y] = '#'; //人机玩家用符号#
break;
}
}
}
运行结果:
到这里,我们已经把玩家 和 人机玩家 都设计好了,最后只需要设计判断输赢就完成了整个三子棋的小游戏的制作了
判断三子棋输赢
输赢判断有三种:1、平局 2、赢 3、输。三子棋输赢的规则是:连续三个棋子是一样的棋子就是赢,哪一方先连接好3个一样的棋子,哪一方就是赢家,另一方就是输家。比如
可以看到赢的方式可以有四种:行连续三个棋子,列连续三个棋子,主对角线连续三个棋子,副对角线连续三个棋子。而平局的方式只有一种,那就是把整个棋盘下满棋子,仍然没有赢家出现。
//平局判断
int draw(char arr[ROW][ARR], int row, int rol)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < rol; j++)
{
if (arr[i][j] == ' ')//如果没有下满棋盘那就还是空格
return 0;
}
}
return 1;//执行到了这里说明棋盘已经满了,平局
}
//判断四种赢的方式,行,列,主对角线,副对角线
char Iswin(char arr[ROW][ARR], int row, int col)
{
int i = 0;
int ret = 0;
for (i = 0; i < row; i++)
{
int j = 0;
if (arr[i][0] == arr[i][1] && arr[i][1] == arr[i][2] && arr[i][0] != ' ')//行
return arr[i][0];
else if (arr[0][i] == arr[1][i] && arr[1][i] == arr[2][i] && arr[i][0] != ' ')//列
return arr[0][i];
else if (arr[0][0] == arr[1][1] && arr[1][1] == arr[2][2] && arr[0][0] != ' ')//主对角线
return arr[0][0];
else if (arr[0][2] == arr[1][1] && arr[1][1] == arr[2][0] && arr[0][2] != ' ')//副对角线
return arr[0][2];
else if (draw(arr, row, col) == 1) //平局
return 'd';
else
return 'k';
}
然后把设计好的函数,全部封装成一个函数去调用
void game()
{
char arr[ROW][ARR] = { 0 };
Initgame(arr, ROW, ARR);
Print(arr, ROW, ARR);
char ch = 0;
while (1)
{
//玩家
player(arr, ROW, ARR);
Print(arr, ROW, ARR);
ch = Iswin(arr, ROW, ARR);//每次落子都判断输赢
if (ch != 'k')//等于k那说明还没有赢家出现,继续下棋
break;
//人机
computerplayer(arr, ROW, ARR);
Print(arr, ROW, ARR);
ch = Iswin(arr, ROW, ARR);
if (ch != 'k')
break;
}
//直到循环跳出,那么此时必定会有三种结局:玩家赢、人机赢、平局
if (ch == '*')
printf("玩家胜利
");
else if (ch == '#')
printf("人机胜利
");
else
printf("平局
");
}
完整代码
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 3 //行
#define ARR 3 //列
void menu();
void Initgame(char arr[ROW][ARR], int row, int col);//初始化数组
void Print(char arr[ROW][ARR], int row, int col);//打印
void player(char arr[ROW][ARR], int row, int col);//玩家
void computerplayer(char arr[ROW][ARR], int row, int col);//人机
char Iswin(char arr[ROW][ARR], int row, int col);//赢家判断
int draw(char arr[ROW][ARR], int row, int rol);//平局判断
void game()
{
char arr[ROW][ARR] = { 0 };
Initgame(arr, ROW, ARR);
Print(arr, ROW, ARR);
char ch = 0;
while (1)
{
//玩家
player(arr, ROW, ARR);
Print(arr, ROW, ARR);
ch = Iswin(arr, ROW, ARR);
if (ch != 'k')
break;
/*if (ch == '*')
{
printf("玩家胜利
");
break;
}*/
//人机
computerplayer(arr, ROW, ARR);
Print(arr, ROW, ARR);
ch = Iswin(arr, ROW, ARR);
if (ch != 'k')
break;
/*if (ch == '#')
{
printf("人机胜利
");
break;
}*/
}
if (ch == '*')
printf("玩家胜利
");
else if (ch == '#')
printf("人机胜利
");
else
printf("平局
");
}
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
break;
default:printf("输入错误,重新输入
");
break;
}
} while (input);
return 0;
}
void menu()
{
printf("1.play
");
printf("0.exit
");
}
void Initgame(char arr[ROW][ARR], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
arr[i][j] = ' ';
}
}
}
void Print(char arr[ROW][ARR], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
//打印数据
for (j = 0; j < col; j++)
{
printf(" %c ", arr[i][j]);
if (j < col - 1)
printf("|");
}
printf("
");
//打印分割线
if (i < row - 1)
{
int j = 0;
for ( j= 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
printf("
");
}
}
//printf("
");
}
void player(char arr[ROW][ARR], int row, int col)
{
printf("玩家下棋:
");
int x = 0;
int y = 0;
while (1)
{
printf("请输入坐标,以空格隔开:");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)//检查坐标是否合法
{
if (arr[x - 1][y - 1] == ' ')//可以落子
{
arr[x - 1][y - 1] = '*';
break;
}
else
{
printf("此坐标已落棋子,请重新输入坐标
");
}
}
else
{
printf("坐标非法,请重新输入
");
}
}
}
void computerplayer(char arr[ROW][ARR], int row, int col)
{
printf("人机下棋:
");
int x = 0;
int y = 0;
while (1)
{
x = rand() % row;
y = rand() % col;
if (arr[x][y] == ' ')
{
arr[x][y] = '#';
break;
}
}
}
char Iswin(char arr[ROW][ARR], int row, int col)
{
int i = 0;
int ret = 0;
for (i = 0; i < row; i++)
{
int j = 0;
if (arr[i][0] == arr[i][1] && arr[i][1] == arr[i][2] && arr[i][0] != ' ')//行
return arr[i][0];
else if (arr[0][i] == arr[1][i] && arr[1][i] == arr[2][i] && arr[i][0] != ' ')//列
return arr[0][i];
else if (arr[0][0] == arr[1][1] && arr[1][1] == arr[2][2] && arr[0][0] != ' ')//主对角线
return arr[0][0];
else if (arr[0][2] == arr[1][1] && arr[1][1] == arr[2][0] && arr[0][2] != ' ')//副对角线
return arr[0][2];
else if (draw(arr, row, col) == 1) //平局
return 'd';
else
return 'k';
}
}
int draw(char arr[ROW][ARR], int row, int rol)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < rol; j++)
{
if (arr[i][j] == ' ')
return 0;
}
}
return 1;
}