C语言-扫雷
创始人
2024-05-09 03:38:28
0

文章目录

  • 完整扫雷
    • 1. 说明
    • 2. 思路
    • 3. 各个功能实现
      • 3.1 雷盘初始化与打印
        • 1)雷盘定义
        • 2) 随机布置雷
      • 3.2 玩家排查雷
        • 1) 获取坐标周围雷数
        • 2) 递归展开
        • 3)胜负判断
        • 3) 显示雷位置
    • 4. 游戏试玩
    • 5. 游戏完整代码
      • game.h
      • test.c
      • game.c

完整扫雷

请添加图片描述

1. 说明

扫雷大家应该都知道,翻开一个格子,显示的数字就是周围 8 格所含的雷数。例如,红色框框里的 1 周围 8 格就只有一个雷。

2. 思路

  1. 我们定义两个数组来实现,show 数组存放玩家看到的棋盘,mine 数组存放隐藏的雷盘

  2. 这两个数组搭配使用,就能计算某个位置周围的雷数,并且修改 show 数组来显示这个位置的雷数。

请添加图片描述

  1. 但是如果计算边缘格子周围的雷数时,数组会越界。

  2. 我们只要在周围留一圈就能解决这个问题

    • 如下图所示,假设我们要玩 9x9 的大小,我们的数组大小就定义为 11x11

请添加图片描述

3. 各个功能实现

3.1 雷盘初始化与打印

1)雷盘定义

请添加图片描述

请添加图片描述

  1. 初始化雷盘
  2. 初始化 show,mine 两个数组,show 存放 ‘*’ , mine 存放 ‘0’
void init_board(char board[ROWS][cols], int rows, int cols, char set)
{
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = set;
}
}
}
打印雷盘
//打印 show 雷盘void display_board(char board[ROWS][cols], int row, int col)
{
int i = 0;
int j = 0;//这里打印上面一行数字printf("|");for (j = 0; j <= col; j++){printf(" %-2d |", j);}printf("\n");for (i = 1; i <= row; i++){printf("|");for (j = 0; j <= col; j++){printf("----|");//打印两行之间的分割线}printf("\n");printf("|");printf(" %-2d |", i);//打印左边一列数字for (j = 1; j <= col; j++){printf(" %2c |",board[i][j]);//打印show数组}printf("\n");}}

效果图:

请添加图片描述

2) 随机布置雷

  1. 随机布置雷,将 mine 中的 ‘0’ 改为 ‘1’

  2. 随机布置雷,在 mine 数组里随机设置 COUNT 个雷

void set_mine(char mine[ROWS][cols], int row, int col)
{
int count = COUNT;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;if (mine[x][y] == '0'){mine[x][y] = '1';  //地雷设置为 '1'count--;}}
}

3.2 玩家排查雷

1) 获取坐标周围雷数

1… 计算该坐标在 mine 中 周围 '1’的个数
2… 获取一个格子周围的雷数

int get_mine_count(char mine[ROWS][cols], int x, int y)
{
//mine 中存放的是字符'0' 和 '1'
return (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] +
mine[x + 1][y + 1] - 8 \* '0');
}

2) 递归展开

请添加图片描述

  1. 我们玩扫雷时,翻开一个格子会展开一片,如上图所示,翻开黑格子,展开紫色区域。
  2. 我们可以用递归来实现
  3. 当这个格子周围没雷时,显示空白,然后继续递归它周围的八个格子
  4. 有雷时,显示雷数,停止递归。
void expand(char mine[ROWS][cols], char show[ROWS][cols], int x, int y, int\* win)
{if (x >= 1 && x <= ROW && y >= 1 && y <= COL) //限制在棋盘内展开,防止越界{int count = get_mine_count(mine, x, y);//获取雷数if (count == 0) //四周没雷,进入递归展开{show[x][y] = ' ';//四周没雷的改为 空格  ' 'int i = 0;//向四周共8个位置递归for (i = x - 1; i <= x + 1; i++){int j = 0;for (j = y - 1; j <= y + 1; j++){//只对 '*' 进行展开,防止死循环if (show[i][j] == '*'){expand(mine, show, i, j, win);}}}}else   //四周有雷显示雷数{show[x][y] = count + '0';}//记录展开的数量(*win)++;}
}

