扫雷C语言如何实现(含递归展开)
Posted 水瓶water_ping
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了扫雷C语言如何实现(含递归展开)相关的知识,希望对你有一定的参考价值。
目录
返回该坐标周围一圈8个坐标的雷的个数count_mine()
判断棋盘上还有多少个“雷”count_show_mine()
扫雷介绍
扫雷游戏就是要把所有非地雷的格子揭开即胜利,踩到地雷格子就算失败。 游戏主区域由很多个方格组成, 使用鼠标左键随机点击一个方格,方格即被打开并显示出方格中的数字,方格中数字则表示其周围的8个方格隐藏了几颗雷。
在C语言中我们用输入坐标的方式代替鼠标点击。
本文未介绍功能:(不是不想介绍,只是博主还未掌握能力,主要还是因为懒)
- 交互难度选择功能
- 标记雷功能
- 标记雷后选择坐标展开功能
实现思路
首先我们使用三个文件包含整个程序
- Mine.h
- Mine.c
- test.c
Mine.h头文件包含代码实现所需所有头文件及全局变量
Mine.c源文件包含代码实现的主要函数
test.c源文件负责测试代码
实现流程
- 打印交互菜单
- 初始化棋盘
- 布置雷
- 扫雷(递归展开)
- 判断胜利
- 胜利游戏结束,否则循环第4步
在定义棋盘的二维数组时我们需要定义两个数组;一个数组mine用来放置雷的位置(不显示),另一个数组show用来展示棋面!
代码分解
-
棋盘定义
//全局变量行和列
#define ROW 3
#define COL 3
//避免数组越界,在原有棋盘的基础上周围多一行和列
#define ROWS ROW+2
#define COLS COL+2
-
交互菜单menu()
//交互菜单
void menu()
printf("-----------------------\\n");
printf("------ 【扫雷】 ------\\n");
printf("------ 1.开始 ------\\n");
printf("------ 0.退出 ------\\n");
printf("-----------------------\\n");
-
初始化棋盘init_board()
这里我们把show棋盘初始化为 '*'
把mine棋盘初始化为 '0'
//初始化棋盘
void init_board(char board[ROWS][COLS], int row, int col, char ch)
int i = 0;
int j = 0;
for (i = 0; i < ROWS; i++)
for (j = 0; j < COLS; j++)
board[i][j] = ch;
-
打印棋盘display()
//打印棋盘
void display(char show[ROWS][COLS], int row, int col)
int i = 0;
int j = 0;
for (i = 0; i <= col; i++)
//打印列坐标
printf("%d ", i);
printf("\\n");
for (i = 1; i <= row; i++)
//打印行坐标
printf("%d ", i);
for (j = 1; j <= col; j++)
printf("%c ", show[i][j]);
printf("\\n");
printf("\\n");
-
布置雷set_mine()
//雷的数量
#define COUNT 1
//布置雷
void set_mine(char mine[ROWS][COLS], int row, int col)
int x = 0;
int y = 0;
int count = COUNT;
while (count)
//获取随机数在棋盘上生成雷('1')
x = rand() % row + 1;
y = rand() % col + 1;
if (mine[x][y] == '0')
mine[x][y] = '1';
count--;
-
返回该坐标周围一圈8个坐标的雷的个数count_mine()
注意这里函数的返回类型是 static
//返回该坐标周围一圈雷的个数
static count_mine(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';//ASCII值与数字字符相差'0'
-
递归展开super_open_mine()
递归展开条件:
- 该坐标处不是雷, != '1'
- 该坐标周围八个坐标没有雷,count = 0
- 该坐标没有被展开过,!= ' '
//递归展开
void super_open_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
//获取该坐标周围八个坐标雷数
int count = count_mine(mine, x, y);
if (count == 0 && show[x][y] != ' ')
show[x][y] = ' ';
if (x - 1 >= 0 && x <= ROW && y >= 0 && y <= COL && show[x - 1][y] == '*')
super_open_mine(mine, show, x - 1, y);
if (x + 1 >= 0 && x + 1 <= ROW && y >= 0 && y <= COL && show[x + 1][y] == '*')
super_open_mine(mine, show, x + 1, y);
if (x >= 0 && x <= ROW && y - 1 >= 0 && y - 1 <= COL && show[x][y - 1] == '*')
super_open_mine(mine, show, x, y - 1);
if (x >= 0 && x <= ROW && y + 1 >= 0 && y + 1 <= COL && show[x][y + 1] == '*')
super_open_mine(mine, show, x, y + 1);
else
show[x][y] = count + '0';
-
排查雷sweep_mine()
//排查雷
int sweep_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
int x = 0;
int y = 0;
int count = 0;
printf("请输入扫雷坐标(行.列):>");
scanf("%d.%d", &x, &y);
if ((x >= 1 && x <= row) && (y >= 1 && y <= col))
if (mine[x][y] == '1')
return 1;
else
super_open_mine(mine, show, x, y);
display(show, ROW, COL);
return 0;
else
printf("输入坐标非法,请重新输入!\\a\\n\\n");
return 0;
-
判断棋盘上还有多少个“雷”count_show_mine()
//判断棋盘上还有多少个“雷”
int count_show_mine(char show[ROWS][COLS], int row, int col)
int i = 0;
int j = 0;
int count = 0;
for (i = 1; i <= row; i++)
for (j = 1; j <=col; j++)
if (show[i][j] == '*')
count++;
return count;
-
游戏实现函数game()
//游戏实现函数
void game()
char mine[ROWS][COLS] = 0 ;
char show[ROWS][COLS] = 0 ;
init_board(mine, ROWS, COLS, '0');//mine初始化为'0'
init_board(show, ROWS, COLS, '*');//show初始化为'*'
set_mine(mine, ROW, COL);
//display(mine, ROW, COL);
display(show, ROW, COL);
while (1)
int ret = sweep_mine(mine, show, ROW, COL);
if (ret)
printf("\\n你被炸死了,游戏结束!\\n\\a");
display(mine, ROW, COL);
break;
int key = count_show_mine(show, ROW, COL);
if (key == COUNT)
printf("WIN!\\a\\n");
break;
-
测试函数test()
//测试函数
void test()
srand((unsigned int)time(NULL));
int choose = -1;
do
menu();
scanf("%d", &choose);
switch (choose)
case 1:
printf("\\n游戏开始:\\n");
game();
break;
case 0:
printf("游戏结束...\\n\\a");
break;
default:
printf("输入有误,请重新输入!\\n\\a");
break;
while (choose);
-
主调函数main()
//主调函数
int main(void)
test();
return 0;
代码总览
- Mine.h
#pragma once
#include <stdio.h>//printf(),scanf()函数头文件
#include <stdlib.h>//获取时间戳头文件
#include <time.h>//时间头文件
//全局变量行和列
#define ROW 3
#define COL 3
//避免数组越界,在原有棋盘的基础上周围多一行和列
#define ROWS ROW+2
#define COLS COL+2
//雷的数量
#define COUNT 1
//函数声明
void menu();
void init_board();
void display();
void set_mine();
int sweep_mine();
- Mine.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "Mine.h"
//交互菜单
void menu()
printf("-----------------------\\n");
printf("------ 【扫雷】 ------\\n");
printf("------ 1.开始 ------\\n");
printf("------ 0.退出 ------\\n");
printf("-----------------------\\n");
//初始化棋盘
void init_board(char board[ROWS][COLS], int row, int col, char ch)
int i = 0;
int j = 0;
for (i = 0; i < ROWS; i++)
for (j = 0; j < COLS; j++)
board[i][j] = ch;
//打印棋盘
void display(char show[ROWS][COLS], int row, int col)
int i = 0;
int j = 0;
for (i = 0; i <= col; i++)
//打印列坐标
printf("%d ", i);
printf("\\n");
for (i = 1; i <= row; i++)
//打印行坐标
printf("%d ", i);
for (j = 1; j <= col; j++)
printf("%c ", show[i][j]);
printf("\\n");
printf("\\n");
//布置雷
void set_mine(char mine[ROWS][COLS], int row, int col)
int x = 0;
int y = 0;
int count = COUNT;
while (count)
//获取随机数在棋盘上生成雷('1')
x = rand() % row + 1;
y = rand() % col + 1;
if (mine[x][y] == '0')
mine[x][y] = '1';
count--;
//返回该坐标周围一圈雷的个数
static count_mine(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';//ASCII值与数字字符相差'0'
//递归展开
void super_open_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
int count = count_mine(mine, x, y);
if (count == 0 && show[x][y] != ' ')
show[x][y] = ' ';
if (x - 1 >= 0 && x <= ROW && y >= 0 && y <= COL && show[x - 1][y] == '*')
super_open_mine(mine, show, x - 1, y);
if (x + 1 >= 0 && x + 1 <= ROW && y >= 0 && y <= COL && show[x + 1][y] == '*')
super_open_mine(mine, show, x + 1, y);
if (x >= 0 && x <= ROW && y - 1 >= 0 && y - 1 <= COL && show[x][y - 1] == '*')
super_open_mine(mine, show, x, y - 1);
if (x >= 0 && x <= ROW && y + 1 >= 0 && y + 1 <= COL && show[x][y + 1] == '*')
super_open_mine(mine, show, x, y + 1);
else
show[x][y] = count + '0';
//排查雷
int sweep_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
int x = 0;
int y = 0;
int count = 0;
printf("请输入扫雷坐标(行.列):>");
scanf("%d.%d", &x, &y);
if ((x >= 1 && x <= row) && (y >= 1 && y <= col))
if (mine[x][y] == '1')
return 1;
else
super_open_mine(mine, show, x, y);
display(show, ROW, COL);
return 0;
else
printf("输入坐标非法,请重新输入!\\a\\n\\n");
return 0;
//判断棋盘上还有多少个“雷”
int count_show_mine(char show[ROWS][COLS], int row, int col)
int i = 0;
int j = 0;
int count = 0;
for (i = 1; i <= row; i++)
for (j = 1; j <=col; j++)
if (show[i][j] == '*')
count++;
return count;
- test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "Mine.h"
//游戏实现函数
void game()
char mine[ROWS][COLS] = 0 ;
char show[ROWS][COLS] = 0 ;
init_board(mine, ROWS, COLS, '0');
init_board(show, ROWS, COLS, '*');
set_mine(mine, ROW, COL);
//display(mine, ROW, COL);
display(show, ROW, COL);
while (1)
int ret = sweep_mine(mine, show, ROW, COL);
if (ret)
printf("\\n你被炸死了,游戏结束!\\n\\a");
display(mine, ROW, COL);
break;
int key = count_show_mine(show, ROW, COL);
if (key == COUNT)
printf("WIN!\\a\\n");
break;
//测试函数
void test()
srand((unsigned int)time(NULL));
int choose = -1;
do
menu();
scanf("%d", &choose);
switch (choose)
case 1:
printf("\\n游戏开始:\\n");
game();
break;
case 0:
printf("游戏结束...\\n\\a");
break;
default:
printf("输入有误,请重新输入!\\n\\a");
break;
while (choose);
//主调函数
int main(void)
test();
return 0;
以上是关于扫雷C语言如何实现(含递归展开)的主要内容,如果未能解决你的问题,请参考以下文章