赞
踩
目录
这里是趣味小游戏第二篇,扫雷想必也是大家以前电脑上必备的休闲游戏,那么今天我就来带大家用代码的方式来回忆并实现它吧!
要实现游戏我们首先要搭建出一个主体游戏框架。
- #include <stdio.h>
-
- void menu()
- {
- printf("********************\n");
- printf("***** 1.play *****\n");
- printf("***** 0.exit *****\n");
- printf("********************\n");
- }
-
- void test()
- {
- int input = 0;
- do
- {
- menu();//给出一个游戏的开始菜单
- printf("欢迎来到扫雷游戏\n");
- printf("输入1开始游戏,输入0退出游戏\n");
- printf("请输入:");
- scanf("%d", &input);
- switch (input)//对于不同输入值给出不同结果
- {
- case 1:
- game();//由此进入游戏
- break;
- case 0:
- printf("游戏已退出\n");//由此退出游戏
- break;
- default:
- printf("输入错误,请重新输入:");//输入其他值时给出反馈,增强代码健壮性
- break;
- }
- } while (input);//输入为真(1)时则进入do里的循环输入为假(0)时即退出循环
- }
-
- int main()
- {
- test();//主体内容
- return 0;
- }
在搭建好主体后,我们就进入游戏实现阶段。
- #define ROW 9
- #define COL 9
-
- #define ROWS ROW+2
- #define COLS COL+2
-
- void game()
- {
- //1.给出一个ROW*COL的棋盘
- char mine[ROWS][COLS];
- char show[ROWS][COLS];
- //2.初始化两棋盘
- IniBoard(mine, ROWS, COLS, '0');
- IniBoard(show, ROWS, COLS, '*');
- //3.随机生成雷
- SetMine(mine, ROW, COL);
- //4.反馈信息
- //PrintBoard(mine, ROW, COL);
- PrintBoard(show, ROW, COL);
- //5.排雷过程
- FindMine(mine, show, ROW, COL);
- }
我们在这里假定ROW=COL=9,那么目标就是产生这样一个9*9的棋盘。
而在我们统计一个格子周围雷的个数时,会出现一些格子统计雷的数量比较困难(如9 9坐标),因此我们将其行和列拓宽两行得到如下棋盘
因此我们便创建两个11*11的二维数组,一个用来作为生成雷的数组(mine),一个用来作为玩家看与猜测的数组(show)。
在成功生成两棋盘后,我们对其分别进行初始化(即将所有的元素化成同一元素)。
在此,我们将mine数组初始化为'0'(后面会解释),将show数组初始化为'*'(方便玩家观察该数组)。因此,我们编写一个函数来实现此目的。
- void IniBoard(char board[ROWS][COLS], int row, int col, char n)
- {
- int i = 0;
- for (i = 0; i < row; i++)//得到每行数据
- {
- int j = 0;
- for (j = 0; j < col; j++)//得到每列数据
- {
- board[i][j] = n;//将每个元素都转变成字符n
- }
- }
- }
在初始化两数组后,我们便开始在mine数组中随机布置雷。
(注意:可供我们操作的范围为1 1——9 9的范围内,因此雷的生成位置也应该处于1 1——9 9之间)
- #define EASY 15
- //简单模式的雷的个数
-
- void SetMine(char mine[ROWS][ROWS], int row, int col)
- {
- srand((unsigned int)time(NULL));//用时间戳来创造伪随机数
- int count = EASY;
- while(count)
- {
- int x = rand() % row + 1;
- int y = rand() % col + 1;//因为行数与列数确定,因此需要保证x,y都处于[1,9]这个区间
- if (mine[x][y] == '0')//判断该位置是否已经被布置了雷
- {
- mine[x][y] = '1';
- count--;//布置成功则使需要布置的雷的个数减少一个
- }
- }
- }
在游戏进行的过程中,我们作为玩家需要不断地知道自己输入坐标后的结果怎么样,所以便离不开显示棋盘这一操作,因此,我们便设计一个函数来进行这个操作。
- void PrintBoard(char board[ROWS][COLS], int row, int col)
- {
- int i = 0;
- int j = 0;
- printf("---------扫雷游戏--------\n");//上分割行
- for (j = 0; j <= col; j++)
- {
- printf("%d ", j);//提供一个精准的定位信息
- }
- printf("\n");
- for (i = 1; i <= row; i++)
- {
- printf("%d ", i);
- for (j = 1; j <= col; j++)
- {
- printf("%c ", board[i][j]);//打印每个元素
- }
- printf("\n");
- }
- printf("---------扫雷游戏--------\n");//下分割行
- }
我们用它来打印show数组,得到如下的效果
在看到棋盘后,想必大家已经手痒痒了吧,别急,让我来带各位进入正戏环节。
还是老样子,我们编写一个函数来实现这一步骤。
- void Change(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col)
- {
- int i = 1;
- for (i = 1; i <= row; i++)
- {
- int j = 1;
- for (j = 1; j <= col; j++)
- {
- if (mine[i][j] == '1')
- {
- show[i][j] = '#';//将mine棋盘中的雷表现为show数组中的#
- }
- }
- }
- }
-
- int MineCount(char board[ROWS][COLS], int x, int y)
- {
- return board[x-1][y-1] + board[x-1][y] + board[x-1][y+1] + board[x][y-1]
- + board[x][y+1] + board[x+1][y-1] + board[x+1][y] + board[x+1][y+1] -8*'0';//根据ASCII码表将所有1的个数相加并返回
- }
-
- void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
- {
- printf("输入排查位置(如5 5)\n");
- int count = ROW * COL - EASY;//用count代表场上除去雷的剩余位置
- while(1)//无法具体确定判断条件,所以用1作为条件,后面完成行为后用break跳出
- {
- int x = 0;
- int y = 0;
- printf("请输入你想排查的坐标\n");
- printf("请输入:");
- scanf("%d %d", &x, &y);
- if (x >= 1 && x <= row && y >= 1 && y <= col)//判断输入的位置是否在棋盘内,如果不在内就反馈给玩家
- {
- if (mine[x][y] == '1')
- {
- printf("很遗憾,你碰到了炸弹,游戏结束\n");
- Change(show, mine, row, col);//在判定玩家已输的情况下,将情况反映到show数组上
- PrintBoard(show, row, col);//让玩家知道自己如何输的
- break;
- }
- else if (show[x][y] != '*')//如果玩家手误,可以借此重新输入
- {
- printf("该位置已被排查过,请重新输入\n");
- }
- else
- {
- int ret = MineCount(mine, x, y);//将该位置周围的雷的数量做一个统计
- show[x][y] = '0' + ret;//将该数字通过ASCII码表还原成对应字符
- PrintBoard(show, row, col);//将结果反馈给玩家
- count--;
- }
- }
- else
- {
- printf("输入坐标非法,请重新输入\n");
- }
- if (count == 0)//当除雷以外的剩余个数为0时,那么棋盘上只剩下雷,即玩家获胜
- {
- printf("恭喜你,排雷成功\n");
- PrintBoard(mine, row, col);//将最后结果反馈给玩家
- break;
- }
- }
- }
在经过了上述流程后,虽然我们体验到了扫雷游戏,但是总感觉玩起来不是很方便,此时我们的心头便会冒出一些想法:可不可以在周围有0个雷的时候直接展开一片?在排查完雷之后可不可以自己标记雷的位置?在标记后可不可以显示自己主观认为的剩余的雷的个数?
答案是:当然!
我们先对展开方面进行优化
我们在反馈前先构建一个Cls函数进行对0的清除与展开,即改为如下这样
- else
- {
- int ret = MineCount(mine, x, y);//将该位置周围的雷的数量做一个统计
- show[x][y] = '0' + ret;//将该数字通过ASCII码表还原成对应字符
- Cls(mine, show, row, col, x, y);
- PrintBoard(show, row, col);//将结果反馈给玩家
- count--;
- }
下面具体实现Cls函数
- void Cls(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y)
- {
- if (show[x][y] == '0')//如果此元素已经为'0'才进入此函数
- {
- show[x][y] = ' ';//将其修改为' '便于观查
- int i = x - 1;
- for (; i <= x + 1; i++)
- {
- int j = y - 1;
- for (; j <= y + 1; j++)//得到该元素的从左上到右下的全部下标
- {
- if (show[i][j] == ' ')//如果已经有元素被替换为' ',则无需再次进行下面的操作
- {
- continue;
- }
- if (i >= 1 && i <= row && j >= 1 && j <= col)//判断该元素是否在棋盘内
- {
- if (show[i][j] != '*')//如果该元素不是'*',即已经被赋值了数字就无需进行下面的操作
- {
- continue;
- }
- int ret = MineCount(mine, i, j);//对该元素进行判定
- show[i][j] = '0' + ret;
- Cls(mine, show, row, col, i, j);//不断迭代,直到不再出现0或数字为止
- }
-
- }
- }
- }
- }
成功展开后,我们再来对标记进行操作与优化
- else
- {
- int ret = MineCount(mine, x, y);//将该位置周围的雷的数量做一个统计
- show[x][y] = '0' + ret;//将该数字通过ASCII码表还原成对应字符
- Cls(mine, show, row, col, x, y);
- PlayerJudge(show, row, col);
- PrintBoard(show, row, col);//将结果反馈给玩家
- count--;
- }
同样的我们编写一个PlayerJduge函数来实现此操作
- void Judge(char show[ROWS][COLS], int row, int col)
- {
- printf("坐标操作:\n");
- printf("1 - 不确定是否为雷\n");
- printf("2 - 确定是雷\n");//根据ASCII码表将1和2转换成对应的?与#
- printf("3 - 取消标记\n");
- printf("请输入你想标记的坐标(如5 5) :\n");
- int x = 0;
- int y = 0;
- while(1)
- {
- printf("请输入:");
- scanf("%d %d", &x, &y);
- printf("请输入你想对该坐标进行的操作\n");
- int c = 0;
- scanf("%d", &c);
- if (show[x][y] == '*')
- {
- if (c == 1)
- {
- c = 63;//将1转换成?所对应的ASCII值
- }
- if (c == 2)
- {
- c = 35;//将2转换成#所对应的ASCII值
- }
- char ch = c;
- show[x][y] = ch;
- printf("标记成功!\n");//给出反馈
- PrintBoard(show, row, col);
- break;//结束本次标记
- }
- else if (show[x][y] == '?' || show[x][y] == '#' && c == 3)//如果输入3还要判断该元素是否已经被标记
- {
- show[x][y] = '*';
- printf("取消成功!\n");//给出反馈
- PrintBoard(show, row, col);
- break;
- }
- else
- {
- printf("输入位置不合法,请重新输入\n");//输入不合理
- }
- }
- }
-
- void PlayerJudge(char show[ROWS][COLS], int row, int col)
- {
- int m = 0;
- printf("请问你是否想标记某位置\n");
- printf("是:1 否:0\n");
- do
- {
- printf("请输入(如已标记完毕请输入0,想继续标记请输入1):");//在进行完一次标记后,玩家需要确定是否进行下一次标记
- scanf("%d", &m);
- switch (m)
- {
- case 1:
- Judge(show, row, col);//具体实现标记操作
- break;
- case 0:
- break;
- default:
- printf("输入有误,请重新输入:\n");
- break;
- }
- } while (m);
- }
最后呢,我们再对雷量的剩余做一个LeaveMine函数来反馈
- else
- {
- int ret = MineCount(mine, x, y);//将该位置周围的雷的数量做一个统计
- show[x][y] = '0' + ret;//将该数字通过ASCII码表还原成对应字符
- Cls(mine, show, row, col, x, y);
- PlayerJudge(show, row, col);
- int res = LeaveMine(show, row, col);//show数组中#的个数
- printf("剩余雷量:%d\n", EASY - res);//反馈剩余的雷的个数
- PrintBoard(show, row, col);//将结果反馈给玩家
- count--;
- }
下面是具体的实现办法
- int LeaveMine(char show[ROWS][COLS], int row, int col)
- {
- int i = 1;
- int num = 0;
- for (i = 1; i <= row; i++)
- {
- int j = 1;
- for (j = 1; j <= col; j++)
- {
- if (show[i][j] == '#')//统计所有元素中#的个数
- {
- num++;
- }
- }
- }
- return num;//返回#的个数
- }
至此,我们便完成了扫雷游戏的优化!
以上就是扫雷游戏的全部实现过程了,希望各位程序员能够玩得开心,同时也希望能从本文中得到灵感与启发!路过的点个赞吧,谢谢!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。