C实现扫雷小游戏及bug解决方法

目录 分布详解1. 创建项目2. 总体代码设计3. 定义棋盘大小4.初始化棋盘5. 打印棋盘6. 布置雷7. 排查雷 代码汇总game.hgame.ctest.c 发现bug

分布详解

1. 创建项目

在源文件中创建test.c文件,对项目的相关功能进行测试。在头文件中创建game.h文件,对自定义函数进行函数声明。在源文件中创建game.c文件,对自定义函数进行函数定义。

2. 总体代码设计

test.c

#include <stdio.h> void menu() {printf("*********************************n");printf("********** 1. play *********n");printf("********** 0. exit *********n");printf("*********************************n"); } void game() { } int main() {int input = 0;do{menu();printf("请选择:>");scanf("%d", &input);switch (input){case 1:game();break;case 0:printf("退出游戏n");break;default:printf("选择错误,请重新选择:>n");break;}} while (input);return 0; }

123456789101112131415161718192021222324252627282930313233343536

3. 定义棋盘大小

image-20210814095931947

若定义成 9*9 的棋盘,则最外圈的排雷信息和内部的要分情况讨论,增加了代码的复杂性。

所以我们考虑将棋盘放大一圈,这样的话就能对棋盘内的所有位置做统一的处理。

除此之外,还要对有雷、无雷和所选区域周围是否有雷做相应的统计,而这些仅使用一个二维数组难以实现。

所以考虑定义两个二维数组,一个定义为mine用来存放布置雷的信息,有雷设为’1’,无雷设为’0’,另一个数组show,用来打印棋盘及展示所选区域周围是否有雷等信息。

在game.h函数中定义宏,提高代码的扩展性。

// 用于处理棋盘时做循环控制变量使用 #define ROW 9 #define COL 9 // 用于初始化棋盘 #define ROWS ROW+2 #define COLS COL+2 1234567

在test.c中进行定义

char mine[ROWS][COLS]; // 存放雷的信息 char show[ROWS][COLS]; // 存放排查出的雷的信息 12

4.初始化棋盘

mine默认初始化为’0’,show初始化为’ '(空格)。

由于两个棋盘要初始化的字符不同,我们用传参的形式将要初始化的字符传递给初始化函数。

在game.h中进行函数声明。

void InitBoard(char board[ROWS][COLS], int rows, int cols, char set); 1

在game.c中进行函数定义。

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;}} } 123456789101112

5. 打印棋盘

game.h

// 虽然没有打印最外边一圈的元素,但是传参的时候传的是mine数组,还是要传11*11的 void DisplayBoard(char board[ROWS][COLS], int row, int col); 12

game.c

void DisplayBoard(char board[ROWS][COLS], int row, int col) {int i = 0;for (i = 1; i <= row; i++){if (i == 1)printf(" %d ", i);elseprintf(" %d ", i);}printf("n");for (i = 0; i <= row; i++){if (i == 0)printf(" ");elseprintf("----");}printf("n");for (i = 1; i <= row; i++){int j = 0;printf("%d |", i);for (j = 1; j <= col; j++){printf(" %c |", board[i][j]);}printf("n");int m = 0;for (m = 0; m <= row; m++){if (m == 0)printf(" ");elseprintf("----");}printf("n");} }

12345678910111213141516171819202122232425262728293031323334353637383940

打印效果展示:

image-20210814100904471

6. 布置雷

这里要随机生成雷的坐标,需要用到rand函数,rand使用前要调用srand。

我们在 主函数中 do循环外面 调用srand( (unsigned)time( NULL ) ); 设置随机数的生成起点。

将随机生成的坐标内的值设为’1’,表示此处有雷。

game.h

void SetMine(char board[ROWS][COLS], int row, int col); 1

game.c

void SetMine(char board[ROWS][COLS], int row, int col) {int count = EASY_COUNT;while (count){// 1. 生成随机下标int x = rand() % row + 1;int y = rand() % col + 1;if (board[x][y] == '0'){board[x][y] = '1';count--;}} }

12345678910111213141516

将随机生成的雷打印出来,查看程序是否正确。打印效果如图所示:

image-20210814104851388

7. 排查雷

排查玩家输入的坐标是否有雷。

若输入坐标无雷,则统计该坐标周围八个坐标的雷数,并在这个坐标上显示出来。

game.h

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col); 1

game.c

int GetMineCount(char mine[ROWS][COLS], int x, int y) {return (mine[x - 1][y] +mine[x - 1][y - 1] +mine[x][y - 1] +mine[x + 1][y - 1] +mine[x + 1][y] +mine[x + 1][y + 1] +mine[x][y + 1] +mine[x - 1][y + 1] - 8 * '0'); } 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){if (mine[x][y] == '1'){printf("很遗憾,你被炸死了n");DisplayBoard(mine, ROW, COL);break;}else{int count = GetMineCount(mine, x, y);show[x][y] = count + '0';DisplayBoard(show, ROW, COL);win++;}}else{printf("坐标非法,请重新输入n");}}if (win == row * col - EASY_COUNT){printf("恭喜你排雷成功!!n");DisplayBoard(mine, ROW, COL);} }

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354

