扫雷的诞生其实源于1989年的时候,一位名叫Robert Donner为了锻炼自己的编程技术,写出的一个以“穿越雷区”为目的的小游戏,在经过一些细节的优化之后,就变成了现在家喻户晓的扫雷游戏。随后,随着计算机的普及,Windows95、98两代操作系统大获成功,免费赠送的扫雷游戏也一举成为了普及率最高的电脑游戏之一。然而,在扫雷红极一时的时候,却被国际反地雷组织盯上了,认为这样的游戏太过简化了扫雷工作的过程,是对扫雷工作及其工作人员的不尊重。于是微软公司最终上线了一款花田游戏,来代替原本的扫雷页面,但游戏的玩法都保持不变。然而,最终经过包装的扫雷游戏还是在国际反地雷组织的据理力争下被下线了,但是这个经典的windows扫雷游戏却早已成为一些人生活中的重要消遣途径。
今天我们就来简单还原一下这个游戏。
一.整体设计逻辑
我们用两个二维数组,mine[ROW][LIN],和show[ROW][LIN]分别用来表示雷盘,和显示盘。在雷盘中设置雷。在排雷是将排雷结果显示在存储到show[ROW][LIN]中,没排好一次就打印一次show[ROW][LIN]显示盘。直到每一颗没有雷的地方都被排查到。
二.加载逻辑
游戏的加载逻辑,我们希望可以选择游戏开始或者退出,也不是玩完一局就没有了,而是玩完一局以后还可以继续选择玩或者不玩,只有我们选组退出时,程序才会结束。还需要一个菜单可以显示选项。
加载逻辑代码:
int main() { int input = 0; do { mnue(); printf("请输入选项:>"); scanf("%d", &input); switch (input) { case 1: game(); break; case 0: printf("退出游戏\n"); break; default: printf("输入错误,请重新选择\n"); break; } } while (input); return 0; }
三.设置雷盘,和显示盘
宏定义雷盘和显示盘的行列
#pragma once #define _CRT_SECURE_NO_WARNINGS 1 //行 #define ROW 11 //列 #define LIN 11 //雷数 #define MINE_COUNT 10
这里定义两个二维数组,mine[ROW][LIN]初始化为‘0’,show[ROW][LIN]初始化为‘*’。并且打印雷盘和显示盘。
为了防止我们后面在排雷是需要查询九宫格,但是在边角的各自就会越界,所以我们直接11*11的雷盘,但是我们只是用1~9。就不会越界了。
void game() { //设置随机数生成器 srand((unsigned int)time(NULL)); //创建雷盘和显示盘 char mine[ROW][LIN] = { 0 }; char show[ROW][LIN] = { 0 }; //初始化雷盘和显示盘 init_board(mine, ROW, LIN,'0'); init_board(show, ROW, LIN,'*'); //打印显示盘 display_show(mine, ROW, LIN); printf("\n"); display_show(show, ROW, LIN); }
//初始化数组 void init_board(char board[ROW][LIN],int row,int lin,char set) { for (int i = 0; i < row; i++) { for (int j = 0; j < lin; j++) { board[i][j] = set; } } } // void display_show(char board[ROW][LIN], int row, int lin) { //打印行号 for (int i = 0; i <= lin-2; i++) { printf("%d ", i); } printf("\n"); //打印数组 //这里lin代表列但是11行,我们只用打印1~9。 for (int i = 1; i < row-1; i++) { //打印列号 printf("%d ", i); //这里lin代表列但是11行,我们只用打印1~9 for (int j = 1; j < lin-1; j++) { printf("%c ", board[i][j]); } printf("\n"); } }
运行展示:
四.设置雷
用随机数设置生成随机坐标,在1~9之间。
void set_mine(char board[ROW][LIN], int row, int lin) { for (int i = 0; i < MINE_COUNT; i++) { while (1) { //32767%10 //0----9 int x = rand() % 9+1; //1~9; int y = rand() % 9+1; //只有在坐标的位置是‘0’,才可以以,防止重复 if (board[x][y]=='0') { board[x][y] = '1'; break; } } } }
void game() { //设置随机数生成器 srand((unsigned int)time(NULL)); //创建雷盘和显示盘 char mine[ROW][LIN] = { 0 }; char show[ROW][LIN] = { 0 }; //初始化雷盘和显示盘 init_board(mine, ROW, LIN,'0'); init_board(show, ROW, LIN,'*'); 打印显示盘 //display_show(mine, ROW, LIN); //printf("\n"); //display_show(show, ROW, LIN); //布置雷 set_mine(mine, ROW, LIN); display_show(mine, ROW, LIN); printf("\n"); display_show(show, ROW, LIN); }
运行结果:
五.排雷
输入坐标,首先查看该坐标是不是雷,如果是游戏直接结束,如果不是就排查他周围的八个格子有几个雷,并将雷数写入显示盘。没排查一个各自计数win就加一,直到win ==(row - 2) * (lin - 2) - MINE_COUNT游戏结束,排雷成功。
//得到九宫格雷数 int get_mine(char mine[ROW][LIN], int x, int y) { int sum = 0; for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { //因为九宫没有类就是‘0’,有雷就是‘1’, //所以就直接加一起,因为字符1~9转换成数字要减去48。 sum += mine[x+i][y+j] - 48; } } return sum; } void find_mine(char mine[ROW][LIN],char show[ROW][LIN],int row,int lin) { int x = 0; int y = 0; int win = 0; while (win < (row - 2) * (lin - 2) - MINE_COUNT) { printf("请输入需要排查的坐标:>"); scanf("%d %d", &x, &y); //判断是否为雷 if (mine[x][y] == '0') { //判断是否被排查过 if (show[x][y] == '*') { int count = get_mine(mine, x, y); //数字转字符需要加48 show[x][y] = count + 48; display_show(show, ROW, LIN); win++; } else { printf("此处已经被排查\n"); } } else { printf("此处是雷,游戏结束!!!\n"); display_show(mine, ROW, LIN); return; } } if (win == (row - 2) * (lin - 2) - MINE_COUNT) { printf("排雷成功,游戏通关!!!\n"); } }
这里为了方便演示我设置80个雷,并且显示出来了,雷盘,大家在测试的时候可以显示出雷盘,以便测试,完成以后把打印雷盘就好了。
最后:
决定今天的不是今天,而是昨天对人生的态度;决定明天的不是明天,而是今天对事业的作为。我们的今天由过去决定,我们的明天由今天决定;制胜不凭体力靠智力,成功不靠奇迹靠轨迹。成功不在于是否拿到好牌,关键在于能否将手中的坏牌打好。人生最重要的是,知道自己要去往的方向。加油,诸君,山顶见!!!