游戏的分析
源代码在最后,需要的自取
扫雷游戏的规则:在棋盘上随机布置雷,玩家要盲选,选到的如果是雷,玩家就输掉比赛,如果不是雷,则显示周围有几颗雷。
对于布置雷,我们应该创建一个二维数组来存放雷的信息,不妨就char类型,字符零表示非雷,字符一表示雷。而随机的话就用rand函数到定。“周围有几颗雷”这一信息我们就再创建一个char类型的二维数组来存储。我们要注意的是:在设计二维数组的大小时,我们需要的是9*9的棋盘,但如果数组的大小设计成9*9的话,可能会造成越界,具体原因如下:我们要访问arr[0][1],如果不是雷,我们就要访问周围坐标,以此来判断周围有几个雷,如果我访问arr[0][1]左边的坐标,是不是就越界了呢?不妨把二维数组的大小设计成11*11的大小,这样访问时就不会越界。
实现游戏的话,我们吧代码分装到三个文件中。分别是game.h,game.c和test.c。game.h用于符号的声明和函数的定义。test.c用于游戏的逻辑。game.c用于扫雷游戏的具体实现。
游戏的框架
首先我们先打印一个菜单,让玩家选择玩不玩。所以我们要实现一个打印菜单的函数。函数名为meun,如图
如图所示我们设计了一个swile与while循环,如果玩家选择1,则进入游戏,如果玩家选择0则跳出循环,也就是退出游戏,如果玩家选择其他数字,则需要接着选择。
游戏的具体实现
如图所示,在创建二维数组的时候,用的不是数字,而是字母。这字母其实是一个自定义的符号,它定义在game.h的文件中(头文件)。为什么这样设计呢?这是因为如果我们将来要改棋盘大小或雷的个数时,只需要在头文件中把数字改掉就行,这样极大方便了我们后期的维护。
二维数组的初始化
然后是二维数组的初始化,这里我们要传四个参数,分别是:要初始化的函数,ROWS,COLS,以及要初始化成的字符,需要注意的是:我们要把整个数组初始化,所以传的是ROWS和COLS。 具体的设计如图
打印棋盘
然后是打印棋盘,这里只需两个for循环实现对行和列的打印并且再添加坐标的打印即可,具体实际如图
布置雷
接着就是在棋盘上布置雷了,这一步的和核心是生成随机数和取模。先用rand函数生成器伪随机数,再用srand函数改变种子,这其中要用time函数,具体操作图
种子设置在main函数里即可。这里要细说一下取模,我们需要的是1到9单位数字,而随机数模a,会生成0到a-1的数。这里我们模row(9),生成的随机数是0到8,所以只需在后面加1,就能生成1到9的数了。
排查雷
这里这里只需要用循环让用户不断地排查,我们只需设计好输赢的条件即可。值得我们注意的是在存放雷的函数中,我们的零是字符零 ,字符和数字的转换条件是:‘0’ + 数字 == 字符数字,例如:‘0’ + 4 = = ‘4’;
以下是源码
game.h
#pragma once #include<stdio.h> #include<stdlib.h> #include<time.h> //定义符号 #define ROW 9//行 #define COL 9//列 #define ROWS ROW+2 #define COLS COL+2 #define MINE 10 //布置几个雷 //定义函数 void InitializeBoard(char arr[ROWS][COLS], int rows, int cols, char set);//初始化棋盘 void PrinfBoard(char arr[ROWS][COLS], int row, int col); //打印棋盘 //布置雷 void SetMine(char arr[ROWS][COLS], int row,int col); //排查雷 void FindMine(char arrm[ROWS][COLS], char arra[ROWS][COLS], int row, int col);
game.c
#define _CRT_SECURE_NO_WARNINGS 1 #include"game.h" //初始化棋盘 void InitializeBoard(char arr[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++) { arr[i][j] = set; } } } void PrinfBoard(char arr[ROWS][COLS], int row, int col)//打印棋盘 { int i = 0; int j = 0; int c = 0; for (c = 0; c <= row; c++) { printf("%d ", c); } printf("\n"); for (i = 1; i <= row; i++) { printf("%d ", i); for (j = 1; j <= col; j++) { printf("%c ", arr[i][j]); } printf("\n"); } } //布置雷 void SetMine(char arr[ROWS][COLS], int row, int col) { int sum = MINE; while (sum) { int x = rand() % row + 1; int y = rand() % col + 1; if (arr[x][y] == '0') { arr[x][y] = '1'; sum--; } } return; } static int CheckMine(char arr1[ROWS][COLS], int a, int b) //数坐标周围的雷的函数 { return arr1[a - 1][b + 1] + arr1[a][b + 1] + arr1[a + 1][b + 1] + arr1[a - 1][b] + arr1[a + 1][b] + arr1[a - 1][b - 1] + arr1[a][b - 1] + arr1[a + 1][b - 1] - 8 * '0'; } //排查雷 void FindMine(char arrm[ROWS][COLS], char arra[ROWS][COLS], int row, int col) { int x = 0; int y = 0; int w = ROW * COL - MINE; //需要排查几次 while (w) { printf("请输入你要排查的目标:\n"); scanf("%d %d", &x, &y); if (x >= 1 && x <= 9 && y >= 1 && y <= 9) { if (arrm[x][y] == '1') { printf("很遗憾,你被炸死了\n"); break; } else { int se = CheckMine(arrm, x, y); arra[x][y] = se + '0'; w--; PrinfBoard(arra, ROW, COL); } } else printf("输入错误,请重新输入\n"); } if (0 == w) printf("恭喜你通关\n"); }
test.c
#define _CRT_SECURE_NO_WARNINGS 1 #include"game.h" void Game() { char mine[ROWS][COLS] = {0}; //存放布置雷的信息 char around[ROWS][COLS] = {0}; //存放排查后周围雷的信息 //初始化棋盘 InitializeBoard(mine, ROWS, COLS,'0'); InitializeBoard(around, ROWS, COLS, '*'); //打印棋盘 //PrinfBoard(mine, ROW, COL); PrinfBoard(around, ROW, COL); //布置雷 SetMine(mine, ROW,COL); //PrinfBoard(mine, ROW, COL); //排查雷 FindMine(mine, around, ROW, COL); } meun() { printf("**************************\n"); printf("******* i. play *******\n"); printf("******* 2. exit *******\n"); printf("**************************\n"); } int main() { srand( (unsigned int)time(NULL)); int a = 0; do { meun(); printf("请选择:\n"); scanf("%d", &a); switch (a) { case 1: Game(); break; case 0: printf("退出成功\n"); break; default: printf("输入错误,请重新输入:\n"); break; } } while (a); return 0; }