目录
一:介绍
如今游戏发展突飞猛进,我们也总能够在网上玩到各种各样的小游戏,回想当初我接触到的第一款游戏就是最经典的扫雷啦,既然是如此能让人勾起回忆的小游戏,那我们今天就来简易复刻一下当年的它,这次玩玩属于自己的扫雷。
二:简易介绍大致的思路
其实不难,如果我们随便去网上找一个扫雷的小游戏来玩我们可以看到它是给出了这样一个界面,上面有介绍到一共有多少个雷,并且点一个位置之后他会显示这个位置的周围8个位置有多少和雷
当我们看完扫雷的这个界面就大致知道我们需要一些上面东西了
1:一个棋盘用来存放雷,怎么存放雷
2:展示棋盘
3:第一个棋盘上布置雷
4:排查这些雷的位置
5:判断胜利和踩到了雷
梳理之后这就是我们大致的一些思路了,那么接下来我们就开始复刻我们的童年回忆吧。
三:棋盘的实现
(1):初始化棋盘,怎么存放雷
如果我们在去看一看这个扫雷的棋盘就会发现,它是一个就是一个9行9列的一个图形,那么这九行九列我们是不是就可以用一个二维数组来存放呢,如果如果说我们直接上手写一个九行九列的图形行不行呢,我们在看上面扫雷的要求,它是要满足当我排查了一个位置之后它会统计周围有多少个雷然后显示出来,如果我们写9*9的话,当我们排查第九行或者第九列的时候,它去统计周围八个位置有多少雷是不是就造成了数组越界,所以我们这里就给上一个11*11行的数组。
然后我们在去想,当我们排查出来这个位置上不是雷的时候怎么去区分这是我们的雷这又不是我们的雷呢。所以我们想到一个办法,用两个棋盘来区分,一个棋盘用来存放雷的位置(用1来表示雷,用0来表示不是雷),另一个用来显示我们排查出来的位置周围有多少雷。好了,棋盘大致思想完成了那么写代码也就很快了。为了方便区分我们这里采用多文件的方法来实现。我们所,用户玩一把之后觉得不过瘾可以再来一把,我们这里就用do-while来写,先给出一个菜单供玩家进行选着,如果是1就开始游玩,如果是0就退出游戏,既不是0也不是1我们就要提醒用户请输入有效的数字。
然后就开始我们棋盘的制作。先拿两个二维数组用来存放我们的棋盘,装雷的这个棋盘我们就说一开始我们都把它初始化成0,显示周围有多少雷的这个棋盘我们把它初始化成*。
既然两个都要初始化,那么我们就把它封装成一个函数,既然是函数肯定就会涉及到函数的传参,那我们就可以把数组的行和列定义成两个宏,这样后期我们无论是要对棋盘扩大缩小就不需要一个一个的去改对应的位置。
接下来我们再去思考,我们说既然要用两个棋盘,并且棋盘初始化一个是0一个是*,那是不是要写两个函数来初始化,其实这里是不用的,我们只需要在传参的时候把我们对应的棋盘需要初始化成什么样式当作参数一起传过去就可以了。当梳理清楚这些逻辑之后就可以开始着手写了,其实也很简单,二维数组嘛,我们只要用两个for循环,把数组的中的每一个元素初始化成我们需要的那个图形就可以了。
(2):展示棋盘
完成了棋盘的初始化,接下里就是对棋盘的展示。展示棋盘也很简单,用两个循环,把数组中的每一个元素打印出来就行了,但是值得注意的是,我们是只需要拿到一个9*9的棋盘,所以只需要打印九行九列就可以了,当然,为了方便用户能够快速的写出自己想排除的区域,我们可以在坐标的位置上写上对应的行列。当完成这样一些的操作之后就得到了我们需要的这两个棋盘。
四:第一个棋盘布置雷
当我们完成了棋盘接下来就可以开始在第一个棋盘里面放入雷了。那说要怎么去放雷呢,我们就可以用一个随机数,让这个随机数去决定我们每一次雷存放的位置。并且,在雷存放的时候有一种情况,就是说如果这个位置上已经有雷了的话我们就不能让它在这个位置继续存放,也就是说这里需要判断一下,只有当这个位置是‘0’的时候,雷才能放进去,那么我们这里也可以写一个宏来表示我们一共要存放多少个雷,当雷确实放进去之后,这个数就进行--操作,直到这个数为0的时候就代表雷已经被我们完全存放进去了。
五:排查雷的位置
雷也布置完了,接下来就可以开始对排查我们的雷了。首先想一下,怎么去排查一个雷呢,其实也很简单,我们只需要输入两个坐标,如果输入的这两个数是大于=1并且小于=9的有效坐标并且该坐标指向的位置还是字符0。那么就可以把这个位置改成安全的标志,关键在于,我们是要在排查的这个位置上显示周围八个坐标有多少个雷,如果有一个雷就显示1,有两个雷就显示2,其实要说的话也很简单,有的就会想到,把周围的八个坐标全部判断一下,如果不是字符0就++一下。那这样是不是太麻烦了,在会到我们最开始的时候,为什么说第一个棋盘用字符0和字符1来表示,而不用想第二个棋盘一样#这样的符号来表示呢。
其实想一想,字符0和数字0的ASCII码值是不一样的,字符的的ASCII是48,而数字0的ASCII是0,得到这样一个结论,我们是不是就可以想到如果要拿到1,2,3,4这样的数字是不是只需要用这个数字的字符减去字符0就能得到呢。
例如我们要拿到数字1
‘1‘ - ‘0’ == 49 - 48 = 1
这个1就是我们的数字1了。
有了这个想法,我就只需要把周围8个位置相加,然后在减去8*字符0,最后得到数就是周围有多少个雷的个数,再把这个值返回去,把这个值在放进我们拍雷的那个位置,是不是就刚好对应着周围8个位置有多少个雷的数了。
六:判断输赢和踩到雷
相对于前面这个是不是就显得很浅显易懂了。我们就可以用一个变量win来存放,这是一个九行九列的数组,那么里面的元素就是9*9=81个,用这个81减去开始我们安放雷的总数就得到了我们需要排查多少次就能把雷排查完全。那么我们就可以说,每次排查成功之后让win-1,当最后win==0的时候就表示所有的雷已经被排查出来,这个时候就可以给玩家一个提示告诉它赢得了胜利。
七:尾声
当我们写道这里的时候扫雷就已经算是大功高成了,其实只能算是一个简易版,因为我们去玩扫雷的时候,当我们点击一个位置,它会去判断如果周围8个位置都没有雷的时候它就会继续扩大,直到周围8个位置有雷的时候才停止,这里就不作过多讲解。如果小伙伴有兴趣的话可以自己去尝试怎么才能实现这样的效果。
八:代码
//头文件
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<string.h>
#include<math.h>
#include<time.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2 //方便后期对棋盘的改动
#define COLS COL+2
#define Mine_count 10 //从来表示一共要存放多少雷
//初始化棋盘
void Init_board(char board[ROWS][COLS], int row, int col, char set);
//打印棋盘
void Print_board(char board[ROWS][COLS], int row, int col);
//放置雷
void get_mine_count(char board[ROWS][COLS], int row, int col);
//排查雷的位置
void find_mine(char board[ROWS][COLS], char show[ROWS][COLS], int row, int col);
//实现函数文件
#include"game.h"
//初始化棋盘
void Init_board(char board[ROWS][COLS], int rows, int cols, char set)//set就是我们对应棋盘的那个标志
{
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = set; //把数组中的每一个元素初始化成对应的那个标志
}
}
}
void Print_board(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("--------------扫雷--------------\n");
printf(" ");
for (j = 1; j <= col; j++) //给用户提示当前这是第几列
{
printf("%d ", j);
}
printf("\n");
for(i = 1 ; i <= row ; i++) //i从1开始,因为我们只需要9*9的棋盘。
{
printf("%d ", i); //提示当前是第几行
for (j = 1 ; j <= col; j++) //同理j也从1开始
{
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("---------扫雷----------\n");
}
void get_mine_count(char board[ROWS][COLS],int row, int col)
{
int count = Mine_count;
while (count) //如果这个数是0的时候就表示雷放完了就跳出循环
{
int x = rand() % 9 + 1; //得到一个1-9的数字
int y = rand() % 9 + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
count--; //只有当雷确实放进去之后才对这个数进行--操作
}
}
}
int around_mine(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] //用周围八个坐标相加的值减去8*字符0就得到周围有几个雷的数字
+ board[x][y + 1] + board[x + 1][y - 1] + board[x + 1][y] + board[x + 1][y + 1] - '0' * 8;
}
void find_mine(char board[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int win = ROW * COL - Mine_count;
while (win)
{
printf("请输入扫雷的坐标:>\n");
scanf("%d %d", &x, &y);
int n = around_mine(board, x, y);
if (x >= 1 && x <= row && y >= 1 && y <= col) //判断用户输入是否是有效的坐标
{
if (show[x][y] != '*') //判断用户输入位置是否已经被排查,如果已经被排查就跳过下面的代码进行下一次输入
{
printf("该坐标已被排查\n");
Print_board(show, ROW, COL);
continue;
}
if (board[x][y] == '0') //判断输入的位置是否是安全区域
{
show[x][y] = (n + '0'); //如果是就把周围有多晒雷显示在这个位置
Print_board(show, ROW, COL);
win--;
}
else if (board[x][y] == '1') //如果是雷显示被炸死
{
printf("你被炸死了\n");
Print_board(board, ROW, COL);
break;
}
}
else
{
printf("坐标无效,请输入1-9的有效坐标\n");
}
}
if (win == 0)
{
printf("你赢了\n");
Print_board(show, ROW, COL);
}
}
//测试
#include"game.h"
void game()
{
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
Init_board(mine, ROWS, COLS,'0'); //'0' && '*'对应的就是我们棋盘初始化成什么
Init_board(show, ROWS, COLS,'*');
Print_board(mine, ROW, COL);
Print_board(show, ROW, COL);
get_mine_count(mine, ROW, COL);
//Print_board(mine, ROW, COL);
find_mine(mine,show, ROW, COL);
/*Print_board(show, ROW, COL);*/
}
void meun()
{
printf("********************************\n");
printf("******** 1:paly *********\n");
printf("******** 0:exit *********\n");
printf("********************************\n");
}
void test()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
meun();
printf("请选择:>\n");
scanf("%d", &input);
switch (input)
{
case 1: //如果用户输入1就表示开始游戏
game();
break;
case 0: //输入0就 退出游戏
printf("退出游戏\n");
break;
default: //既不是0也不是1就提醒用户输入正确的数
printf("输入错误,请重新输入\n");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}