扫雷大多人都不陌生,是一个益智类的小游戏,那么我们能否用c语言来编写呢,
我们先来分析一下扫雷的运行逻辑,
首先,用户在进来时需要我们给与一个菜单,以供用户选择,
然后我们来完善一下,写出用户输入后对应要进行的内容,
game函数就是我们要写的扫雷的具体操作了,
首先我们来分析一下扫雷游戏的运行原理,
扫雷需要一个表格,可能是9*9,也可能是15*15,我们就拿9*9举例,
我们首先需要对这个9*9的表格进行埋雷,那用什么来代表我这个格子是不是雷呢,
我们可以用两个不同的字符来代替,我们假设’1‘为雷,’0‘没有雷,
转化为程序语言,表格我们用二维数组,埋雷用rand函数(rand函数在之前的文章中有讲述,没有学过的同学可以看一下,在“小游戏-猜数字”中)。
下面是我们的9*9棋盘,0代表还没有埋雷,
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
下面我们随即在其中埋几个雷,
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 |
0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 1 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
雷埋好了,我们就要开始排雷了,
假如用户点击这个格子,如果没有雷,我们显示周围八个格子中的雷的数量,有雷的话,我们结束游戏,并展示我们埋的雷的情况,
这个格子周围有两个雷,那么我们在这个格子显示为2,
下面,用户继续点击其他格子进行排雷,
这个格子改为1,这个时候就会发现问题
如果用户接下来选择红色格子怎么办,灰色格子是我们更改后的雷的数量,并不代表这里有雷,这里就出现歧义了,那么我们现在应该怎么办呢?我们可以另外开辟一个表格来存放用户扫雷得到的信息,
设置数组大小的时候我们要注意一个点,当用户点到边缘的格子时,周围就不是八个格子了,这时我们去访问就会有越界的情况出现,
那这个时候我们应该怎么办呢,
我们可以在外面再加一圈,变成11*11的表格,但是在埋雷和让用户选择的时候不使用最外层,
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
这个时候我们再去访问就不会有越界的情况了,而且在查雷的数量时,也不会有影响,
分析的差不多了,那么我们现在来把想法转换成代码,
我们新建两个文件,一个头文件,一个.c文件,我们声明两个变量放在.h头文件中,
那么我们想要在源.c中用的话就要在源.c中包含头文件#include“扫雷.h",同时我们设置出两个数组,
这里有疑问的朋友可以浏览一下我上面发布的那篇文章(文章标题:”在面对一个大型的代码,需要分文件编写的时候,应该怎么办呢;以及在编写出一个功能时,有人想要买这个功能,怎么在不给出源代码的情况下让买家可以使用这个代码功能呢?”),
下面我们开始埋雷,埋雷前,我们把两个数组初始化,下面的代码要注意都是写在了哪个文件中,
下面我将不再特意标明代码所处文件了,
初始化好后,我们开始随机埋雷,
雷布置完了,现在需要用户进行扫雷,但是扫之前,我们得让用户有选项来选择吧,我们把show棋盘打印给用户,
下面排查雷,
下面我们把游戏放到循环里,
下面我们把小错误改一下,并且完善一下我们的代码,
//源.c:
#define _CRT_SECURE_NO_WARNINGS 1#include "扫雷.h"void menu()
{printf("****************************\n");printf("******* 1 . play *******\n");printf("******* 0 . exit *******\n");printf("****************************\n");
}void game()
{char mine[ROWS][COLS] = { 0 };//存放布置好雷的信息char show[ROWS][COLS] = { 0 };//存放排查出来的雷的信息用于显示//初始化棋盘 让mine棋盘埋好雷,show棋盘显示*//初始化mine棋盘//InitMine(mine, ROWS, COLS);//InitMine(show, ROWS, COLS);//在上面的代码中多增加一个实参,用于说明要初始化的内容InitMine(mine, ROWS, COLS,'0');InitMine(show, ROWS, COLS,'*');//打印show棋盘//Print(show, ROW, COL);//观察代码是否有问题//布置雷DisPlayBoard(mine, ROW, COL);//Print(mine, ROW, COL);Print(show, ROW, COL);//排查雷FindMine(mine, show, ROW, COL);
}int main()
{int input = 0;srand((unsigned int)time(NULL));do{//菜单menu();printf("请选择:>");scanf("%d", &input);switch (input){case 1:printf("-------- 扫雷 --------\n");game();break;case 0:printf("退出游戏\n");break;default:printf("选择错误,请重新输入\n");break;}} while (input);
}
//扫雷.h:
#pragma once#include<stdio.h>#define EASY_COUNT 10//雷的数量#define ROW 9 //雷的行
#define COL 9 //雷的列//防止访问时越界
#define ROWS ROW+2
#define COLS COL+2 //棋盘初始化
void InitMine(char board[ROWS][COLS], int rows, int cols,char set);//打印棋盘
void Print(char board[ROWS][COLS], int row, int col);//布置雷
void DisPlayBoard(char board[ROWS][COLS], int row, int col);//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
//扫雷.c:
#define _CRT_SECURE_NO_WARNINGS 1#include"扫雷.h"//初始化mine棋盘均为字符‘0’
void InitMine(char board[ROWS][COLS], int rows, int cols,char set)
{for (int i = 0; i < rows; i++){for (int j = 0; j < cols; j++){board[i][j] = set;}}
}//打印棋盘
void Print(char board[ROWS][COLS], int row, int col)
{//打印列号for (int i = 0; i <= row; i++){printf("%d ", i);}printf("\n");for (int i = 1; i <= row; i++){printf("%d", i);//打印行号for (int j = 1; j <= col; j++){printf(" %c",board[i][j]);}printf("\n");}
}//布置雷
void DisPlayBoard(char board[ROWS][COLS], int row, int col)
{int x = 0, y = 0;//代表布置雷的横纵坐标for (int i = 1; i <= EASY_COUNT; i++){x = rand() % ROW + 1;y = rand() % COL + 1;if (board[x][y] == '1'){i--;}board[x][y] = '1';}
}//排查雷int Count(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]+ board[x][y + 1] + board[x + 1][y - 1]+ board[x + 1][y] + board[x + 1][y + 1]- 8 * '0'; //这里将字符转化为数值
}void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{//for (int i = 1; i <= row * col - EASY_COUNT; i++)int i = row * col - EASY_COUNT;while(i){printf("请输入要排查雷的坐标:>");int x = 0, y = 0;scanf("%d%d", &x, &y);if (x <= row && y <= col && x>=1 && y>=1){if (mine[x][y] == '1'){printf("很遗憾,你被炸死了\n");break;}else{//统计mine中这个坐标周围有几个雷int count = Count(mine, x, y);show[x][y] = count + '0';//转化为字符Print(show, ROW, COL);i--;}}else{printf("请输入正确的坐标\n");}}if (i == 0){printf("恭喜你!\n");}Print(mine, ROW, COL);
}