我这次采用的函数声明定义以及实现三个文件分开的写法。
函数申明:game.h 函数定义:game.c 游戏实现的主函数:test.c
首先一款游戏肯定不可能是只玩一次的,一定是想玩可以一直玩,不想玩就退出的,那么,我们就需要一个循环语句进行控制。而游戏一般都要有开始界面,那么就需要在游戏开始前就打印写东西先运行起来。这个时候do……while结构的循环语句(do……while是先进行一次循环再去判断是否继续循环。)就能很好的实现我们想要的功能。
这个是我们的主函数:
int main()
{
srand((unsigned int)time(NULL));//设置随机数的起点;
int input = 0;
do
{
menu();//打印菜单
printf("请选择:>");
scanf("%d", &input);
switch(input)
{
case 1:
{
//进入游戏。
game();
break;
}
case 0:
{
printf("退出游戏n");
break;
}
default:
{
printf("选择错误,重新选择。");
break;
}
}
} while(input);
return 0;
}
具体的逻辑就是,我们运行程序后会先打印一份菜单,然后进入switch语句进行选择,是否进入游戏,或者退出游戏。我们先约定好进入游戏输入1,退出游戏输入0.然后将我们输入的值成为while的判断条件,这样输入1,while会判断为真就能一直玩;而输入0,while则会判断为假终止游戏。
然后就是菜单函数的打印,可以diy自己写出自己想要的效果
void menu()
{
printf("****************************************n");
printf("***************三 子 棋*****************n");
printf("****************************************n");
printf("***************菜 单*****************n");
printf("**************1.开始游戏****************n");
printf("**************0.退出游戏****************n");
printf("****************************************n");
}
我的就是一个简单的开始和退出。
解决了游戏的基本框架,那就要开始游戏的设计了
游戏的基本思路就是首先我们初始化棋盘再将棋盘打印在屏幕上。接下来下棋的过程则是一个循环的过程,我们用while循环去进行控制。
下棋的过程就是我们先让玩家下棋,之后我们判断输赢后打印棋盘,若玩家未赢则电脑下棋,下完后再次判断输赢,循环往复,直到一方获胜,再次打印棋盘,宣布获胜方。
void game()
{
char ret = 0;
char board[ROW][COL] = { 0 };
//初始化棋盘。
InitBoard(board,ROW,COL);
//打印棋盘。
DispalyBoard(board, ROW, COL);
//下棋
while (1)
{
//玩家下棋
PalyerMove(board, ROW, COL);
//判断输赢
ret = IsWin(board, ROW, COL);
if(ret != 'C')
{
break;
}
DispalyBoard(board, ROW, COL);
//电脑下棋
ComputerMove(board, ROW, COL);
//判断输赢
ret = IsWin(board, ROW, COL);
if (ret != 'C')
{
break;
}
DispalyBoard(board, ROW, COL);
}
if (ret == '*')
{
printf("玩家胜利!n");
}
else if (ret == '#')
{
printf("电脑胜利!n");
}
else
{
printf("平局n");
}
DispalyBoard(board, ROW, COL);
}
游戏设计方面我们首先需要一个二维数组去存放玩家和电脑下棋的数据。所以,创建二维数组是一定的,但是为了我们的游戏可以更加具有灵活性,我们将二维数组的行和列的大小用常量进行定义,这样我们的棋盘就能可大可小,改起来很方便。
#pragma once #define _CRT_SECURE_NO_WARNINGS 1 #include#include #include #define ROW 3 #define COL 3 //初始化棋盘 void InitBoard(char board[ROW][COL], int row, int col); //打印棋盘 void DispalyBoard(char board[ROW][COL], int row, int col); //玩家下棋 void PalyerMove(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);
这个是我们声明函数的game.h头文件中的内容,因为函数的定义和实现两个文件所需要的库函数头文件大部分相同,所以我们将所有的头文件引用,函数声明,以及常量声明都放在game.h的头文件中,然后在其他两个文件中用#include"game.h"进行引用就可以更加方便。
讲完框架再讲game里面的棋盘初始化,打印,以及玩家下棋和电脑下棋判断输赢的这些函数该怎么去写。
首先是初始化棋盘,我们玩家和电脑下棋所下的棋子都是一个个字符,所以我们先要用char类型去定义一个二维数组。然后,我们讲二维数组里的元素全部都先放入空格,那么玩家们看上去就跟没下过棋一样。
void InitBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
ok,一个二维数组简单的遍历就能轻松搞定,ps.(空格一定要用单引号去写,不然就会成为乱码,个人经历。)
接下来是打印棋盘
我们想想象一下棋盘的样子,首先它能存放九个元素,其次,要讲九个元素分开显得不拥挤。那么我们就可以用空格,竖线(|),还有减号(---),去画一个井字。
void DispalyBoard(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]);
if (j < col - 1)
{
printf("|");
}
}
printf("n");
if (i < row - 1)
{
int j = 0;
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
{
printf("|");
}
}
printf("n");
}
}
}
这个代码的思路就是,我们将井字拆开,我们会发现可以拆成三个部分:
我们发现前两个部分相同,只有第三个部分比前两个部分少一个横线,那我们将他们的列分开三份,发现也是一样只有第三个部分少个竖线。那么我们只要吧横线和竖线分别打印,然后控制他们最后一次少打印一个横线和竖线,然后再循环三次,就能得到一个井字了。
void DispalyBoard(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]);
if (j < col - 1)
{
printf("|");
}
}
printf("n");
if (i < row - 1)
{
int j = 0;
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
{
printf("|");
}
}
printf("n");
}
}
}
ps.(不要忘记再后面打印"n",不然就会挤在一起了。)
再然后就是下棋部分,分为玩家下棋和电脑下棋。
玩家下棋我们只需要先创建两个临时变量存放玩家输入的行和列,然后再将其对应到二维数组的下标中就能实现下棋了,这里需要注意的是一定要判断玩家输入的数字是否合法。然后因为c语言的二维数组下标行和列都是从0开始,但是正常人习惯都是从1开始,所以不要忘了在找下标的时候给数字减一。
玩家下棋
void PalyerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("玩家下棋n");
while (1)
{
printf("请输入坐标:>");
scanf("%d%d", &x, &y);
//判断玩家输入坐标合法性
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '*';
break;
}
else
{
printf("坐标被占用,请重新输入。n");
}
}
else
{
printf("坐标非法请重新输入。n");
}
}
}
电脑下棋则有很多种方式,我们写一种比较简单的,就是让电脑找到空格然后将棋下进去,这样的做法会让电脑很笨,但是由于博主技术有限,只会这种,其他的方法还在尝试。
首先我们先用rand函数生成两个随机数然后分别%上行和列,就能得到0~2之间的数字,然后判断这两个随机数下标的二维数组元素是否为空格,如果是就下棋。
void ComputerMove(char board[ROW][COL], int row, int col)
{
printf("电脑下棋:n");
int x = 0;
int y = 0;
while (1)
{
x = rand() % row;
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
接下来就是最难的判断输赢的函数了。
首先我们要先知道如何使用这个函数,我们先约定好如果玩家胜利返回‘*’,电脑胜利返回‘#’,如果游戏继续返回‘C’,如果平局我们就返回‘Q’。
然后我们将玩家下棋,判断输赢,电脑下棋判断输赢看成一个循环放到一起。就可以写成这段代码。
while (1)
{
//玩家下棋
PalyerMove(board, ROW, COL);
//判断输赢
ret = IsWin(board, ROW, COL);
if(ret != 'C')
{
break;
}
DispalyBoard(board, ROW, COL);
//电脑下棋
ComputerMove(board, ROW, COL);
//判断输赢
ret = IsWin(board, ROW, COL);
if (ret != 'C')
{
break;
}
DispalyBoard(board, ROW, COL);
}
只要返回‘C’那么游戏就会继续,如果游戏结束,那就可以判断是玩家赢还是电脑赢还是平局。
if (ret == '*')
{
printf("玩家胜利!n");
}
else if (ret == '#')
{
printf("电脑胜利!n");
}
else
{
printf("平局n");
}
DispalyBoard(board, ROW, 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][1] != ' ')
{
return board[i][1];
}
}
//列
int j = 0;
for (j = 0; j < col; j++)
{
if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[1][j] != ' ')
{
return board[1][j];
}
}
//对角线
if (board[0][1] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
{
return board[1][1];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
{
return board[1][1];
}
而判断平局则需要看看棋盘上是否有空格,如果有,那就是继续,如果没有就是平局。
而我们用一个函数去遍历一遍,如果有就空格返回0,没有空格就返回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][1] != ' ')
{
return board[i][1];
}
}
//判断平局
if (IsFull(board, row, col))
{
return 'Q';
}
else
return 'C';
写到这,这个游戏就算初步完成了,可以进行正常的游戏,但是还有很多不足,比如判断输赢依旧只能判断三子棋,其他类似于五子棋就无法判断,还有就是电脑下棋的方式也十分笨拙,有很大的改进空间!



