带你快速实现C语言之扫雷(未优化版)
Posted Ls_rosy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了带你快速实现C语言之扫雷(未优化版)相关的知识,希望对你有一定的参考价值。
目录
一.游戏底层逻辑
要写出一款游戏,首先得要知道游戏的底层原理。
在扫雷这个游戏中,首先我们得要有一个雷盘,棋盘中要有N个雷,输入坐标后如果踩到雷,游戏结束。反之,则显示该坐标周围的雷数。
二.菜单
设计任何游戏都得有一个菜单方便用户选择,和三子棋一样,我们使用do while结构,让菜单不论什么情况都能打印一次。
int main()
srand((unsigned int)time(NULL)); //rand函数初始化
int p = 0;
do
menu();
printf("\\n请选择->");
scanf("%d", &p);
switch (p)
case 1:
game(); //选择1进入游戏,转到game函数
break;
case 0:
printf("\\n再见\\n"); //退出游戏
break;
default: //选择错误
printf("\\n选择错误,请重新选择\\n");
break;
while(p);
void menu()
printf("|---欢迎来到扫雷---|\\n");
printf("|------------------|\\n");
printf("|------1.play------|\\n");
printf("|------0.exit------|\\n");
printf("|------------------|\\n");
三. 游戏设计
1.雷盘设置.
这里要注意的是,如果使用1个棋盘,它又要负责设置雷,又要负责打印雷盘,又要负责标记已经扫过的雷,这显然会使得太过繁琐复杂。所以我们用两个雷盘,一个用于设置雷,一个用于展示雷盘。这里我们顺便把他初始化,第一个全部初始化为字符0,第二个全部初始化成字符*
然后,如果雷盘我们选择9*9的矩阵,但这里我们不能设置成9*9的数组,因为我们后续扫雷的会检查周围8个坐标的雷数,如果玩家刚好输入下标为9 9的坐标,去检查雷数的话会导致下标访问越界,所以这里我们把矩阵上下左右各自延展1,也就是设置成11*11的数组,这样就不会存在访问越界的问题了。
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define mine 10
void game()
char board[ROWS][COLS] = 0 ; //设置雷
char show[ROWS][COLS] = 0 ; //展示
init(board, ROWS, COLS,'0');
init(show, ROWS, COLS,'*');
void init(char board[ROWS][COLS], int r, int c, int set)
int i = 0;
int j = 0;
for (i = 0; i < r; i++)
for (j = 0; j < c; j++)
board[i][j] = set; //‘0’或者‘*’
2.打印雷盘.
初始化后,我们来检查检查是否完成,设计一个函数print打印,这里不需要把11*11的数组全部打印,因为我们玩家玩的是9*9的雷盘,只需要展示9*9的数组就好。
另外,为了帮助玩家更加直观的输入坐标,我们在第一行,第一列加上坐标。
void print(char board[ROWS][COLS], int r, int c)
int i = 0;
int j = 0;
//列标
for (j = 0; j <= c; j++)
printf("%d ", j);
printf("\\n");
//行标
for (i = 1; i <= r; i++)
printf("%d ", i);
for (j = 1; j <= c; j++)
printf("%c ", board[i][j]);
printf("\\n");
3.设置雷.
这里我们设置10颗雷,雷用字符‘1’表示,注意不是数字1。(后面会讲为什么用字符1)
随机生成使用rand函数,rand函数要使用srand初始化。
void set(char board[ROWS][COLS], int r, int c)
int count = mine;
while (count) // count为0跳出循环
int x = rand() % r + 1; //表示只在下标为1-9的地方生成
int y = rand() % c + 1; //表示只在下标为1-9的地方生成
if (board[x][y] == '0')
board[x][y] = '1';
count--; // 每成功生成一次count--
看看效果图
4.找雷.
找雷,玩家输入坐标得满足2个条件:1.该坐标在1-9之间。2.该坐标未被重复扫雷。
满足条件后,如果踩到了雷,游戏结束,否则,游戏继续。
而游戏继续中,我们要把该坐标附近8个坐标的雷数打印出来,所以又需要一个函数mine_num来计算。在这里用字符1的好处就体现出来了,我们先找8个坐标中有几个字符1,
假设找到了8个字符1 ,我们减去8*字符0,就得到了数字8。
所以我们要返回一个数字,就得用算出的字符1减去8*字符0,得到数字N返回给函数。
最后这个游戏不能一直进行,如果一直没踩到雷的话,它结束的条件应该是除了雷的所有格子被扫过了,即win=r*c-mine的时候游戏结束
void findmine(char board[ROWS][COLS], char show[ROWS][COLS], int r, int c)
int win = 0;
while (win<r*c-mine)
int x = 0;
int y = 0;
printf("\\n请输入坐标->");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= r && y >= 1 && y <= c)
if (show[x][y] == '*')
if (board[x][y] == '1')
printf("\\n恭喜你,踩到雷了,游戏失败\\n");
break;
else
int num = mine_num(board, x, y);
show[x][y] = num + '0';
win++;
else
printf("\\n该地已被排查\\n");
if (win == r * c - mine)
printf("\\nWIN\\n");
print(board, r, c);
break;
else
printf("坐标非法,请重新输入\\n");
print(show, r, c);
int mine_num(char board[ROWS][COLS], int x, int y)
return ((board[x - 1][y] + board[x - 1][y - 1] + 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');
四.总代码
1.game.h
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define mine 10
void menu();
void game();
//初始化棋盘
void init(char board[ROWS][COLS], int r,int c,int set);
//打印棋盘
void print(char board[ROW][COL], int r, int c);
//设置雷
void set(char board[ROWS][COLS], int r, int c);
//找雷
void findmine(char board[ROWS][COLS], char[ROWS][COLS], int r, int c);
2.game.c
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
void menu()
printf("|---欢迎来到扫雷---|\\n");
printf("|------------------|\\n");
printf("|------1.play------|\\n");
printf("|------0.exit------|\\n");
printf("|------------------|\\n");
void init(char board[ROWS][COLS], int r, int c,int set)
int i = 0;
int j = 0;
for (i = 0; i < r; i++)
for (j = 0; j < c; j++)
board[i][j] = set;
void print(char board[ROWS][COLS], int r, int c)
int i = 0;
int j = 0;
//列标
for (j = 0; j <= c; j++)
printf("%d ", j);
printf("\\n");
//行标
for (i = 1; i <= r; i++)
printf("%d ", i);
for (j = 1; j <= c; j++)
printf("%c ", board[i][j]);
printf("\\n");
void set(char board[ROWS][COLS], int r, int c)
int count = mine;
while (count)
int x = rand() % r + 1;
int y = rand() % c + 1;
if (board[x][y] == '0')
board[x][y] = '1';
count--;
int mine_num(char board[ROWS][COLS], int x, int y)
return ((board[x - 1][y] + board[x - 1][y - 1] + 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');
void findmine(char board[ROWS][COLS], char show[ROWS][COLS], int r, int c)
int win = 0;
while (win<ROW*COL-mine)
int x = 0;
int y = 0;
printf("\\n请输入坐标->");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= r && y >= 1 && y <= c)
if (show[x][y] == '*')
if (board[x][y] == '1')
printf("\\n恭喜你,踩到雷了,游戏失败\\n");
break;
else
int num = mine_num(board, x, y);
show[x][y] = num + '0';
win++;
else
printf("\\n该地已被排查\\n");
if (win == ROW * COL - mine)
printf("\\nWIN\\n");
print(board, r, c);
break;
else
printf("坐标非法,请重新输入\\n");
print(show, r, c);
3.test.c
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
void game()
char board[ROWS][COLS] = 0 ;
char show[ROWS][COLS] = 0 ;
init(board, ROWS, COLS,'0');
init(show, ROWS, COLS,'*');
//print(board, ROW, COL);
print(show, ROW, COL);
set(board, ROW, COL);
print(board, ROW, COL);
findmine(board, show, ROW, COL);
int main()
srand((unsigned int)time(NULL));
int p = 0;
do
menu();
printf("\\n请选择->");
scanf("%d", &p);
switch (p)
case 1:
game();
break;
case 0:
printf("\\n再见\\n");
break;
default:
printf("\\n选择错误,请重新选择\\n");
break;
while(p);
扫雷游戏(C语言实现)初级版和优化版(增加了自动展开标记地雷功能,同时排除了第一次排到地雷的情况)
文章目录
一、初级版扫雷
1.1 游戏功能
初级版只具备最基础的两个功能:
1、显示当前输入坐标周围雷的数目
2、排雷错误,则游戏结束
3、当排除所有的非雷区域后,取得胜利
1.2 设计思路
我们以9*9的格子(我们称为棋盘)为例。
首先,我们需要两个数组,其中一个用来布置地雷的位置(这个数组不对玩家显示),另一个用来显示排雷的信息。
假设我们现在要统计坐标(1,1)和(3,4)周围雷的数目,坐标(3,4)需要统计周围8个位置是否有雷,坐标(1,1)只用统计周围三个位置是否有雷,在棋盘中,大多数格子都被8个格子所包围,而边界位置旁边有3或5个格子,如果分别进行判断的话,需要讨论多种情况,因此我们将棋盘扩大为11 *11。有效区域只有中间的9 *9部分,这样对于每一个位置,都是统计周围8个格子是否有雷。
运行效果:
在游戏开始前,我们打印一个游戏菜单供玩家进行选择,当玩家选择了开始游戏后,我们进入游戏模块。
void menu()
printf("**********************************************\\n");
printf("********请选择-> 1:开始游戏 0:结束游戏****\\n");
printf("**********************************************\\n");
int main()
int input = 0;
srand((unsigned int)time(NULL)); //初始化种子
do
menu(); //打印菜单
scanf("%d",&input);
switch (input)
case 1:
printf("扫雷游戏开始:\\n");
game();
break;
case 0:
printf("退出游戏\\n");
break;
default:
printf("输入错误,请重新输入\\n");
break;
while (input);
return 0;
当玩家选择开始游戏后,我们要先创建两个数组,并将其初始化。存放地雷的数组,先将其全部初始化为字符’0’;存放排雷信息的数组先全部初始化为字符 ’ * '。
游戏模块:
void game()
char Myboard[ROWS][COLS] = 0 ; //用来存放地雷
char ShowBoard[ROWS][COLS] = 0 ; //用来显示排雷的信息
InitBoard(Myboard, ROWS, COLS, '0'); //将地雷棋盘全部初始化为0
InitBoard(ShowBoard, ROWS, COLS, '*'); //将显示棋盘全部初始化为*
SetBoard(Myboard, ROW, COL); //布雷
PrintBoard(ShowBoard, ROWS, COLS); //打印棋盘
FindBoard(Myboard,ShowBoard, ROWS, COLS); //排雷
初始化模块:
void InitBoard(char board[ROWS][COLS], int row, int col, char c) //初始化棋盘
int i = 0, j = 0;
for (i = 0; i < row; i++)
for (j = 0; j < col; j++)
board[i][j] = c;
然后我们使用srand和rand函数随机布置地雷的位置(srand函数要放在主函数的循环体外)因为棋盘的有效区域只有中间的9 *9部分,因此我们要确保rand产生的随机数在1-9这个范围内。
void SetBoard(char board[ROWS][COLS], int row, int col) //布雷
for (int cnt = 0; cnt < COUNT;)
int x = rand() % row + 1; //随机产生横纵坐标
int y = rand() % col + 1;
if (board[x][y] == '0')
board[x][y] = '1';
cnt++;
当布置好雷之后,我们打印显示棋盘,在打印的同时打印上横纵序号,方便玩家确定坐标
void PrintBoard(char board[ROWS][COLS], int row, int col) //打印棋盘
printf(" ");
for (int i = 1; i < row - 1; i++) //打印列坐标
printf("%d ", i);
printf("\\n");
for (int i = 1; i < row - 1; i++)
printf("%d ", i); //打印横坐标
for (int j = 1; j < col - 1; j++)
printf("%c ", board[i][j]);
printf("\\n");
最后是游戏的核心部分:排雷
当玩家输入的坐标不是雷,统计周围8个位置雷的数目,可以用8个if语句或者循环语句来统计,此处我将每个位置的字符相加,最后减去8个’0’,也是雷的数目。
int Num(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';
//如果是雷,则对应的坐标位置是字符 '1',否则是字符'0',将周围八个位置的字符全部相加最后减去8个字符'0',就是周围雷的数目
//'1' - '0' = 1(数字1) '0' - '0' = 0(数字0)
void FindBoard(char board[ROWS][COLS], char ShowBoard[ROWS][COLS], int row, int col) //排雷
int x = 0;
int y = 0;
int cnt = ROW * COL - COUNT; //cnt表示非雷的数目,即棋盘大小减去地雷数
while (1)
printf("请输入坐标\\n");
scanf("%d%d", &x, &y);
if (x < 1 || x >row || y < 1 || y > col)
printf("坐标非法,请重新输入\\n");
else
if (board[x][y] == '1') //当前坐标位置是雷,游戏结束
printf("你失败了,游戏结束\\n");
PrintBoard(board, row, col);
break;
else if (board[x][y] == '0') //当前坐标不是雷,统计周围雷的数目
if (0 == Num(board, x, y)) //如果周围没有雷,则当其置为空
ShowBoard[x][y] = ' ';
else ShowBoard[x][y] = Num(board, x, y) + '0'; //周围有雷,将其置为雷的个数
//(因为我们打印的是字符型变量,因此要加上'0'才是所对应的数字字符)
cnt--; //每排完一个雷,非雷的数目减1
PrintBoard(ShowBoard, row, col); //打印当前显示棋盘的信息
if (cnt == 0)
printf("恭喜你,成功排雷\\n");
PrintBoard(board, row, col);
break;
我们将代码分别封装在main.c和game.c两个文件中,并在game.h头文件中对函数进行声明
main.c
#include"game.h"
void menu()
printf("**********************************************\\n");
printf("********请选择-> 1:开始游戏 0:结束游戏****\\n");
printf("**********************************************\\n");
void game()
char Myboard[ROWS][COLS] = 0 ; //用来存放地雷
char ShowBoard[ROWS][COLS] = 0 ; //用来显示排雷的信息
InitBoard(Myboard, ROWS, COLS, '0'); //将地雷棋盘全部初始化为0
InitBoard(ShowBoard, ROWS, COLS, '*'); //将显示棋盘全部初始化为*
SetBoard(Myboard, ROW, COL); //布雷
PrintBoard(ShowBoard, ROWS, COLS);
FindBoard(Myboard,ShowBoard, ROWS, COLS); //排雷
int main()
int input = 0;
srand((unsigned int)time(NULL)); //初始化种子
do
menu(); //打印菜单
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.c
void InitBoard(char board[ROWS][COLS], int row, int col, char c) //初始化棋盘
int i = 0, j = 0;
for (i = 0; i < row; i++)
for (j = 0; j < col; j++)
board[i][j] = c;
void PrintBoard(char board[ROWS][COLS], int row, int col) //打印棋盘
printf(" ");
for (int i = 1; i < row - 1; i++) //打印列坐标
printf("%d ", i);
printf("\\n");
for (int i = 1; i < row - 1; i++)
printf("%d ", i); //打印横坐标
for (int j = 1; j < col - 1; j++)
printf("%c ", board[i][j]);
printf("\\n");
void SetBoard(char board[ROWS][COLS], int row, int col) //布雷
for (int cnt = 0; cnt < COUNT;)
int x = rand() % row + 1; //随机产生横纵坐标
int y = rand() % col + 1;
if (board[x][y] == '0')
board[x][y] = '1';
cnt++;
int Num(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';
void FindBoard(char board[ROWS][COLS], char ShowBoard[ROWS][COLS], int row, int col) //排雷
int x = 0;
int y = 0;
int cnt = ROW * COL - COUNT; //cnt表示非雷的数目,即棋盘大小减去地雷数
while (1)
printf("请输入坐标\\n");
scanf("%d%d", &x, &y);
if (x < 1 || x >row || y < 1 || y > col)
printf("坐标非法,请重新输入\\n");
else
if (board[x][y] == '1') //当前坐标位置是雷,游戏结束
printf("你失败了,游戏结束\\n");
PrintBoard(board, row, col);
break;
else if (board[x][y] == '0') //当前坐标不是雷,统计周围雷的数目
if (0 == Num(board, x, y)) //如果周围没有雷,则当其置为空
ShowBoard[x][y] = ' ';
else ShowBoard[x][y] = Num(board, x, y) + '0'; //周围有雷,将其置为雷的个数
//(因为我们打印的是字符型变量,因此要加上'0'才是所对应的数字字符)
cnt--; //每排完一个雷,非雷的数目减1
PrintBoard(ShowBoard, row, col); //打印当前显示棋盘的信息
if (cnt == 0) //所有非雷位置均排查完
printf("恭喜你,成功排雷\\n");
PrintBoard(board, row, col);
break;
二、优化版扫雷
2.1 优化功能
在初级版扫雷中,我们必须一个一个地将所有非雷位置全部排查完才能完成游戏的胜利,提示的信息特别少,并且如果运气不好,第一次就可能排到雷的位置。在优化版扫雷中,增加了自动展开、防止第一次就排到雷的情况同时增加了标记功能。
2.2 设计思路
1、展开功能
当输入一个坐标,如果它的周围没有雷,则将其周围不是雷的区域展开,如果它周围的格子周围也没有雷,则继续展开。
同时为了防止数组越界,在统计雷的数目函数里增加一个if语句来判断。同时为了记录在展开函数中,展开了多少个格子,我们将展开函数返回值设为int,用来记录展开了多少格子。
int Num(char board[ROWS][COLS],int x,int y) //统计当前位置周围有几个雷
if (x >= 1 && x <= ROW && y >= 1 && y <= COL) //防止数组越界
return board[x - 1][y - 1] + board[x - 1][y] + board[x - 1][y + 1] +
board[x][y - 1] + board[x][y + 1如何用C语言快速实现初级版扫雷(步骤详细)
扫雷游戏(C语言实现)初级版和优化版(增加了自动展开标记地雷功能,同时排除了第一次排到地雷的情况)