迟来的小游戏之三子棋,哈哈哈哈哈好久之前本来就要写这篇博客,因为有事情就一直拖着,接下来就给大家详细的讲解小游戏三子棋.
前言
首先是需要的头文件如下
定义行和列
这个#pragma once是防止包含有多个头文件,因为代码比较多了,就需要分模块去做,每个模块有着自己的工作
这个小游戏就分为了三个模块
Game.h;//游戏代码的声明(函数声明,符号定义)
Game.c;//游戏代码的实现
test.c//测试游戏的逻辑
这样可以使别人看到代码后清晰明了,便于阅读
一、运行菜单
第一步先要做出基本的运行界面供用户选择
代码如下,就不做过多解释了
menu() {
printf("************************\n");
printf("********1. play ********\n");
printf("********0. exit ********\n");
printf("************************\n");
}
二、用户选择
如果选择1就开始游戏,选择0就退出游戏,输入其他告诉用户输入错误需要重新选择.
这里我们就需要用到do while()循环,使得程序至少进行一次
代码如下
int input = 0;
do
{
menu();//打印菜单
printf("请选择->");
scanf("%d",&input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,请重新选择\n");
break;
}
} while (input);
switch语句是控制走向哪一步
这里输入input,input的值来控制循环的进行还是停止.
三、游戏的实现
1.棋盘的初始化
这里我们给入一个新的函数InitBoard();
首先棋盘一开始每个元素都为空
引入代码
//棋盘的初始化
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] = ' ';
}
}
}
2.打印棋盘
目标棋盘是这个样子,我们需要多组循环来控制输入
首先是第一行 | |
我们可以打印的打印一个空格一个元素一个空格
printf(" %c ",board[i][j]);
接下来在打印一个|
然后还有一个条件最后一个|不进行打印
加一条if语句来控制
当循环数小于列数-1才打印|
同理第二行打印—
当循环数小于列数-1才打印|
最后一行不打印
加一条if判断循环数小于行数-1不打印即可
代码如下
//打印棋盘
void DisPlayBoard(char board[Row][Col], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
//打印数据
//printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
int j = 0;
for (int j = 0; j < col; j++)
{
printf(" %c ",board[i][j]);
if(j<col-1)
printf("|");
}
printf("\n");
//打印分割信息
//printf("---|---|---\n");
if (i < row - 1)
{
int j = 0;
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
printf("\n");
}
}
}
四、用户下棋
因为用户输入行和列就是正常逻辑来走,不像数组首元素下标从0走
所以我们稍作调整即可
其次首先输入的坐标判断位置是否合法,不合法的话重新输入
合法之后判断这个位置是否为空,可以继续下棋,否则就重新输入
代码如下
void PlayMove(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()生成随机值函数,又因为生成后直到这个程序结束之前一直不变,这里我们就要用到srand()函数,函数里面在调用time()函数返回时间戳,因为时间一直在变化,所以生成的随机数也在变化
这里要包含time的头文件
srand()函数传参值,对应一个固定的随机数序列,通过改变srand的传参值实现产生不同随机数序列
例
srand(1) 对应一个固定随机数序列,srand(2)对应另外一个随机数序列
函数原型
int rand(void);
void srand(unsigned seed);
参数说明
seed:srand()的种子,用于初始化srand()的起始值
//电脑下棋
//找没有下棋的地方随机下棋
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;
}
}
}
取余的操作是为了使得生成的数在0到2之间
六、判断棋盘是否为空
//如果满了 返回1
//未满返回0
代码如下
IsFull(char board[Row][Col], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j << col; j++)
{
if (board[i][j] == ' ')
{
return 0;
}
}
}
return 1;
}
七、判断输赢
//玩家赢返回’*’
//电脑赢了返回’#’
//平局返回’Q’
//继续返回’C’
玩家或者电脑赢得条件无非是每行,每列,对角线有三个相同的即可
平局就是九个格子都下满了,还没有决出胜负
如果上面的都不满足游戏就继续
char Iswin(char board[Row][Col], int row, int col)
{
//行
for (int i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ')
{
return board[i][0];
}
}
//列
for (int i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
{
return board[0][i];
}
}
//对角线
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
{
return board[1][1];
}
if (board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[1][1] != ' ')
{
return board[1][1];
}
//平局
if (IsFull(board[Row][Col],row,col))
{
return 'Q';
}
//游戏继续
return 'C';
}
到此我们游戏的实现就全部结束啦.
八、拓展
如果以后项目做得好了,要卖出去,可以封装成一个静态库,给公司一个声明,告诉他们怎么使用,不给代码,利用声明就可以实现。
1、右键单击项目,选择属性,在配置属性里,将配置类型改为静态库(.lib),点击确定。
2、右键点击项目,生成。
3、右键点击项目,选择在文件资源管理器中打开文件夹,然后跳到上一层目录,找到Release文件夹,其中便有MYFIRSTLIB.lib文件,即为生成的静态库。
打开就是一堆反汇编代码,不会被破解出源代码.
总结
以上Row和Col可以自定义改变棋盘的大小,可以改成5x5
9x9…
只需要在声明的时候改变值就可以。
还有就是可以编写电脑下棋的步骤,可以按照人的思维去赢,和堵别人。
我的能力有限,今天就写到这里啦.
希望三连支持哦!!!