3)胜负判断

  1. 这里定义了一个 win 来表示翻开的格子数,当翻开的格子数量 = 行 x 列 - 雷数 ===> 排雷成功。
  2. 玩家排查雷
void find_mine(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 - COUNT)//当翻开的格子数量 = 行 x 列 - 雷数 ===> 排雷成功{printf("请输入要排查的坐标:>");scanf("%d %d", &x, &y);//检查坐标是否越界if (x >= 1 && x <= row && y >= 1 && y <= col){//检查坐标是否排查过了if (show[x][y] == '*'){if (mine[x][y] == '1'){system("cls");show_mine(mine, show, row, col);printf("-----------很遗憾,你被炸死了-----------\n");break;}else{//展开expand(mine, show, x, y, &win);system("cls");//清屏display_board(show, row, col);printf("--------------还需翻开%d格--------------\n", row * col - COUNT - win);}}else{printf("该坐标已排查,请重新输入\n");}}else{printf("坐标非法,请重新输入\n");}}if (win == row* col - COUNT){system("cls");show_mine(mine, show, row, col);//展示地雷位置printf("------------恭喜你,排雷成功-----------\n");}}

3) 显示雷位置

显示地雷位置,排雷成功或被炸死后 向玩家展示地雷位置

void show_mine(char mine[ROWS][cols], char show[ROWS][cols], int row, int col)
{
int i = 0;
for (i = 1; i <= row; i++)
{
int j = 0;
for (j = 1; j <= COL; j++)
{
if (mine[i][j] == '1')
{
show[i][j] = '@'; //将地雷改成 '@'
}
}
}
display_board(show, row, col); //打印
}

4. 游戏试玩

  1. 游戏设置 10 行 ,10 列 ,15 个雷
游戏设置
开始菜单
开始排雷
排雷
  1. 排雷成功

请添加图片描述

  1. 排雷失败

请添加图片描述

5. 游戏完整代码

game.h

头文件 常量定义,函数声明

#pragma once#include 
#include 
#include //玩家看到的大小
#define ROW 10
#define COL 10//实际数组大小,防止越界
#define ROWS ROW+2
#define COLS COL+2#define COUNT 10//雷数//初始化棋盘
void init_board(char board[ROWS][cols], int rows, int cols, char set);//打印棋盘
void display_board(char board[ROWS][cols], int row, int col);//随机布置雷
void set_mine(char mine[ROWS][cols], int row, int col);//获取坐标周围地雷数
int get_mine_count(char mine[ROWS][cols], int x, int y);//显示地雷位置并打印
void show_mine(char mine[ROWS][cols], char show[ROWS][cols], int row, int col);//递归展开
void expand(char mine[ROWS][cols], char show[ROWS][cols], int x, int y, int\* win);//排查雷
void find_mine(char mine[ROWS][cols],char show[ROWS][cols],int row, int col);

test.c

游戏测试文件

