赞
踩
目录
扫雷游戏是我们这一代人小时候都会玩的游戏,那如何用C语言来实现一个简单的扫雷游戏呢?
让我们一起来逐步学习吧 ~
(1)游戏可以通过菜单实现继续玩或者退出游戏
(2)扫雷游戏的棋盘是9*9的格子
(3)默认随机布置10个雷
(4)可以排查雷
a.如果位置不是雷,就显示周围有几个雷
b.如果位置是雷,就炸死游戏结束
c.把除10个类之外的所有非雷都找出来,排雷成功,游戏结束
棋盘示例:
在进行扫雷游戏的设计时,应在同一项目下加入三个文件(如图):
首先,在test.c文件中完成游戏的测试逻辑。
为避免所有的指令全部位于主函数之内,可以采用函数调用,来使程序的内容整体更加清晰、明确。
确定头文件:
#include<stdio.h>
- int main()
- {
- test();//测试逻辑
- return 0;
- }
一般游戏的开始总会有菜单界面进行选择。
例如:“开始游戏”和“结束游戏”。用户通过选择“1”,“0”来开始或结束游戏。
该选择的实现可以通过switch循环语句实现
想多次进行游戏则可以通过do......while循环语句来实现:
- void test
- {
- do
- {
- menu();//menu为菜单界面
- } while ();
- }
此时进行修整后的菜单及选择界面的代码及运行结果如下:
- #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("请选择:>");
- scanf_s("%d", &input);//下一步识别1、0、其他数
- switch(input)
- {
- case 1:
- printf("扫雷\n");//输入值为 1 开始游戏
- break;
- case 0:
- printf("游戏结束,退出游戏\n");//输入值为 0 结束游戏
- break;
- default:
- printf("选择错误,重新选择\n");//输入其他数,重新进行选择
- }
- } while (input);//只有当输入值为 0 时才停止循环,否则将一直进行循环
- }
- int main()
- {
- test();
- return 0;
这样游戏的菜单界面就设计好啦~
那我们开始游戏的时候可就不能只打印“扫雷”两个字喽!要将它换成我们的游戏函数game()了
假设,对棋盘进行排查,则会发现
在排查(2,5)这个坐标时,我们访问周围的一圈八个黄色位置,统计周围雷的个数是1
在排查(8,6)这个坐标时,我们访问周围的一圈八个黄色位置,统计周围雷的个数时,最下面的三个坐标就会越界,为了避免越界的情况,我们在设计时应该给数组扩大一圈,而我们的雷仍应该布置在9*9的坐标上,即创建成11*11的区域。
(起始棋盘)
(优化后的棋盘)
从上面的棋盘中我们设定了:‘1’为雷 ‘0’为非雷 但当我们将雷排出时,原本‘0’所在的位置见会被改写成‘1’代表被排除,但此时将会与用‘1’代表的雷混淆。那么此时~聪明的我们肯定会想到解决的办法,那就是--设置两个数组,一组用来设置雷,一组用来排雷。如图:
时要对棋盘进行初始化,为了方便之后对游戏的拓展,我们还需要在game.h的头文件中设计:
- #pragma once
-
- #define ROW 9//行
- #define COL 9//列
-
- #define ROWS ROW+2
- #define COLS COL+2
此时要记得在文件test.c中声明我们自己的头文件,即:
#include "game.h"
要注意声明自己的头文件时不能使用<>要使用""
时利用文件game.c执行棋盘的初始化,此时,文件test.c中的game函数中应该如下
- void game()
- {
- char mine[ROWS][COLS] = { 0 };//数组全部初始化为'0'
- char show[ROWS][COLS] = { 0 };//数组全部初始化为'*'
- //初始化棋盘
- InitBoard(mine, ROWS, COLS, '0');
- InitBoard(show, ROWS, COLS, '*');
- }
此时的game.c文件中的InitBoard函数应该如下:
- #include"game.h"
-
- void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
- {
- int i = 0;
- for (i = 0; i < rows; i++)
- {
- int j = 0;
- for (j = 0; j < cols; j++)
- {
- board[i][j] = set;
- }
- }
- }
打印棋盘时主要是打印show函数中的棋盘,则在game.h文件中声明打印棋盘的函数,并在game.c文件中写入初步打印棋盘的函数。
- void DispiayBoard(char board[ROWS][COLS], int row, int col);
- //因为棋盘只用打印9*9棋盘,所以只用传输9行9列
- void DispiayBoard(char board[ROWS][COLS], int row, int col)
- {
- int i = 0;
- printf("---------扫雷游戏---------\n");//美化棋盘
- for (i = 0; i <= col; i++)
- {
- printf("%d ", i);
- }
- printf("\n");
- for (i = 1; i <= row; i++)
- {
- printf("%d ", i);
- int j = 0;
- for (j = 1; j <= col; j++)
- printf("%c ", board[i][j]);
- printf("\n");
- }
- }
此时的运行结果如图:
布置雷是在数组mine中布置的,这些雷在我们的游戏条件下是10个,而且是随机的,所以在test.c文件中的game函数中需要添加一个布置雷的函数SetMine并在game.c文件中确定函数。
因为要使用随机数所以在game.h文件中需要包含库函数:
#include<stdlib.h>
#include<time.h>
#define EASY_COUNT 10//确定雷的个数
- void SetMine(char board[ROWS][COLS], int row, int col)
- {
- int count = EASY_COUNT;//确定雷的个数
- while (count)
- {
- int x = rand() % row + 1;
- int y = rand() % col + 1;
- if (board[x][y] == '0')
- {
- board[x][y] = '1';
- count--;
- }
- }
- }
d.排除雷需要同时借助mine和show数组,构建函数FindMine进行排查。
如图 即为此处的排除雷的函数代码:
- int GetMineCount(char mine[ROWS][COLS], int x, int y)
- {
- return(mine[x - 1][y] +
- 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] -
- 8 * '0');
- }
-
- void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
- {
- int x = 0;
- int y = 0;
- int win = 0;//用来记录已经排除掉的坐标的个数,以便及时停止游戏
- while (win < row * col - EASY_COUNT)
- {
- printf("请输入要排查的坐标:>");
- scanf("%d %d", &x, &y);
- if (x >= 1 && x <= row && y >= 1 && y <= col)//判断坐标是否有效
- {
- if (mine[x][y] == '1')//判断是否是雷
- {
- printf("很遗憾,你被炸死了\n");
- DispiayBoard(mine, ROW, COL);
- break;
- }
- else
- {
- int count = GetMineCount(mine, x, y);//增加一个函数,用来计算输入的坐标周围八个位置中总共的雷的个数
- show[x][y] = count + '0';
- DispiayBoard(show, ROW, COL);//每排除一个便,打印一次此时的棋盘
- win++;//每排除一个便加一
- }
- }
- else
- {
- printf("坐标非法,重新输入\n");
- }
- }
- if (win == row * col - EASY_COUNT)//所有不是雷的坐标全部找到,结束游戏
- {
- printf("恭喜你,排雷成功\n");
- DispiayBoard(mine, ROW, COL);
- }
- }
此时所有的代码都已准备就绪:
- #pragma once
-
- #include<stdio.h>
- #include<stdlib.h>
- #include<time.h>
-
- #define ROW 9//行
- #define COL 9//列
-
- #define ROWS ROW+2
- #define COLS COL+2
-
- #define EASY_COUNT 10
- //初始化棋盘
- void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);
-
- //打印棋盘
- void DispiayBoard(char board[ROWS][COLS], int row, int col);
-
- //布置雷
- void SetMine(char board[ROWS][COLS], int row, int col);
-
- //排除雷
- void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
- #include"game.h"
-
- void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
- {
- int i = 0;
- for (i = 0; i < rows; i++)
- {
- int j = 0;
- for (j = 0; j < cols; j++)
- {
- board[i][j] = set;
- }
- }
- }
-
- void DispiayBoard(char board[ROWS][COLS], int row, int col)
- {
- int i = 0;
- printf("-------扫雷游戏-------\n");//美化棋盘
- for (i = 0; i <= col; i++)
- {
- printf("%d ", i);//打印列号
- }
- printf("\n");
- for (i = 1; i <= row; i++)
- {
- printf("%d ", i);//打印行号
- int j = 0;
- for (j = 1; j <= col; j++)
- printf("%c ", board[i][j]);//打印棋盘
- printf("\n");
- }
- }
-
- void SetMine(char board[ROWS][COLS], int row, int col)
- {
- int count = EASY_COUNT;
- while (count)//确保只有规定数量的雷
- {
- int x = rand() % row + 1;
- int 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] +
- 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] -
- 8 * '0');
- }
-
- void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
- {
- int x = 0;
- int y = 0;
- int win = 0;//用来记录已经排除掉的坐标的个数,以便及时停止游戏
- while (win < row * col - EASY_COUNT)
- {
- printf("请输入要排查的坐标:>");
- scanf("%d %d", &x, &y);
- if (x >= 1 && x <= row && y >= 1 && y <= col)//判断坐标是否有效
- {
- if (mine[x][y] == '1')//判断是否是雷
- {
- printf("很遗憾,你被炸死了\n");
- DispiayBoard(mine, ROW, COL);
- break;
- }
- else
- {
- int count = GetMineCount(mine, x, y);//增加一个函数,用来计算输入的坐标周围八个位置中总共的雷的个数
- show[x][y] = count + '0';
- DispiayBoard(show, ROW, COL);//每排除一个便,打印一次此时的棋盘
- win++;//每排除一个便加一
- }
- }
- else
- {
- printf("坐标非法,重新输入\n");
- }
- }
- if (win == row * col - EASY_COUNT)//所有不是雷的坐标全部找到,结束游戏
- {
- printf("恭喜你,排雷成功\n");
- DispiayBoard(mine, ROW, COL);
- }
- }
- #include"game.h"
-
- void menu()//仅用于打印菜单
- {
- printf("***************************\n");
- printf("******* 1. play *******\n");
- printf("******* 0. exit *******\n");
- printf("***************************\n");
- }
-
- void game()//完成扫雷游戏
- {
- char mine[ROWS][COLS] = { 0 };//数组全部初始化为'0'
- char show[ROWS][COLS] = { 0 };//数组全部初始化为'*'
-
- //初始化棋盘
- InitBoard(mine, ROWS, COLS, '0');
- InitBoard(show, ROWS, COLS, '*');
-
- //布置雷
- SetMine(mine, ROW, COL);//先布置雷,再打印雷更符合逻辑
-
- //打印棋盘
- DispiayBoard(show, ROW, COL);
-
- //排除雷
- FindMine(mine, show, ROW, COL);
- }
-
- void test()
- {
- int input = 0;
- srand((unsigned int)time(NULL));
- do
- {
- menu();
- printf("请选择:>");
- scanf("%d", &input);//下一步识别1、0、其他数
- switch(input)
- {
- case 1:
- printf("一共有十个雷,请找出");
- game();//输入值为 1 开始游戏
- break;
- case 0:
- printf("游戏结束,退出游戏\n");//输入值为 0 结束游戏
- break;
- default:
- printf("选择错误,重新选择\n");//输入其他数,重新进行选择
- }
- } while (input);//只有当输入值为 0 时才停止循环,否则将一直进行循环
- }
-
- int main()
- {
- test();
- return 0;
- }
此时一共有八十一个坐标,而实际上的雷只有十个,如果想要测试代码是否能正常运行到结束,需要,耗费很长时间,若中途游戏失败,还需要重新进行,所以我们要选用更便捷的方式来测试。即:
设置雷的个数为80个,此时只有一个位置不是雷,在进行排雷之前直接显示出雷的位置,即可测试是否可以顺利结束。
如图中的运行结果:
以上便是简易的扫雷游戏的代码设计过程,这只是最简易的,欢迎大家继续拓展呦~
如果代码有用,记得一键三连呦~
在线扫雷游戏:http://www.minesweeper.cn/
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。