目录
实现思路讲解:
首先我们要分装函数,新建两个源文件和一个头文件text.c用于实现游戏开始前的逻辑和测试。game.c用于实现游戏逻辑。game.h用于实现函数的声明。
在text.c文件中创建main函数,在main函数中创建text函数,再在text函数中通过do.....while语句实现游戏的循环游玩。在简单创建一个menu函数用于打印我们的初始菜单栏。Menu函数要放在do...while语句中,每次循环都会打印。在text中要先定义一个input,input用于接收我们输入数字1表示进行游戏,0表示退出游戏,其他数字则会报错,为了实现这样的效果,我们需要在do...while语句中创建Switch case语句,case 1中放game函数,case2中放break,default表示其他情况,打印输入错误。最重要的部分是,在do while语句中,while的循环条件必须要是input,当我们输入非0常数时,while判断都为真,怎样都会返回继续循环,当我们输入0,跳出了Switch case语句中,但由于input=0,为假,会跳出游戏的循环,则结束游戏。
注意,因为我们加了game.h文件,所以当我们用到printf等函数数时,要引用的头文件直接放在game.h中,后续在text.c和game.c文件中,只要在开头加上#include“game.h”就行。
代码内容
main函数内容
#include"game_3ziqi.h"
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
mune();
printf("是否游玩(0/1)?\n");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
default:
printf("输入错误,请重新输入!\n");
}
} while (input);
return 0;
}
mune打印菜单函数
void mune()
{
printf("*************************\n");
printf("******* 1.play ********\n");
printf("******* 0.exit ********\n");
printf("*************************\n");
}
game()函数,存放游戏内容
void game()
{
char arr[ROW][COL] = {0};
ChuShi(arr, ROW, COL);
PrintArr(arr, ROW, COL);
char ret = 'j';//判断游戏是否继续的条件
while (1)
{
PlayerMove(arr, ROW, COL);
PrintArr(arr, ROW, COL);
ret = IsWin(arr, ROW, COL);
if (ret != 'j')
{
break;
}
ComputerMove(arr, ROW, COL);
PrintArr(arr, ROW, COL);
ret=IsWin(arr, ROW, COL);
if (ret != 'j')
{
break;
}
}
if (ret == '*')
{
printf("玩家胜利\n");
}
if (ret == '#')
{
printf("电脑胜利\n");
}
if (ret == 'p')
{
printf("平局\n");
}
}
game()函数内容详解
首先game函数只进行调用函数,而不定义函数,函数的声明放在game.h文件中,函数的定义(内容的实现)放在game.c文件中。然后我们就需要打game函数里的代码了。先定义一个char类型的二维数组作为棋盘,长为ROW,宽为COL,内容先给为0,。然后再game.h中define两个变量的大小为3。这样做的好处在于,若后续我们想修改长宽,可以在定义中直接修改,不用后续一个一个去改,减少了修改的工作量。
注意:在game.h中要负责声明函数、定义棋盘格长宽、引用头文件。game.h文件如下:(其中ROW表示长,COL表示宽)
game.h头文件
#include<stdio.h>//printf
#include<time.h>//time
#include<stdlib.h>//rand,srand
#define ROW 3
#define COL 3
//函数声明
//初始化棋盘
void ChuShi(char arr[ROW][COL], int row, int col);
//打印棋盘
void PrintArr(char arr[ROW][COL], int row, int col);
//玩家下棋
void PlayerMove(char arr[ROW][COL], int row, int col);
//电脑下棋
void ComputerMove(char arr[ROW][COL], int row, int col);
//判断胜利
char IsWin(char arr[ROW][COL], int row, int col);
接着我们要给二维数组内加内容了。为防止数组中的内容不统一,我们先进行初始化数组,把数组内的每个元素都给上空格,方便我们前期我们后期的调用。具体操作为,先在text.c文件的game函数中,定义一个函数ChuShi(sanziqi,ROW,COL)在里面放上棋盘和长宽,再在game.h中声明这个函数 void chushi(char sanziqi[ROW][COL], int row, int col);
(注意,声明的函数里row和col不能是大写,要不然会与之前定义的长宽相冲突,这里声明只是为了接收ROW和COL的值,当形参,并不是等于他俩),然后把声明的这串内容复制到game.c文件中,为其添加代码内容,实现功能。后续在game函数中加的其他函数皆是这样的操作。
ChuShi()初始化函数
//初始化数组
void ChuShi(char arr[ROW][COL], 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] = ' ';
}
}
}
把二维数组内容全部清空后,接着我们要打印棋盘格,在我们的想法中,棋盘格的样式应该如下:
第一行里放可以存放字符的部分,在打印一行分割行;第二行一样,接着第三行只打印内容行,不打印分割行,其具体代码如下:
PrintArr()打印函数
//打印棋盘
// | |
//---|---|---
// | |
//---|---|---
// | |
void PrintArr(char arr[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 ",arr[i][j]);
if (j < COL - 1)
{
printf("|");
}
}
printf("\n");
//打印分割行
for (j = 0; j < COL; j++)
{
//分割行只打印2列
if (i < ROW - 1)
{
printf("---");
if (j < COL - 1)
{
printf("|");
}
}
}
printf("\n");
}
}
打印完棋盘,接着我们要进行玩家下棋了。我们用PlayMove()函数来存放玩家下棋的代码。具体代码如下:
PlayerMove()玩家移动函数
//玩家移动 *
void PlayerMove(char arr[ROW][COL], int row, int col)
{
int x = 0, y = 0;
printf("请输入要下棋的坐标:\n");
//getchar();
while (1)
{
scanf("%d %d", &x, &y);
if ((((x - 1) >= 0) && ((x - 1) < ROW)) && (((y - 1) >= 0 )&& ((y - 1) < COL)))
{
if (arr[x-1][y-1] == ' ')
{
arr[x-1][y-1] = '*';
break;
}
else
{
printf("坐标已被占用,请重新输入坐标\n");
}
}
else
{
printf("输入坐标超出范围,请重新输入:\n");
}
}
}
如上述代码所示,我们用while(1)来实现死循环,直到玩家输入了正确的、没被占用的坐标内容,才能跳出这个循环。接着,玩家走完了应该新打印一个棋盘,来显示玩家到底下在哪里。
然后再进行电脑下棋。由于电脑下棋不用判断是否会下棋盘外的棋子,所以比起玩家,只需要在棋盘内进行随机下就行。因为是随机,所以我们就要用到rand了。
在ComputerMove函数内部打上x = rand()% row; y = rand()% col;模上长和宽,最后输出的值就只有比长宽更小的数字了。比如:当row和col为3时,任何数%3,那都只剩下0/1/2,就刚好是二维数组的坐标,在ComputerMove中引用了rand后,要在text.c文件中的text函数的do while语句执行前加上srand((unsigned int)time(NULL));让这个伪随机值rand,随着时间变化而变化,实现真随机(注意上面这具代码不能加入循环语句中,我们只要取一次时间,那后续的数字都是随机的)因为用了rand和srand还有time,我们要在game.h文件中,加两个头文件#include<stdlib.h>和#include<time.h>
接着在电脑走完之后,我们也要重新打印棋盘,来看看电脑走了哪步。所以在game函数中的ComputerMove(arr, ROW, COL);后面加一个PrintArr(Arr, ROW, COL);电脑下棋代码如下:
ComputerMove()电脑移动函数
//电脑移动
void ComputerMove(char arr[ROW][COL], int row, int col)
{
int x = 0, y = 0;
while (1)
{
x = rand() % ROW;//控制在0、1、2
y = rand() % COL;
if (arr[x][y] == ' ')
{
arr[x][y] = '#';
break;
}
}
}
当我们实现了玩家和电脑一步一步的下棋,最后就要实现游戏胜利的条件了。先在game函数中定义一个char类型的变量ret用于接收不同情况下的返回值。写一个IsWin()函数,放在game.c文件中,用于检测游戏当前状态,条件为:若电脑胜利,返回#。若玩家胜利,返回*。若平局(棋盘被下满了),返回p。若没有结束游戏,且没有平局,则继续,返回j。
具体代步骤为:先判断横竖,返回值就是三个相等的字符的其中一个字符(因为电脑是输入#,玩家是输入*,返回的值可以直接用于判断哪方获胜)接着判断两个斜着的,同理也是直接返回数组里面的字符。
然后,我们要判断平局,平局的条件为:棋盘满了,且没有一方获胜,所以我们要再创建一个函数IsFull(),来判断棋盘是否满了。满了IsFull()函数返回1给IsWin()函数,然后IsWin函数再返回P。若三者都没达成条件,则返回j,表示游戏继续。IsWin()代码如下:
IsWin()判断当前状况函数
//判断胜利
//玩家胜利,返回*
//电脑胜利,返回#
//继续,返回j
//平局,返回p
char IsWin(char arr[ROW][COL], int row, int col)
{
int x = 0, y = 0;
//判断横
for (x = 0; x < ROW; x++)
{
int PlayerWin = 0;
int ComputerWin = 0;
for (y = 0; y < COL; y++)
{
if (arr[x][y] == '*')
{
PlayerWin++;
}
if (arr[x][y] == '#')
{
ComputerWin++;
}
}
if (ComputerWin == ROW)
{
return '#';
}
if (PlayerWin == ROW)
{
return '*';
}
}
//判断竖
for (y = 0; y < COL; y++)
{
int PlayerWin = 0;
int ComputerWin = 0;
for (x = 0; x < ROW; x++)
{
if (arr[x][y] == '*')
{
PlayerWin++;
}
if (arr[x][y] == '#')
{
ComputerWin++;
}
}
if (PlayerWin == COL)
{
return '*';
}
if (ComputerWin == COL)
{
return '#';
}
}
//判断交叉
int PlayerWin = 0;
int ComputerWin = 0;
for (x = 0, y = 0; (x < ROW) && (y < COL); x++, y++)
{
if (arr[x][y] == '*')
{
PlayerWin++;
}
if (arr[x][y] == '#')
{
ComputerWin++;
}
if (PlayerWin == COL)
{
return '*';
}
if (ComputerWin == COL)
{
return '#';
}
}
PlayerWin = 0;
ComputerWin = 0;
for (x = ROW-1, y = 0; (x > 0) && (y < COL); x--, y++)
{
if (arr[x][y] == '*')
{
PlayerWin++;
}
if (arr[x][y] == '#')
{
ComputerWin++;
}
if (PlayerWin == COL)
{
return '*';
}
if (ComputerWin == COL)
{
return '#';
}
}
//判断是否填满了
if (IsFull(arr, ROW, COL))
{
return 'p';
}
//以上都不满足时,则游戏继续,返回j
return 'j';
}
由于判断横竖有很多相同的地方,这样会导致代码很长。在输赢判断完之后再检测一下是否填满了,把IsFull()函数放在IsWin()函数上面。IsFull()函数代码如下:
IsFull()判断是否填满函数
int IsFull(char arr[ROW][COL], int row, int col)
{
int x = 0, y = 0;
for (x = 0; x < ROW; x++)
{
for (y = 0; y < COL; y++)
{
if (arr[x][y] == ' ')
return 0;
}
}
return 1;
}
我们接着看回game.c文件中的部分代码。整个game函数里为了实现游戏进行而创建的一个一个嵌套函数,若IsWin返回的值不是j,即游戏结束,break跳出死循环,然后下面再用if判断返回的是哪个字符,从而打印谁获胜或者平局。
char ret = 'j';//判断游戏是否继续的条件
while (1)
{
PlayerMove(arr, ROW, COL);
PrintArr(arr, ROW, COL);
ret = IsWin(arr, ROW, COL);
if (ret != 'j')
{
break;
}
ComputerMove(arr, ROW, COL);
PrintArr(arr, ROW, COL);
ret=IsWin(arr, ROW, COL);
if (ret != 'j')
{
break;
}
}
if (ret == '*')
{
printf("玩家胜利\n");
}
if (ret == '#')
{
printf("电脑胜利\n");
}
if (ret == 'p')
{
printf("平局\n");
}
}
判断完胜利后,全部代码已经写完,功能也就实现了,就可以进行测试游玩了。最后我们来看一下全部的代码。
全部代码
text.c
//三子棋小游戏
#include"game_3ziqi.h"
//菜单
void mune()
{
printf("*************************\n");
printf("******* 1.play ********\n");
printf("******* 0.exit ********\n");
printf("*************************\n");
}
void game()
{
char arr[ROW][COL] = {0};
ChuShi(arr, ROW, COL);
PrintArr(arr, ROW, COL);
char ret = 'j';//判断游戏是否继续的条件
while (1)
{
PlayerMove(arr, ROW, COL);
PrintArr(arr, ROW, COL);
ret = IsWin(arr, ROW, COL);
if (ret != 'j')
{
break;
}
ComputerMove(arr, ROW, COL);
PrintArr(arr, ROW, COL);
ret=IsWin(arr, ROW, COL);
if (ret != 'j')
{
break;
}
}
if (ret == '*')
{
printf("玩家胜利\n");
}
if (ret == '#')
{
printf("电脑胜利\n");
}
if (ret == 'p')
{
printf("平局\n");
}
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
mune();
printf("是否游玩(0/1)?\n");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
default:
printf("输入错误,请重新输入!\n");
}
} while (input);
return 0;
}
game.c
#include"game_3ziqi.h"
//初始化数组
void ChuShi(char arr[ROW][COL], 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 PrintArr(char arr[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 ",arr[i][j]);
if (j < COL - 1)
{
printf("|");
}
}
printf("\n");
//打印分割行
for (j = 0; j < COL; j++)
{
//分割行只打印2列
if (i < ROW - 1)
{
printf("---");
if (j < COL - 1)
{
printf("|");
}
}
}
printf("\n");
}
}
//玩家移动 *
void PlayerMove(char arr[ROW][COL], int row, int col)
{
int x = 0, y = 0;
printf("请输入要下棋的坐标:\n");
//getchar();
while (1)
{
scanf("%d %d", &x, &y);
if ((((x - 1) >= 0) && ((x - 1) < ROW)) && (((y - 1) >= 0 )&& ((y - 1) < COL)))
{
if (arr[x-1][y-1] == ' ')
{
arr[x-1][y-1] = '*';
break;
}
else
{
printf("坐标已被占用,请重新输入坐标\n");
}
}
else
{
printf("输入坐标超出范围,请重新输入:\n");
}
}
}
//电脑移动
void ComputerMove(char arr[ROW][COL], int row, int col)
{
int x = 0, y = 0;
while (1)
{
x = rand() % ROW;//控制在0、1、2
y = rand() % COL;
if (arr[x][y] == ' ')
{
arr[x][y] = '#';
break;
}
}
}
//判断胜利
//玩家胜利,返回*
//电脑胜利,返回#
//继续,返回j
//平局,返回p
int IsFull(char arr[ROW][COL], int row, int col)
{
int x = 0, y = 0;
for (x = 0; x < ROW; x++)
{
for (y = 0; y < COL; y++)
{
if (arr[x][y] == ' ')
return 0;
}
}
return 1;
}
char IsWin(char arr[ROW][COL], int row, int col)
{
int x = 0, y = 0;
//判断横
for (x = 0; x < ROW; x++)
{
int PlayerWin = 0;
int ComputerWin = 0;
for (y = 0; y < COL; y++)
{
if (arr[x][y] == '*')
{
PlayerWin++;
}
if (arr[x][y] == '#')
{
ComputerWin++;
}
}
if (ComputerWin == ROW)
{
return '#';
}
if (PlayerWin == ROW)
{
return '*';
}
}
//判断竖
for (y = 0; y < COL; y++)
{
int PlayerWin = 0;
int ComputerWin = 0;
for (x = 0; x < ROW; x++)
{
if (arr[x][y] == '*')
{
PlayerWin++;
}
if (arr[x][y] == '#')
{
ComputerWin++;
}
}
if (PlayerWin == COL)
{
return '*';
}
if (ComputerWin == COL)
{
return '#';
}
}
//判断交叉
int PlayerWin = 0;
int ComputerWin = 0;
for (x = 0, y = 0; (x < ROW) && (y < COL); x++, y++)
{
if (arr[x][y] == '*')
{
PlayerWin++;
}
if (arr[x][y] == '#')
{
ComputerWin++;
}
if (PlayerWin == COL)
{
return '*';
}
if (ComputerWin == COL)
{
return '#';
}
}
PlayerWin = 0;
ComputerWin = 0;
for (x = ROW-1, y = 0; (x > 0) && (y < COL); x--, y++)
{
if (arr[x][y] == '*')
{
PlayerWin++;
}
if (arr[x][y] == '#')
{
ComputerWin++;
}
if (PlayerWin == COL)
{
return '*';
}
if (ComputerWin == COL)
{
return '#';
}
}
//判断是否填满了
if (IsFull(arr, ROW, COL))
{
return 'p';
}
//以上都不满足时,则游戏继续,返回j
return 'j';
}
game.h
#include<stdio.h>//printf
#include<time.h>//time
#include<stdlib.h>//rand,srand
#define ROW 3
#define COL 3
//函数声明
//初始化棋盘
void ChuShi(char arr[ROW][COL], int row, int col);
//打印棋盘
void PrintArr(char arr[ROW][COL], int row, int col);
//玩家下棋
void PlayerMove(char arr[ROW][COL], int row, int col);
//电脑下棋
void ComputerMove(char arr[ROW][COL], int row, int col);
//判断胜利
char IsWin(char arr[ROW][COL], int row, int col);