#define \_CRT_SECURE_NO_WARNINGS 1#include "game.h"//菜单
void menu()
{
printf("======================\n");
printf("|| 扫雷 ||\n");
printf("|| 1-开始游戏 ||\n");
printf("|| 0-退出游戏 ||\n");
printf("======================\n");
}//游戏流程
void game()
{
char mine[ROWS][cols] = { 0 };//存放布置的雷(隐藏的)
char show[ROWS][cols] = { 0 };//存放排查的雷(游戏看到的)//初始化棋盘//mine 全为'0'//show 全为'*'init_board(mine, ROWS, COLS, '0');init_board(show, ROWS, COLS, '*');//随机布置雷set_mine(mine,ROW,COL);//打印棋盘//display_board(mine, ROW, COL);display_board(show, ROW, COL);printf("--------------需要翻开%d格--------------\n", ROW * COL - COUNT);//排查雷(游戏开始)find_mine(mine, show, ROW, COL);}int main()
{
int input = 0;
srand((unsigned int)time(NULL));do{menu();printf("请选择:>");scanf("%d", &input);switch (input){case 1:system("cls");game();break;case 0:printf("退出游戏\n");break;default:printf("选择错误,请重新输入\n");break;}} while (input);return 0;}

game.c

函数定义

#define \_CRT_SECURE_NO_WARNINGS 1#include "game.h"//将两个数组初始化,show 全为'\*' ,mine 全为'0'void init_board(char board[ROWS][cols], int rows, int cols, char set)
{
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = set;
}
}
}//打印 show 棋盘void display_board(char board[ROWS][cols], int row, int col)
{
int i = 0;
int j = 0;//这里打印上面一行数字printf("|");for (j = 0; j <= col; j++){printf(" %-2d |", j);}printf("\n");for (i = 1; i <= row; i++){printf("|");for (j = 0; j <= col; j++){printf("----|");//打印两行之间的分割线}printf("\n");printf("|");printf(" %-2d |", i);//打印左边一列数字for (j = 1; j <= col; j++){printf(" %2c |",board[i][j]);//打印show数组}printf("\n");}}//随机设置雷,在 mine 数组里随机设置 COUNT 个雷void set_mine(char mine[ROWS][cols], int row, int col)
{
int count = COUNT;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;if (mine[x][y] == '0'){mine[x][y] = '1';  //地雷设置为 '1'count--;}}}//获取一个格子周围的雷数int get_mine_count(char mine[ROWS][cols], int x, int y)
{
//mine 中存放的是字符'0' 和 '1'
return (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] +
mine[x + 1][y + 1] - 8 \* '0');
}//递归展开void expand(char mine[ROWS][cols], char show[ROWS][cols], int x, int y, int\* win)
{if (x >= 1 && x <= ROW && y >= 1 && y <= COL) //限制在棋盘内展开,防止越界{int count = get_mine_count(mine, x, y);//获取雷数if (count == 0) //四周没雷,进入递归展开{show[x][y] = ' ';//四周没雷的改为 空格  ' 'int i = 0;//向四周共8个位置递归调用for (i = x - 1; i <= x + 1; i++){int j = 0;for (j = y - 1; j <= y + 1; j++){//只对 '*' 进行展开,防止死循环if (show[i][j] == '*'){expand(mine, show, i, j, win);}}}}else   //四周有雷显示雷数{show[x][y] = count + '0';}//记录展开的数量(*win)++;}}//显示地雷位置,排雷成功或被炸死后 向玩家展示地雷位置void show_mine(char mine[ROWS][cols], char show[ROWS][cols], int row, int col)
{
int i = 0;
for (i = 1; i <= row; i++)
{
int j = 0;
for (j = 1; j <= COL; j++)
{
if (mine[i][j] == '1')
{
show[i][j] = '@'; //将地雷改成 '@'
}
}
}
display_board(show, row, col); //打印
}//玩家排查雷void find_mine(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 - COUNT)//当翻开的格子数量 = 行 x 列 - 雷数 ===> 排雷成功{printf("请输入要排查的坐标:>");scanf("%d %d", &x, &y);//检查坐标是否越界if (x >= 1 && x <= row && y >= 1 && y <= col){//检查坐标是否排查过了if (show[x][y] == '*'){if (mine[x][y] == '1'){system("cls");show_mine(mine, show, row, col);printf("-----------很遗憾,你被炸死了-----------\n");break;}else{//展开expand(mine, show, x, y, &win);system("cls");//清屏display_board(show, row, col);printf("--------------还需翻开%d格--------------\n", row * col - COUNT - win);}}else{printf("该坐标已排查,请重新输入\n");}}else{printf("坐标非法,请重新输入\n");}}if (win == row* col - COUNT){system("cls");show_mine(mine, show, row, col);//展示地雷位置printf("------------恭喜你,排雷成功-----------\n");}}

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
客厅放八骏马摆件可以吗(家里摆... 今天给各位分享客厅放八骏马摆件可以吗的知识,其中也会对家里摆八骏马摆件好吗进行解释,如果能碰巧解决你...
苏州离哪个飞机场近(苏州离哪个... 本篇文章极速百科小编给大家谈谈苏州离哪个飞机场近,以及苏州离哪个飞机场近点对应的知识点,希望对各位有...