赞
踩
友友们好,今天和大家一起做一个简单的C语言小游戏——扫雷小游戏。
游戏规则如下:
扫雷的规则很简单。盘面上有许多方格,方格中随机分布着一些雷。你的目标是避开雷,打开其他所有格子。一个非雷格中的数字表示其相邻8格中的雷数,你可以利用这个信息推导出安全格和雷的位置。打开所有安全格将被判定为胜利,打开雷将被判定为失败。
目录
首先,制作一个游戏菜单,而后构建整个游戏的基本逻辑结构,然后进入游戏的制作。首先要在盘面上随机给出10个雷的位置; 然后玩家需要在盘面的合法位置排雷,如果在非法位置,应给出相应提示;在排雷的同时要判断游戏是否结束,如果结束需要判断胜负。
接下来我们就以这个基本思路来进行代码的实现。
首先,我们要制作一个游戏菜单。我们用一个简易的函数来实现他。
- void menu()
- {
- printf("*********************************\n");
- printf("******* 扫雷小游戏 *********\n");
- printf("******* 1、play *********\n");
- printf("******* 0、exit *********\n");
- printf("*********************************\n");
- }
我们在主函数中可以调用这个函数来实现打印菜单的目的。
制作完菜单后,我们需要构建这个游戏的基本逻辑结构。
首先需要明确我们的需求: 1、我们可以通过输入 1 / 0 来选择开始或结束游戏
2、如果一把玩完不过瘾,我们可以通过选择来再玩一把
· 我们运用分支语句的知识来实现第一个需求。
在这里我使用switch语句,定义一个整型来存放输入的数字,如果输入的数字是 1 ,则提示“开始游戏”;如果输入的数字是 0 ,则提示“结束游戏”;如果输入了 1/0 以外的数字,则我们提醒他输错了,重新输入。
· 我们通过循环来实现第二个需求。
在这里使用do... while() 循环,将定义的整型放在() 里作为判断条件。当我们输入 1 ,为非0,判断为真,游戏继续;当我们输入 0 ,判断为假,游戏结束;当我们输入 1/0 以外的数字,为非0,判断为真,可以继续循环让我们重新判断。
- int main()
- {
- int input;
- //先输入一个input判断要不要进入游戏,将其也设为循环的判断条件
-
- do {
- menu();
- printf("请输入->");
- scanf("%d", &input);
- switch (input)
- {
- case 1:
- printf("开始游戏\n");
- game();
- //如果输入1,说明要玩游戏,封装一个game函数来包含游戏内容
- break;
- case 0:
- printf("退出游戏\n");
- break;
- default:
- printf("输错啦,请重新输入\n");
- break;
- }
- } while (input);
-
- return 0;
- }
从代码运行结果来看,满足了我们提出的两点需求。
两个数组,一个展示,一个放雷
所以我们需要定义两个 11*11的数组,一个用来存放雷的数据,一个用来显示。
为了后期调试的方便,我们可以将数组参数使用#define标识符替换列表中的参数。
- #include<stdio.h>
- #include<stdlib.h> //srand函数的头文件
- #include<time.h> //time函数的头文件
-
- #define ROW 9 //实际使用的行
- #define COL 9 //实际使用的列
-
- #define ROWS 11 //数组使用的行
- #define COLS 11 //数组使用的列
-
- #define COUNT_EASY 10
- //简单版本有10个雷
首先我们封装一个game函数,将实现游戏的内容都放在game函数中。定义两个字符型的二维数组,将二者初始化。
- //初始化数组
-
- void InitBoard(char board[ROWS][COLS], int rows, int cols, char ret)
- {
- int x = 0;
- int y = 0;
- for (x = 0; x < rows; x++)
- {
- for (y = 0; y < cols; y++)
- {
- board[x][y] = ret;
- }
- }
- }
-
-
- void game()
- {
- //为了方便,把两个数组定义成完全一样的
- char mine[ROWS][COLS] = { 0 };
- char show[ROWS][COLS] = { 0 };
-
- //初始化两个数组,传对应的参数进去
- //将雷盘先全都定义为0
- //将显示盘定义为*
- InitBoard(mine, ROWS, COLS, '0');
- InitBoard(show, ROWS, COLS, '*');
-
- }
我们先清楚盘面的格式为:11 * 11 的正方形;其中只需打印中间的9*9,所以我们传ROW与COL进去即可;为了格式好看与查找方便,我们还可以添加一些表头与分隔。
- //打印棋盘
- void DisplayBoard(char board[ROWS][COLS], int row, int col)
- {
- int x = 0;
- int y = 0;
- printf("--------扫雷---------\n");
- for (x = 0; x <= row; x++)
- {
- printf(" %d", x); //打印坐标提示行
- }
- printf("\n");
- for (x = 1; x <= row; x++)
- {
- printf(" %d", x); //打印坐标提示列
- for (y = 1; y <= col; y++)
- {
- printf(" %c", board[x][y]);
- }
- printf("\n");
- }
- printf("---------------------\n");
- }
-
-
-
- //打印的时候传过去的数组还是11*11的,数组是不会变的,不会因为你想打印的是9*9的就变成9*9的数组
- //因为我们只想打印出9*9的格子,所以传过去的是ROW和COL
简易版的9*9盘面内有10个雷,我们可以用rand函数来生成随机值来作为雷生成的坐标。生成雷时需要注意,雷的坐标需要是一个合法坐标,我们可以将生成坐标的过程放进循环里,当雷的坐标为合法坐标时跳出循环。注意将坐标适当处理。我们封装一个函数,在game函数中调用来实现该功能。
- //布置雷
- void Setmine(char board[ROWS][COLS], int row, int col)
- {
- int x = 0;
- int y = 0;
- int count = COUNT_EASY; //雷的数量
- while (count)//当没布置完雷之前都继续循环
- {
- x = rand() % row + 1; //生成数%row后范围是0~8 我们需要的是1~9
- y = rand() % col + 1;
- if (board[x][y] == '0')
- {
- board[x][y] = '1';
- count--;
- }
- }
- }
注意:
C语言中提供了一个rand函数可以帮我们生成随机数,返回值为int 整型,返回的值就是一个随机数。但rand函数生成的是伪随机数,返回的随机值并不完全随机。
![]()
rand函数在生成随机数之前,要使用srand函数设置随机数的生成器。srand()括号中放置类似于生成随机数的种子,种子固定了生成的随机数也是固定的。所以我们要使括号中的值为随机变化的,才能使产生的数值为随机值。
在我们的计算机中,时间是时刻在发生变化的,如果能将时间传入srand中,那么就可以实现真正的随机。这个时候我们可以使用time函数来解决这个问题。
time函数可以返回一个时间戳,时间戳是一串数字, 是随着时间在不断变化的 。在使用时我们需要调用二者的头文件。time函数的返回类型是time_t,在srand中要使用他需要强制类型转换为(unsigned int)
所以在主函数中:
- //记得引用头文件
- #include<stdio.h>
- #include<stdlib.h> //srand函数的头文件
- #include<time.h> //time函数的头文件
-
- int main()
- {
- srand((unsigned int)time(NULL));
- int input = 0;
- do {
- menu();
- printf("请输入->");
- scanf("%d", &input);
-
- switch (input)
- {
- case 1:
- printf("开始游戏\n");
- game();
- break;
- case 0:
- printf("退出游戏\n");
- break;
- default:
- printf("输错了,请重新输入\n");
- break;
- }
- } while (input);
- return 0;
- }
-
这样就能实现随机布置雷:
首先玩家排查雷需要在盘面中的合法位置,如果排查位置在盘外或者排查的位置已被占用,我们需要给出相应的提示。然后玩家给出的是盘面的坐标位置,因为我们盘面坐标刚好和数组位置对应,所以可以不用再进行操作。我们封装一个函数,在game函数中调用来实现该功能。
并且在排查的过程中,可能出现以下几种情况:1、这个坐标不是雷,提示周围有几个雷
2、这个坐标是雷,游戏结束
3、所有非雷位置都找到了,游戏胜利
如果找到的坐标位置为非雷,那么我们就需要继续排查,所以我们将排查过程放到循环中进行,踩到雷或者排查结束才跳出循环。
所以我们可以通过以下代码来实现功以上功能:
- //数周围有几个雷
- int GetMineCount(char mine[ROWS][COLS], int x, int y)
- {
- return (mine[x - 1][y - 1] +
- mine[x][y - 1] +
- mine[x + 1][y - 1] +
- mine[x + 1][y] +
- mine[x + 1][y + 1] +
- mine[x][y + 1] +
- mine[x - 1][y + 1] +
- mine[x - 1][y]) - (8 * '0');
- }
然后在game函数中调用,实现函数功能。
当踩到雷时,我们给出相应提示后直接跳出循环结束游戏即可。
我们可以设置一个整型变量,其大小为非雷的位置个数。如果成功排除一个雷就将其减一,将他作为循环的判断条件,当他减为0时刚好也能跳出循环,并给出相应提示表示排雷成功。
- //排查雷
- void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
- {
- int x = 0;
- int y = 0;
- int win = row * col - COUNT_EASY;
- while (win )
- {
- printf("请输入要排查的坐标->");
- scanf("%d %d", &x, &y);
- if (x >= 1 && x <= row && y >= 1 && y <= col)
- {
- if (mine[x][y] == '1')
- {
- printf("踩到雷啦!爆炸!\n");
- DisplayBoard(mine, row, col);
- break;
- }
- else if (show[x][y] != '*')
- {
- printf("排查过该坐标,请重新输入\n");
- }
- else if (mine[x][y] == '0')
- {
- int ret = 0;
- ret = GetMineCount(mine, x, y);
- show[x][y] = ret + '0';
-
- DisplayBoard(show, ROW, COL);
- win--;
- }
- }
- else
- {
- printf("输入坐标非法,请重新输入\n");
- }
- }
- //跳出循环有两种可能,一个是踩雷退出,一个是排雷完成退出
- //需要判断是不是排雷成功,然后给出提示
- if(win==0)
- printf("恭喜你,排雷成功! \n");
- }
-
- void game()
- {
- //为了方便,把两个数组定义成完全一样的
- char mine[ROWS][COLS] = { 0 };
- char show[ROWS][COLS] = { 0 };
-
- //初始化两个数组
- InitBoard(mine, ROWS, COLS, '0');
- InitBoard(show, ROWS, COLS, '*');
-
- //打印棋盘
- //DisplayBoard(mine, ROW, COL);
- //对应雷的数组不需要给玩家看
- DisplayBoard(show, ROW, COL);
-
- //布置雷
- Setmine(mine, ROW, COL);
- //DisplayBoard(mine, ROW, COL);
-
- //排查雷
- Findmine(mine, show, ROW, COL);
- }
将上面的代码汇总成一个完整的扫雷游戏:
- #include<stdio.h>
- #include<stdlib.h>
- #include<time.h>
-
- #define ROW 9
- #define COL 9
- #define ROWS 11
- #define COLS 11
-
- #define COUNT_EASY 10
- //简单版本有10个雷
-
- void menu()
- {
- printf("*********************************\n");
- printf("******* 扫雷小游戏 *********\n");
- printf("******* 1、play *********\n");
- printf("******* 0、exit *********\n");
- printf("*********************************\n");
- }
-
-
- //初始化数组
- void InitBoard(char board[ROWS][COLS], int rows, int cols, char ret)
- {
- int x = 0;
- int y = 0;
- for (x = 0; x < rows; x++)
- {
- for (y = 0; y < cols; y++)
- {
- board[x][y] = ret;
- }
- }
- }
-
-
- //打印棋盘
- void DisplayBoard(char board[ROWS][COLS], int row, int col)
- {
- int x = 0;
- int y = 0;
- printf("--------扫雷---------\n");
- for (x = 0; x <= row; x++)
- {
- printf(" %d", x);
- }
- printf("\n");
- for (x = 1; x <= row; x++)
- {
- printf(" %d", x);
- for (y = 1; y <= col; y++)
- {
- printf(" %c", board[x][y]);
- }
- printf("\n");
- }
- printf("---------------------\n");
- }
-
-
- //布置雷
- void Setmine(char board[ROWS][COLS], int row, int col)
- {
- int x = 0;
- int y = 0;
- int count = COUNT_EASY;
- while (count)
- {
- x = rand() % row + 1;
- y = rand() % col + 1;
- if (board[x][y] == '0')
- {
- board[x][y] = '1';
- count--;
- }
- }
- }
-
-
- //数周围有几个雷
- int GetMineCount(char mine[ROWS][COLS], int x, int y)
- {
- return (mine[x - 1][y - 1] +
- mine[x][y - 1] +
- mine[x + 1][y - 1] +
- mine[x + 1][y] +
- mine[x + 1][y + 1] +
- mine[x][y + 1] +
- mine[x - 1][y + 1] +
- mine[x - 1][y]) - (8 * '0');
- }
-
-
-
- //排查雷
- void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
- {
- int x = 0;
- int y = 0;
- int win = row * col - COUNT_EASY;
- while (win )
- {
- printf("请输入要排查的坐标->");
- scanf("%d %d", &x, &y);
- if (x >= 1 && x <= row && y >= 1 && y <= col)
- {
- if (mine[x][y] == '1')
- {
- printf("踩到雷啦!爆炸!\n");
- DisplayBoard(mine, row, col);
- break;
- }
- else if (show[x][y] != '*')
- {
- printf("排查过该坐标,请重新输入\n");
- }
- else if (mine[x][y] == '0')
- {
- int ret = 0;
- ret = GetMineCount(mine, x, y);
- show[x][y] = ret + '0';
-
- DisplayBoard(show, ROW, COL);
- win--;
- }
- }
- else
- {
- printf("输入坐标非法,请重新输入\n");
- }
- }
- if(win==0)
- printf("恭喜你,排雷成功! \n");
- }
-
-
-
-
- void game()
- {
- //为了方便,把两个数组定义成完全一样的
- char mine[ROWS][COLS] = { 0 };
- char show[ROWS][COLS] = { 0 };
- //初始化两个数组
- InitBoard(mine, ROWS, COLS, '0');
- InitBoard(show, ROWS, COLS, '*');
-
- //打印棋盘
- //DisplayBoard(mine, ROW, COL);
- //对应雷的数组不需要给玩家看
- DisplayBoard(show, ROW, COL);
-
- //布置雷
- Setmine(mine, ROW, COL);
- //DisplayBoard(mine, ROW, COL);
-
- //排查雷
- Findmine(mine, show, ROW, COL);
- }
-
-
- int main()
- {
- srand((unsigned int)time(NULL));
- int input = 0;
- do {
- menu();
- printf("请输入->");
- scanf("%d", &input);
-
- switch (input)
- {
- case 1:
- printf("开始游戏\n");
- game();
- break;
- case 0:
- printf("退出游戏\n");
- break;
- default:
- printf("输错了,请重新输入\n");
- break;
- }
- } while (input);
- return 0;
- }
大家也可以将其封装为多个文件看上去更简洁明了,我这里为了表达方便将其放在一个文件里。
以上就是 C语言基础:扫雷游戏的C语言实现(超详图解+源码)的全部内容啦,希望能对你有所帮助!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。