三子棋游戏
注:本篇三子棋实现使用C语言,在VS编译环境下实现。
- 文件的创建
- 三子棋代码框架
- 初始化和打印函数
- 玩家下棋
- 电脑下棋
- 胜负判断
- 效果演示
- 全部代码
三子棋详细步骤讲解
1.文件的创建
为了让代码更加整洁和分工明确,我们需要在VS上创建三个不同的文件,1.创建test.c的源文件,用于测试三子棋游戏。2.创建game.c的头文件,实现游戏函数的声明。3.创建game.c源文件,用于游戏函数的实现。创建好后如下图。
2.三子棋代码框架
我们编写任何一个复杂工程项目,都是先把框架写出来,然后一步一步去实现它。
如图,在test.c文件下设计框架:
框架设计好后,开始实现内容,menu作为菜单函数,可以这样设计:
void menu()
{
printf("******************************\n");
printf("********* 1.play *********\n");
printf("********* 0.exit *********\n");
printf("******************************\n");
}
按F5编译运行,我们输入0,结果如下图:
3.初始化和打印函数实现
如何设计三子棋游戏呢,我们先观察三子棋样貌,有三行三列,我们下棋一次棋,保存一下,然后电脑下棋…不难得出棋盘类似于一个二维数组,观察棋盘图,定义初始化数组,然后实现打印函数。
我们在test.c中创建初始化和打印函数,在game.h中声明函数,在game.c中实现数组,之后实现函数同理,创建和声明将不再赘述。
1.在test文件中创建初始化函数和打印函数
2.在game.h文件中声明函数
3.初始化函数的实现
4.打印棋盘函数的实现
5.效果如图
注:改变define中的值可以改变棋盘大小
4.玩家下棋
步骤1.先在test.c中的game()函数中创建。2.在game.h中声明。3.在game.c中实现。前两部操作同上,不展开讲述,最后我会将全部代码放到最后,这里详细讲解game.c中玩家下棋的实现。
void player(char board[row][col], int r, int c)
{
int i = 0;
int j = 0;
printf("玩家下棋:>\n");
while (1) //会出现下棋位置错误或重复下棋情况,需要循环
{
printf("请输入下棋位置:>");
scanf("%d %d", &i, &j);
//常人思维第一个位置是1 1,但实践在数组里是0 0
//下棋位置不能越界
if ((i >= 1 && i <= row) && (j >= 1 && j <= col))
{
//下棋位置不能是之前下过的
if (board[i-1][j-1] == ' ')//i-1这样解决常人输入1 1情况
{
board[i-1][j-1] = '*';
break;
}
else
{
printf("该位置已经下过,请重新下棋\n");
}
}
else
{
printf("下棋位置错误,请重新下棋\n");
}
}
}
注:写完玩家下棋函数后,在其下在接上之前的打印函数,这样下一个子就可以立刻看到棋盘。
5.电脑下棋
基本步骤同上,rand(),srand(),time()函数可以去这个网站了解:https://legacy.cplusplus.com/
//game.c
void computer(char board[row][col], int r, int c)
{
int i = 0;
int j = 0;
printf("电脑下棋:>\n");
while (1)
{
//rand()随机值函数,任何数模上一个数,得到范围是0~这个数
i = rand() % row; //使用rand函数需要用srand()函数,头文件<stdlib.h>
j = rand() % col; //srand()函数需要调用time()函数,头文件<time.h>
if (board[i][j] == ' ')
{
board[i][j] = '#';
break;
}
} //因为是电脑下棋,不需要提示错误,自己会循环
}
//test.c
因为srand()函数只调用一次,所以在main()中加如下代码
srand((unsigned int)time(NULL));
6.判断胜负
首先在game()函数中创建判断胜负函数is_win(),分别在玩家下棋和电脑下完一次棋后进行判断,根据判断值返回值来看是继续下棋还是谁赢了,或者是平局。
1.设计判断函数之前game()函数内容
2.设计后game()函数内容
3.判断函数is_win()的实现
注:因为函数是有返回值,字符,所以声明是设计为char返回类型,而不是void
判断满没满full()函数的实现。注:写在is_win()函数上面
7.效果演示
8.全部代码
- test.c
#define _CRT_SECURE_NO_WARNINGS 1 //这是VS使用scanf函数报错bug应对方法
#include "game.h" //头文件声明函数,这里引用头文件,就不用在test上声明,省事
void game()
{
char board[row][col] = { 0 }; //创建棋盘数组
Inital(board,row,col); //初始化棋盘
display(board, row, col);//打印棋盘
//玩游戏
while (1)
{
player(board, row, col);
display(board, row, col);
//判断一下情况
if ('c' != is_win(board, row, col))
{
break;
}
computer(board, row, col);
//判断一下情况
if ('c' != is_win(board, row, col))
{
break;
}
display(board, row, col);
}
//跳出循环,不在下棋,根据判断函数返回值确定结果
if ('*' == is_win(board, row, col))
{
printf("玩家赢\n");
}
if ('#' == is_win(board, row, col))
{
printf("电脑赢\n");
}
if ('p' == is_win(board, row, col))
{
printf("平局\n");
}
//最后将结果在输出一遍
display(board, row, col);
}
void menu()
{
printf("******************************\n");
printf("********* 1.play *********\n");
printf("********* 0.exit *********\n");
printf("******************************\n");
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do //用do....while循环来构建基本框架
{
menu(); //创建menu函数,来打印游戏菜单
printf("请输入数字:>");
scanf("%d", &input);
switch (input)
{
case 1: //输入1,进入game函数
game(); //game函数就是之后的游戏实现
break;
case 0:
printf("退出游戏\n");
break; //输入0,break退出switch函数
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input); //正好输入0退出,while(0)为假,退出游戏
return 0;
}
- game.h
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h> //printf,scanf函数声明
#include <stdlib.h>
#include <time.h>
#define row 3 //宏定义棋盘长宽,以后修改方便
#define col 3
//初始化棋盘函数的声明,因为不反回值,所以用void
void Inital(char board[row][col], int r,int c);
//打印棋盘的声明
void display(char board[row][col], int r, int c);
//玩家下棋
void player(char board[row][col],int r,int c);
//电脑下棋
void computer(char board[row][col], int r, int c);
//判断输赢
char is_win(char board[row][col], int r, int c);
- game.h
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void Inital(char board[row][col], int r, int c)
{
int i = 0;
for (i = 0; i < r; i++) //二维数组初始化两个for循环
{ //第一个for循环代表行,第二个for代表列
int j = 0;
for (j = 0; j < c; j++)
{
board[i][j] = ' '; //数组赋值为空格‘ ’
}
}
}
void display(char board[row][col], int r, int c)
{
int i = 0;
for (i = 0; i < r; i++) //这个大for循环控制的是行,r=3,3行
{
int j = 0;
for (j = 0; j < c; j++) //这个for循环控制列,将' |'作为一组打印
{
printf(" %c ", board[i][j]);
if (j < c - 1) //观察棋盘,最后一列的|不打印
{
printf("|");
}
}
printf("\n");
if (i < r - 1) //观察棋盘,最后一行的---和|不打印,但' |'打印了
{
for (j = 0; j < c; j++) //打印3列‘---’
{
printf("---");
if (j < c - 1) //只打印2列'|'
{
printf("|");
}
}
printf("\n");
}
}
}
void player(char board[row][col], int r, int c)
{
int i = 0;
int j = 0;
printf("玩家下棋:>\n");
while (1) //会出现下棋位置错误或重复下棋情况,需要循环
{
printf("请输入下棋位置:>");
scanf("%d %d", &i, &j);
//常人思维第一个位置是1 1,但实践在数组里是0 0
//下棋位置不能越界
if ((i >= 1 && i <= row) && (j >= 1 && j <= col))
{
//下棋位置不能是之前下过的
if (board[i-1][j-1] == ' ')//i-1这样解决常人输入1 1情况
{
board[i-1][j-1] = '*';
break;
}
else
{
printf("该位置已经下过,请重新下棋\n");
}
}
else
{
printf("下棋位置错误,请重新下棋\n");
}
}
}
void computer(char board[row][col], int r, int c)
{
int i = 0;
int j = 0;
printf("电脑下棋:>\n");
while (1)
{
//rand()随机值函数,任何数模上一个数,得到范围是0~这个数
i = rand() % row; //使用rand函数需要用srand()函数,头文件<stdlib.h>
j = rand() % col; //srand()函数需要调用time()函数,头文件<time.h>
if (board[i][j] == ' ')
{
board[i][j] = '#';
break;
}
} //因为是电脑下棋,不需要提示错误,自己会循环
}
int full(char board[row][col], int r, int c)
{
int i = 0;
int j = 0;
for (i = 0; i < r; i++)
{
for (j = 0; j < c; j++)
{
if (' ' == board[i][j])
{
return 0;
}
}
}
return 1;
}
char is_win(char board[row][col], int r, int c)
{
int i = 0;
int j = 0;
//判断行是否相等
for (i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][0] == board[i][2] && board[i][0] != ' ')
{
return board[i][0];
}
}
//判断列是否相等
for (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[0][i] == board[2][i] && board[0][i] != ' ')
{
return board[i][0];
}
}
//判断右对角是否相等
if (board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][i] != ' ')
{
return board[0][0];
}
//判断左对角是否相等
if (board[0][2] == board[1][1] && board[0][2] == board[2][0] && board[0][2] != ' ')
{
return board[0][0];
}
//判断棋盘是否满了
if (1 == full(board,row,col))
{
return 'p'; //满了,平局
}
else
return 'c';//没满,继续下棋
}
这里三子棋讲解就结束啦,当然还有很多不足之处,如:1.三子棋写死了,不能实现五子棋 2.打印屏幕没设计清除等等,好了,同志们赶紧冲,搞起来。