赞
踩
目录
扫雷大家应该都知道,翻开一个格子,显示的数字就是周围 8 格所含的雷数。例如,红色框框里的1周围8格就只有一个雷。
我们定义两个数组来实现,show数组存放玩家看到的棋盘,mine数组存放隐藏的雷盘
这两个数组搭配使用,就能计算某个位置周围的雷数,并且修改show数组来显示这个位置的雷数。
但是如果计算边缘格子周围的雷数时,数组会越界。
我们只要在周围留一圈就能解决这个问题
如下图所示,假设我们要玩 9x9 的大小,我们的数组大小就定义为 11x11
初始化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");
- }
- }
效果图:
随机布置雷,将mine中的 '0' 改为 '1'
- //随机布置雷,在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--;
- }
- }
- }
计算该坐标在mine中 周围 '1'的个数
- //获取一个格子周围的雷数
-
- 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)++;
- }
- }
这里定义了一个 win 来表示翻开的格子数,当翻开的格子数量 = 行 x 列 - 雷数 ===> 排雷成功。
- //玩家排查雷
-
- 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");
- }
- }
- //显示地雷位置,排雷成功或被炸死后 向玩家展示地雷位置
-
- 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); //打印
- }
游戏设置 10 行 ,10 列 ,15个雷
排雷成功
排雷失败
头文件 常量定义,函数声明
- #pragma once
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <time.h>
-
-
- //玩家看到的大小
- #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);
游戏测试文件
- #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;
- }
函数定义
- #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");
- }
- }
-
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。