目录
设计
1.游戏功能
1.通过坐标判断,来进行扫雷
2.同时会在棋盘上显示周边的雷数量
3.雷的数量有10个
4.默认格子数为9*9
5.找到雷,游戏就会失败
6.排出了所有雷,即为成功。
2.设计思路
1.开始菜单
菜单的实现,可以通过设计一个自定义函数来完成,无需返回值。
具体的选择(比如玩游戏或者退出)可以在主函数中通过switch进行判断
2.游戏的过程
2.1棋盘
棋盘的构成有两部分,一个是11*11,一个是9*9的。9*9是实际打印给玩家看的。
之所以设计成两个,是因为扫雷过程中需要对周围一圈雷的数量进行计算,若只有9*9,实际操作中会超过数组的边界,造成错误。
2.2信息的存储
整个棋盘需要的数组,默认的棋盘;装有雷信息的棋盘;存储周围雷的数量;
但实际上默认的棋盘只会在游戏开始出现一次,因此:周围雷的数量可以在默认的棋盘上进行展示,从数组的角度,只需把雷的数量(变量)放在默认的棋盘上(数组),而不必额外创建数组。
设show数组为默认的棋盘(也是后面雷数量展示的),mine数组为布置的雷。
2.3数据类型的选择
具体的数据上,考虑到实际上有3种数据要记录,雷,非雷,雷的个数。
虽然在展示上(也就是数组上)已经省略到2个,但实际过程中还是要考虑到3种数据的不同。
如果只用数字来记录,会出现雷的数量与雷与非雷的标识冲突(比如相邻的两个坐标,一个坐标如果在展示了自身周围的雷数量后从0变成1(1也代表着雷),另一个坐标也要扫描,那么这时候就会出现把本不是雷的格子也识别成了雷)。
因此采用字符来表示,同时由于字符型也是可以进行计算的,因此不影响数量的记录
2.4文件结构
game.c文件:设计具体游戏的函数,一共5个自定义函数。
初始化棋盘的(将show数组和mine数组进行初始化,分别给定默认的信息‘0’‘*’)
打印棋盘的(每次输入坐标前打印show数组,用来提示游戏进度,失败后打印mine数组,展示本局游戏的雷信息)
布置雷的(主要是对mine数组进行赋值,用随机数来实现随机坐标含有雷。)
记录已确认输入的坐标周围一圈雷的数量的记录函数(这个函数不需要在头文件中额外声明,是作为被嵌套函数被接下来的扫雷函数嵌套,因为其展示是show数组中,实现需要在扫雷函数中实现)
扫雷函数(实现判断是否为雷,是雷的打印mine数组,不是雷的,根据记录函数的返回值,填入show数组,重新打印show数组)
game.h:头文件,主要是声明自定义函数和一些变量,比如行数和列数(因为用变量的话,后期修改难度也更加方便),雷的数量。
test.c:包含主函数的文件,是程序的主体部分。主要是菜单函数的定义,以及游戏函数的定义(主要是调用game.c文件中已设计好的函数),以及主函数的定义(确定游戏的流程)
代码实现
1.首先是game.h文件的内容:
#pragma once #include<stdio.h> #include<stdlib.h> #include<time.h> #define easy_count 10 //雷的数量 #define ROW 9 //棋盘真正的行数 #define COL 9 //棋盘真正的列数 #define ROWS ROW+2 //棋盘外一圈的行数 #define COLS COL+2 //棋盘外一圈的列数 void initboard(char board[ROWS][COLS], int rows , int cols, char set); //初始化整个(包括外面一圈)棋盘 void displayboard(char board[ROWS][COLS], int row, int col);//打印棋盘 void setmine(char board[ROWS][COLS], int row, int col);//设置雷 void findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col); //排雷
2.其次是game.c文件的内容:
2.1初始化棋盘的函数:
void initboard(char board[ROWS][COLS], int rows, int cols, char set) { int i = 0; for (i = 0; i < rows; i++) { int j = 0; for (j = 0; j < cols; j++) { board[i][j] = set;//set具体的值由主函数那边赋予,因为要考虑到mine数组和show数组 //都需要初始化 } } }
2.2打印棋盘的函数:
void displayboard(char board[ROWS][COLS], int row, int col) { int i = 0; printf("-----排雷游戏-----\n"); for (i = 0; i <= col; i++)//打印坐标轴的横坐标轴 { printf("%d ", i); } printf("\n"); for (i = 1; i <= row; i++) { printf("%d ", i);//打印坐标轴的纵坐标轴 int j = 0; for (j = 1; j <= col; j++)//打印棋盘内容 { printf("%c ",board[i][j]); } printf("\n"); } }
2.3布置雷的函数:
void setmine(char board[ROWS][COLS], int row, int col) { int count = easy_count;//将预设好的雷的数量赋值给count变量 while (count) { int x = rand() % row + 1; int y = rand() % col + 1; if (board[x][y] == '0') { board[x][y] = '1'; count--;//通过count变量的减少,当count=0也就是当雷布置数量达到预设好的后,就会结束循坏 } } }
2.4记录雷数量的函数:
int getminecount(char board[ROWS][COLS], int x, int y) { return (board[x - 1][y - 1] + board[x][y - 1] + board[x + 1][y - 1] + board[x - 1][y] + board[x + 1][y] + board[x - 1][y + 1] + board[x][y + 1] + board[x + 1][y + 1] - 8 * '0'); }//通过坐标的增减来取到周围一圈的格子存储的数,因为数组都是字符型, '0'的asc码是48,'1'的asc码是49, 所以一圈相加后,再减去8个48,多出来的部分就是雷的数量. //注意,这里的返回值类型是int整型
2.5扫雷函数:
void findmine(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 - easy_count)//满足条件说明还有不是雷的坐标没被输入 { printf("请输入要排查的坐标:"); scanf("%d %d", &x, &y); if (x >= 1 && x <= row && y >= 1 && y <= col)//限定坐标范围,因为数组的范围是11*11 //而实际棋盘应该是9*9 { if (mine[x][y] == '1') { printf("很遗憾,你被炸死了\n"); displayboard(mine,row,col);//失败后打印本局游戏雷的信息,也就是mine数组 break; } else { int count = getminecount(mine, x, y);//调用记录函数,赋予数量给 //count,但要注意的是记录函数的返回值是int整型,所以这里的count类型也是int show[x][y] = count + '0';//注意count存的是int整型,所以如果雷的 //数量是1,那么1+'0'是1+48,也就是整型1+字符'0'的asc码48 displayboard(show, row, col);//打印show数组现在的状态,也就是 //提示游戏进度 win++;//执行了上面的循坏体,也就是说输入的坐标不是雷,那win就要+1,推动游戏进度。 } } else { printf("坐标非法,重新输入\n"); } } if (win == row * col - easy_count)//当上面的循坏条件不满足后,就应当满足这里的条件 //也就是说已经找到了所有不是雷的坐标。游戏成功了。 { printf("恭喜你,排雷成功\n"); displayboard(mine, row, col);//游戏成功后,打印一次雷的信息,也就是mine数组 } }
3.最后是test.c文件:
1.菜单函数:
void menu() { printf("**************\n"); printf("****1.play****\n"); printf("****2.exit****\n"); printf("**************\n"); }
2.游戏函数:
void game() { char mine[ROWS][COLS];//存放雷的信息 char show[ROWS][COLS];//存放排出的雷 initboard(mine, ROWS, COLS, '0'); initboard(show, ROWS, COLS, '*'); displayboard(show, ROW, COL); setmine(mine, ROW, COL); findmine(mine, show, ROW, COL); }
3.主函数:
int main() { srand((unsigned int)time(NULL));//生成随机数种子 int input=0; do { menu();//弹出菜单 printf("请选择:"); scanf("%d", &input); switch (input) { case 1: game(); break; case 2: printf("退出游戏\n"); break; default: printf("选择错误,重新选择\n"); break; } } while (input); return 0 ; }
最后是扫雷的完整文件:
saolei2 · 孟新大人/c-xuexi - 码云 - 开源中国 (gitee.com)