代码汇总

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 EASY_COUNT 10 // 初始化棋盘 void InitBoard(char board[ROWS][COLS], int rows, int cols, char set); // 打印棋盘 // 虽然没有打印最外边一圈的元素,但是传参的时候传的是mine数组还是要传11*11的 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);

1234567891011121314151617181920212223242526

game.c

#include "game.h" 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;}} } void DisplayBoard(char board[ROWS][COLS], int row, int col) {int i = 0;for (i = 1; i <= row; i++){if (i == 1)printf(" %d ", i);elseprintf(" %d ", i);}printf("n");for (i = 0; i <= row; i++){if (i == 0)printf(" ");elseprintf("----");}printf("n");for (i = 1; i <= row; i++){int j = 0;printf("%d |", i);for (j = 1; j <= col; j++){printf(" %c |", board[i][j]);}printf("n");int m = 0;for (m = 0; m <= row; m++){if (m == 0)printf(" ");elseprintf("----");}printf("n");} } void SetMine(char board[ROWS][COLS], int row, int col) {int count = EASY_COUNT;while (count){// 1. 生成随机下标int x = rand() % row + 1;int y = rand() % col + 1;if (board[x][y] == '0'){board[x][y] = '1';count--;}} } int GetMineCount(char mine[ROWS][COLS], int x, int y) {return (mine[x - 1][y] +mine[x - 1][y - 1] +mine[x][y - 1] +mine[x + 1][y - 1] +mine[x + 1][y] +mine[x + 1][y + 1] +mine[x][y + 1] +mine[x - 1][y + 1] - 8 * '0'); } 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){if (mine[x][y] == '1'){printf("很遗憾,你被炸死了n");DisplayBoard(mine, ROW, COL);break;}else{int count = GetMineCount(mine, x, y);show[x][y] = count + '0';DisplayBoard(show, ROW, COL);win++;}}else{printf("坐标非法,请重新输入n");}}if (win == row * col - EASY_COUNT){printf("恭喜你排雷成功!!n");DisplayBoard(mine, ROW, COL);} }

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127

test.c

#include "game.h" void menu() {printf("*********************************n");printf("********** 1. play *********n");printf("********** 0. exit *********n");printf("*********************************n"); } void game() {char mine[ROWS][COLS]; // 存放雷的信息char show[ROWS][COLS]; // 存放排查出的雷的信息// 将两个数组设定的一样大,是为了将两个数组一一对应// 初始化棋盘InitBoard(mine, ROWS, COLS, '0'); // 初始化为'0'InitBoard(show, ROWS, COLS, ' '); // 初始化为' ' -- 空格// 打印棋盘//DisplayBoard(mine, ROW, COL);DisplayBoard(show, ROW, COL);// 布置雷SetMine(mine, ROW, COL);//DisplayBoard(mine, ROW, COL);// 排查雷FindMine(mine, show, ROW, COL); } int main() {int input = 0;srand((unsigned)time(NULL));do{menu();printf("请选择:>");scanf("%d", &input);switch (input){case 1:game();break;case 0:printf("退出游戏n");break;default:printf("选择错误,请重新选择:>n");break;}} while (input);return 0; }

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556

发现bug

不知道大家有没有发现,在这个小游戏当中也存在着bug,当我们输入字符或者浮点数时,程序就会进入死循环。

那么这个问题要怎么解决呢?

经过一番查找,我发现bug是在scanf函数读取缓存区的时候产生的。

想要了解如何解决bug,可以访问这篇博客,带你解决scanf造成的死循环问题。

希望可以对大家有所帮助,如果有什么不对的地方,还烦请指教,谢谢!

相关知识

扫雷小游戏什么时候出 公测上线时间预告
异星探险家bug大全及解决方法
经典扫雷游戏下载大全2022 扫雷游戏下载合集
《王牌与冒险 Aces and Advantures 》无限洗牌bug解决方法介绍
必玩的单机经典版扫雷下载 最好玩的扫雷游戏有哪些2024
无期迷途扫雷怎么玩
扫雷益智扫雷好玩吗 扫雷益智扫雷玩法简介
《刺客信条:奥德赛》各种BUG汇总和解决方法
星光扫雷好玩吗 星光扫雷玩法简介
《无猜扫雷》可以借助高科技快速的完成扫雷要求

网址: C实现扫雷小游戏及bug解决方法 http://www.hyxgl.com/newsview329889.html

推荐资讯