之前我们学过函数,数组,循环选择分支等等,我们今天就用现有的C语言知识编写一个小游戏——三子棋游戏。
说到三子棋,我们应该先构思所需要的内容。
1.构建一个游戏菜单界面
2.创建一个3*3的棋盘
3.选择先手(玩家先还是电脑先)
4.轮流下棋流程
5.判断胜负
此次游戏代码将分为两大模块,主函数体系和游戏函数体系
我们在主函数中,可以使用do while 函数进行游戏的循环在用switch嵌套创建一个主观菜单,让玩家进行循环游戏,也可以直接推出游戏,增加了游戏的开始界面。
代码如下:
void Screenmeau(void)
{
printf("*******************\n");
printf("******1.Play******\n");
printf("******0.Exit*******\n");
printf("*******************\n");
}
int main(void)
{
int input = 0;
do {
Screenmeau();
printf("请输入数字:");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
break;
default:
printf("请从新输入数字,0或1\n");
break;
}
} while (input != 0);
return 0;
}
通过选择0,可以结束游戏,选择1,进入游戏,选择其他数字则属于非法输入,需要重新选择。当我们选择1时,就可以进入游戏函数体系了。
当我们在主函数中的菜单进行选择进入游戏后,我们的第一大任务就是创建一个棋盘。棋盘的本质就是一个二维数组。那我们这次的目标为三子棋,我们可以使用#define ROW 3 和#define COL 3进行常量定义,在以后的使用或游戏的修改都提供了便利。
首先创建一个未被初始化的二维数组arr,将arr传入Array函数中进行初始化,arr中放入空格可以当作空棋盘。但如果打印棋盘给予玩家的视觉冲击很差,什么也看不见。所以我们应该将棋盘进行美化。
美化棋盘其实非常简单,可以在打印棋盘的同时,打印一些符号将棋盘鲜明化,利用for循环和一些if语句的镶嵌组合就可以将其完成。
见代码:
void Array(char arr[ROW][COL], int row, int col)//arr数组的初始化
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
arr[i][j] = ' ';
}
}
}
void Ddfinarray(char arr[ROW][COL], int row, int col)//棋盘的美化
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
printf(" %c ", arr[i][j]);
if(j < col-1)
printf("|");
}
printf("\n");
for (int j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
printf("\n");
}
}
美化的棋盘:
之前的代码只是准备工作,与玩家没有多大的关系,接下来我们将正式进入游戏的环节。
创建一个choosemeau函数让玩家选择,是玩家先下棋还是让电脑先。与主函数的思路一样,使用do while循环中间嵌套一个switch提供菜单让玩家进行选择。然后创建两个函数,一个是玩家的下棋函数,一个是电脑下棋函数,无论在上一环节选择1或者2,只是两个函数的先后执行顺序不同。所以先完成两个函数体。
int Choosemeau(void)//选择先手菜单程序
{
int a = 0;
do {
printf("********************\n");
printf("*****1.玩家先 ******\n");
printf("*****2.电脑先 ******\n");
printf("********************\n");
printf("请选择:");
scanf("%d", &a);
switch (a)
{
case 1:
return 1;
case 2:
return 2;
default:
printf("只能输入1或2,请重新输入\n");
}
} while (1);
}
首先完成玩家下棋函数,提供两个变量,分别对应下棋的坐标,因为这个棋盘实质是一个二维数组,数组的第一个元素的下标为0,但是玩家不都是程序员,所以我们应当在玩家输入对应坐标后将其坐标减1,得到的值才是玩家心里所想的值。
为了使游戏更加严谨,作为程序员我们应该考虑更加全面。有两个问题,输入的值超出数组下标,玩家下棋的位置已有棋子。我们应该让程序避免出现这两个问题,我们可以用分支语句进行判断,如果玩家选择的位置的值是空格并且输入的坐标没有超出数组的下标,既可以落子,玩家的棋子用‘*’表示。反正系统将提醒非法落子,需要玩家重新输入两个合法的坐标。
void Playermove(char arr[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
while (1)
{
printf("请输入要下棋的横竖坐标:");
scanf("%d %d", &x, &y);
if (arr[x - 1][y - 1] == ' ')
{
if (x > 0 && x <= row && y >0 && y <= col)
{
arr[x - 1][y - 1] = '*';
break;
}
}
else
{
printf("非法落子\n");
}
}
}
完成玩家下棋函数后,我们将进行电脑下棋。
下棋的本质就是在arr二维数组中选择合适的两个下标,所以我们可以使用随机数函数rand()和srand()的函数,我们在主函数中引入srand((unsigned int )time(NULL));,就可以在函数中使用rand()函数中产生随机数(使用rand(),srand(),time()函数得引用头文件#include
void Displayermove(char arr[ROW][COL], int row, int col)
{
printf("电脑下棋\n");
while (1)
{
int x = rand() % row;
int y = rand() % col;
if (arr[x][y] == ' ')
{
arr[x][y] = '#';
break;
}
}
}
当玩家和电脑都走了一步之后,我们将棋盘展现出来,可以更直观的看出棋子的位置。所以我们可以在两个下棋函数运行完成后运行一下Ddfinarray函数,将棋盘打印出来即可。
如果现在运行程序,当棋盘被占满后会进入死循环,就相当于递归没退出程序。而退出的程序就是判断棋的输赢。
下棋的结果一般有四个:玩家赢,电脑赢,和棋,继续游戏。
无论玩家赢电脑赢还是和棋就可以结束循环了,但是继续游戏还需要我们继续下棋。所以我们现需要一个函数来判断棋盘是否下满,利用for循环对数组中的每个元素进行检测判断,如果没有空格就是棋盘下满了。这个函数需要有返回值供以后选择,如果棋盘满了则返回值为1,反之返回0。
三子棋的获胜条件就是让横竖斜都是同一种棋子,创建一个判断胜负的函数,在玩家和电脑每下一步棋后进行判断,并且这个函数有返回值char,返回的值在if判断条件时可以使用,如果返回的是’*‘时,则玩家赢,返回是‘#’电脑赢,返回是‘h’为和棋,返回c为继续。
这里就有一个非常巧妙的点,用数组判断横竖斜是否相等并且不等于空格,返回值为数组的符号,这样就可以用一个函数来提取其中的返回值即可,使用if就可以知道游戏的输赢。如果前面的横竖斜都没有相同的时,使用上一个函数的返回值当作下一个if的判断条件,即可判断出是否和棋。如果棋盘没有满将使用continue退出此次循环进行下一次两两下棋,直到得到结果,游戏结束。
游戏函数的主体:
void game(void)
{
char arr[ROW][COL] = { 0 };
Array(arr, ROW, COL);
Ddfinarray(arr, ROW, COL);
int a = Choosemeau();
if (a == 1)
{
while (1)
{
Playermove(arr, ROW, COL);
Ddfinarray(arr, ROW, COL);
Displayermove(arr, ROW, COL);
Ddfinarray(arr, ROW, COL);
char ch =Iswin(arr, ROW, COL);
if (ch == '*')
{
printf("玩家赢\n");
break;
}
else if (ch == '#')
{
printf("电脑赢\n");
break;
}
else if (ch == 'c')
{
continue;
}
else
{
printf("和棋\n");
break;
}
}
}
else
{
while (1)
{
Displayermove(arr, ROW, COL);
Ddfinarray(arr, ROW, COL);
Playermove(arr, ROW, COL);
Ddfinarray(arr, ROW, COL);
char ch = Iswin(arr, ROW, COL);
if (ch == '*')
{
printf("玩家赢\n");
break;
}
else if (ch == '#')
{
printf("电脑赢\n");
break;
}
else if (ch == 'c')
{
continue;
}
else
{
printf("和棋\n");
break;
}
}
}
}
判断棋盘是否下满函数:
int Isfull(char arr[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
for (int j = 0; j < col; j++)
{
if (arr[i][j] == ' ')
return 1;
}
}
判断输赢的函数:
char Iswin(char arr[ROW][COL], int row, int col)
{
for(int i = 0; i < row; i++)
{
if (arr[i][0] == arr[i][1] && arr[i][1] == arr[i][2] && arr[i][0] != ' ')
return arr[i][0];
}
for(int j = 0; j < col; j++)
{
if (arr[0][j] == arr[1][j] && arr[1][j] == arr[2][j] && arr[2][j] == '*')
return arr[0][j];
}
if (arr[0][0] == arr[1][1] && arr[1][1] == arr[2][2] && arr[2][2] == '*')
{
return arr[0][0];
}
if (arr[0][0] == arr[1][1] && arr[1][1] == arr[2][2] && arr[2][2] == '#')
{
return arr[0][0];
}
if (Isfull(arr, ROW, COL))
return 'c';
else
return 'h';
}
将这些函数结合一起就可以得到三子棋小游戏,现在让我们玩一下。