技术支持

为您提供7*24小时在线技术支持、安全技术专家、行业资深安全顾问服务。400-888-1688

服务器问题

您当前位置首页 > 技术支持 > 服务器问题

C语言-----扫雷游戏

C语言-----扫雷游戏

编程语言 · 技术分享

扫雷游戏的功能说明 : • 使⽤控制台实现经典的扫雷游戏 • 游戏可以通过菜单实现继续玩或者退出游戏 • 扫雷的棋盘是9*9的格⼦ • 默认随机布置10个雷 • 可以排查雷: ◦ 如果位置不是雷,就显⽰周围有⼏个雷 ◦ 如果位置是雷,就炸死游戏结束 ◦ 把除10个雷之外的所有⾮雷都找出来,排雷成功,游戏结束 test.c //⽂件中写游戏的测试逻辑 game.c //⽂件中写游戏中函数的实现等 game.h //⽂件中写游戏需要的数据类型和函数声明等 逻辑开始: 一、菜单 输入1进入游戏,输入0退出游戏,输入其他数字显示输入错误,并且重新输入 test.c #include "game.h" int main() { menu(); { regain: printf("请输入你的选择:"); int input1; scanf("%d", &input1); switch (input1) { case 1: { printf("进入游戏\n"); game(); break; } case 0: { printf("退出游戏\n"); break; } default: { printf("输入错误,请重新输入:"); goto regain; } } } return 0; } game.c #include "game.h" void menu() { printf("****************\n"); printf("**** 1.Play ****\n"); printf("**** 0.Quit ****\n"); printf("****************\n"); } game.h #pragma once #include <stdio.h> #include "game.h" //菜单 void menu(); 二、生成 9X9 的游戏界面 使用二维数组实现运用两个棋盘,一个用于展示,一个用于设置雷,写出初始化棋盘的函数将展示的棋盘char show全部初始化为 '*',将布置雷的棋盘char mine全部初始化为0为方便后边测试,可以先把打印棋盘的函数写出 test.c文件增加了以下代码 test.c #include "game.h" void game() { //用于布置雷的二维数组 char mine[ROWS][COLS] = { 0 }; //用于游戏界面的的二维数组 char show[ROWS][COLS] = { 0 }; //用于游戏界面的的二维数组全部初始为 '*' set_keyboard(show, ROWS, COLS, '*'); //用于布置雷的二维数组全部初始化为 '0' set_keyboard(mine, ROWS, COLS, '0'); //打印函数 printf_keyboard(show, ROW, COL); printf_keyboard(mine, ROW, COL); } game.c文件增加了以下代码 game.c #include "game.h" //初始化棋盘 void set_keyboard(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 printf_keyboard(char board[ROWS][COLS], int row, int col) { printf("-------扫雷--------\n"); for (int r = 0; r <= row; r++) { printf("%d ", r); } 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"); } } game.c文件增加了以下代码 #pragma once #include <stdio.h> #include "game.h" #define ROW 9 #define COL 9 #define ROWS ROW+3 #define COLS COL+2 //菜单 void menu(); //初始化棋盘 void set_keyboard(char board[ROWS][COLS], int rows, int cols, char set); //展示棋盘 void printf_keyboard(char board[ROWS][COLS], int row, int col); 三、随机布置雷 使用srand((unsigned int) time(NULL))和rand()将雷设置为1,雷只能布置在char mine[x][y] == '0'的地方 game.h文件增加了 #include <time.h> #include "stdlib.h" #define MINE 10 void set_mine(char board[ROWS][COLS], int row, int col, int mine); game.h #pragma once #include <stdio.h> #include "game.h" #include <time.h> #include "stdlib.h" #define ROW 9 #define COL 9 #define ROWS ROW+3 #define COLS COL+2 #define MINE 10 //菜单 void menu(); //初始化棋盘 void set_keyboard(char board[ROWS][COLS], int rows, int cols, char set); //展示棋盘 void printf_keyboard(char board[ROWS][COLS], int row, int col); //随机布置雷 void set_mine(char board[ROWS][COLS], int row, int col, int mine); game.c文件增加以下代码 game.c //随机布置雷 void set_mine(char board[ROWS][COLS], int row, int col, int mine) { srand((unsigned int) time(NULL)); while (mine) { int x = (rand() % row) + 1; int y = (rand() % col) + 1; if (board[x][y] == '0'); { board[x][y] = '1'; mine--; } } } test.c文件增加以下代码 test.c //随机布置雷 set_mine(mine, ROW, COL, MINE); 四、排雷 注意输入的坐标,横纵坐标都只能是0~9,出现其他数字报错,并重新输入所排的坐标要显示周围雷的个数,如果为0,展开周围的棋盘(运用到递归)如果所排的坐标是雷,显示游戏结束如果输入的坐标是已经输入过的坐标,显示该坐标已经排除判断游戏胜利,排除的坐标个数与减掉雷后的格子数相等 test.c文件布局改为以下情况 test.c void game() { //用于布置雷的二维数组 char mine[ROWS][COLS] = { 0 }; //用于游戏界面的的二维数组 char show[ROWS][COLS] = { 0 }; //用于游戏界面的的二维数组全部初始为 '*' set_keyboard(show, ROWS, COLS, '*'); //用于布置雷的二维数组全部初始化为 '0' set_keyboard(mine, ROWS, COLS, '0'); //随机布置雷 set_mine(mine, ROW, COL, MINE); //打印函数 printf_keyboard(show, ROW, COL); //printf_keyboard(mine, ROW, COL); //排雷 move_mine(show, mine, ROW, COL); } game.c文件增加了以下代码 game.c //计算周围雷的个数 int Count_mine(char mine[ROWS][COLS], int x, int y) { return mine[x][y] - '0'; } //展开棋盘----递归 void Open_keyboard(char show[ROWS][COLS], char mine[ROWS][COLS], int x, int y) { //写递归首先写结束条件 //越界时,返回 if ((x > (ROWS - 2)) || (x < 1) || (y > (COLS - 2)) || (y < 1)) { return; } //遇到以及排过雷的坐标返回 if (show[x][y] != '*') { return; } //计算雷的个数 int count = 0; for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { count += Count_mine(mine, x + i, y + j); } } show[x][y] = count + '0'; //按照游戏规则,如果坐标显示雷的数目不为零,则返回 if (show[x][y] != '0') { return; } //展开雷 for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { Open_keyboard(show, mine, x + i, y + j); } } } //排雷 void move_mine(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col) { int x, y; while (1) { printf("请输入要排查的坐标:"); regain2: scanf("%d %d", &x, &y); if ((x >= 1 && x <= 9) && (y >= 1 && y <= 9)) { if (show[x][y] == '*') { if (mine[x][y] == '0') { Open_keyboard(show,mine,x,y); printf_keyboard(show, ROW, COL); } else { printf("很遗憾,踩到雷了,游戏结束\n以下是雷的位置:"); printf_keyboard(mine, ROW, COL); break; } } else { printf("该坐标已经排查过了,请输入别的坐标:"); goto regain2; } } else { printf("输入错误,重新输入:"); goto regain2; } //判断赢 int Remove_mine_count = 0; for (int i = 1; i <= row; i++) { for (int j = 1; j <= col; j++) { if (show[i][j] != '*') { Remove_mine_count++; } } } if (Remove_mine_count == ((ROW * COL) - MINE)) { printf("恭喜你,排除所有的雷,游戏胜利\n"); printf_keyboard(mine, ROW, COL); break; } } } game.h文件的代码不变 game.h #pragma once #include <stdio.h> #include "game.h" #include <time.h> #include "stdlib.h" #define ROW 9 #define COL 9 #define ROWS ROW+3 #define COLS COL+2 #define MINE 10 //菜单 void menu(); //初始化棋盘 void set_keyboard(char board[ROWS][COLS], int rows, int cols, char set); //展示棋盘 void printf_keyboard(char board[ROWS][COLS], int row, int col); //随机布置雷 void set_mine(char board[ROWS][COLS], int row, int col, int mine); //排雷 void move_mine(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col); 五、扫雷游戏完整代码 test.c #include "game.h" // 包含扫雷游戏所需的头文件(声明函数、宏定义等) // 游戏核心逻辑函数,负责初始化游戏数据、布置雷、处理排雷过程 void game() { // 定义二维数组mine,用于存储雷的位置信息('1'表示有雷,'0'表示无雷) // ROWS和COLS是宏定义,通常比实际游戏区域大2(用于处理边界判断,避免越界) char mine[ROWS][COLS] = { 0 }; // 定义二维数组show,用于展示给玩家的界面(初始为'*',排雷后显示周围雷数或雷) char show[ROWS][COLS] = { 0 }; // 初始化show数组,全部元素设为'*'(表示未探索的格子) // set_keyboard是自定义函数,用于批量初始化二维数组 set_keyboard(show, ROWS, COLS, '*'); // 初始化mine数组,全部元素设为'0'(先默认所有格子无雷,后续再随机布置雷) set_keyboard(mine, ROWS, COLS, '0'); // 在mine数组中随机布置雷,MINE是宏定义(雷的总数) // ROW和COL是宏定义,代表实际游戏区域的行数和列数(比ROWS、COLS小2) set_mine(mine, ROW, COL, MINE); // 打印玩家界面(show数组),展示当前未探索的格子(全为'*') printf_keyboard(show, ROW, COL); // 调试用:打印雷的位置(mine数组),实际游戏中不会显示给玩家 // printf_keyboard(mine, ROW, COL); // 进入排雷逻辑,玩家输入坐标,处理排雷结果(显示周围雷数、踩雷结束等) move_mine(show, mine, ROW, COL); } // 主函数,程序入口,负责展示菜单和处理用户选择 int main() { menu(); // 调用menu函数,打印游戏菜单(如"1. 开始游戏 0. 退出游戏") { // 局部作用域,隔离内部变量 regain1: // 跳转标签,用于输入错误时重新回到输入步骤 printf("请输入你的选择:"); // 提示用户输入选项(1或0) int input1; // 存储用户输入的选项 scanf("%d", &input1); // 读取用户输入 // 根据用户输入的选项执行对应操作 switch (input1) { case 1: // 用户选择"开始游戏" { printf("进入游戏\n"); // 提示进入游戏 game(); // 调用game函数,启动扫雷游戏逻辑 break; // 退出switch分支 } case 0: // 用户选择"退出游戏" { printf("退出游戏\n"); // 提示退出游戏 break; // 退出switch分支 } default: // 用户输入了无效选项(非1和0) { printf("输入错误,请重新输入:"); // 提示输入错误 goto regain1; // 跳转到regain1标签,重新等待用户输入 } } } return 0; // 程序正常结束 } game.c #include "game.h" // 包含扫雷游戏所需的头文件(宏定义、函数声明等) // 打印游戏菜单 void menu() { printf("****************\n"); printf("**** 1.Play ****\n"); // 1表示开始游戏 printf("**** 0.Quit ****\n"); // 0表示退出游戏 printf("****************\n"); } // 初始化棋盘(二维数组) // board:要初始化的二维数组 // rows、cols:数组的行数和列数 // set:初始化填充的字符(如'*'或'0') void set_keyboard(char board[ROWS][COLS], int rows, int cols, char set) { // 遍历数组的每个元素,设置为指定字符set for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { board[i][j] = set; } } } // 展示棋盘(打印到控制台) // board:要展示的二维数组(玩家界面或雷区) // row、col:实际游戏区域的行数和列数(不包含边界) void printf_keyboard(char board[ROWS][COLS], int row, int col) { printf("-------扫雷--------\n"); // 打印列号(0到col),方便玩家定位坐标 for (int r = 0; r <= row; r++) { printf("%d ", r); } printf("\n"); // 打印每行内容(包含行号和对应格子的字符) for (int i = 1; i <= row; i++) { printf("%d ", i); // 打印行号(1到row) // 打印当前行的每个格子(从第1列到第col列) for (int j = 1; j <= col; j++) { printf("%c ", board[i][j]); } printf("\n"); // 每行结束后换行 } } // 随机布置雷到雷区数组 // board:存储雷区信息的二维数组('1'表示有雷,'0'表示无雷) // row、col:实际游戏区域的行数和列数 // mine:要布置的雷的总数 void set_mine(char board[ROWS][COLS], int row, int col, int mine) { srand((unsigned int)time(NULL)); // 初始化随机数种子,确保每次雷的位置不同 // 循环布置雷,直到雷的数量为0 while (mine) { // 生成1到row范围内的随机行坐标x int x = (rand() % row) + 1; // 生成1到col范围内的随机列坐标y int y = (rand() % col) + 1; // 如果当前位置没有雷(为'0'),则布置雷(设为'1') if (board[x][y] == '0') // 注意:原代码此处多了一个分号,可能是笔误,实际应去掉 { board[x][y] = '1'; mine--; // 雷的数量减1 } } } // 计算指定坐标周围8个方向的雷的总数 // mine:雷区数组 // x、y:要检查的坐标 int Count_mine(char mine[ROWS][COLS], int x, int y) { // 计算坐标(x,y)周围8个相邻格子中雷的总数 // 原理:将周围8个格子的字符值('0'表示无雷,'1'表示有雷)转换为数字后求和 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' // 减去8个'0'的ASCII值(将字符转为数字:'0'→0,'1'→1) ); } // 递归展开无雷区域(当某个格子周围无雷时,自动展开周围所有无雷格子) // show:玩家界面数组 // mine:雷区数组 // x、y:当前要展开的坐标 void Open_keyboard(char show[ROWS][COLS], char mine[ROWS][COLS], int x, int y) { // 递归结束条件1:坐标越界(超出实际游戏区域) if ((x > (ROWS - 2)) || (x < 1) || (y > (COLS - 2)) || (y < 1)) { return; } // 递归结束条件2:该坐标已被探索过(非'*') if (show[x][y] != '*') { return; } // 计算当前坐标周围8个方向的雷的总数 int count = 0; for (int i = -1; i <= 1; i++) // 行方向:-1(上)、0(当前)、1(下) { for (int j = -1; j <= 1; j++) // 列方向:-1(左)、0(当前)、1(右) { count += Count_mine(mine, x + i, y + j); // 累加周围每个格子的雷数 } } // 在玩家界面显示当前格子周围的雷数(字符形式,如'0'表示无雷) show[x][y] = count + '0'; // 递归结束条件3:如果周围有雷(count≠0),则停止展开 if (show[x][y] != '0') { return; } // 如果周围无雷(count=0),递归展开周围8个方向的格子 for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { Open_keyboard(show, mine, x + i, y + j); } } } // 排雷核心逻辑 // show:玩家界面数组 // mine:雷区数组 // row、col:实际游戏区域的行数和列数 void move_mine(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col) { int x, y; // 存储玩家输入的排查坐标 while (1) // 循环处理排雷操作,直到游戏结束 { printf("请输入要排查的坐标:"); regain2: // 跳转标签,用于输入错误时重新输入坐标 scanf("%d %d", &x, &y); // 读取玩家输入的坐标(x为行,y为列) // 检查坐标是否在有效范围内(1到row行,1到col列) if ((x >= 1 && x <= 9) && (y >= 1 && y <= 9)) // 假设row=col=9,可改为x<=row && y<=col { // 检查该坐标是否未被排查过(仍为'*') if (show[x][y] == '*') { // 如果该位置无雷(mine[x][y]为'0') if (mine[x][y] == '0') { Open_keyboard(show, mine, x, y); // 展开周围无雷区域 printf_keyboard(show, ROW, COL); // 刷新并显示玩家界面 } // 如果该位置有雷(mine[x][y]为'1') else { printf("很遗憾,踩到雷了,游戏结束\n以下是雷的位置:"); printf_keyboard(mine, ROW, COL); // 显示所有雷的位置 break; // 退出循环,游戏结束 } } // 该坐标已被排查过 else { printf("该坐标已经排查过了,请输入别的坐标:"); goto regain2; // 跳转到regain2,重新输入坐标 } } // 坐标输入无效(超出范围) else { printf("输入错误,重新输入:"); goto regain2; // 跳转到regain2,重新输入坐标 } // 判断玩家是否获胜(已排查所有非雷格子) int Remove_mine_count = 0; // 记录已排查的非雷格子数量 for (int i = 1; i <= row; i++) { for (int j = 1; j <= col; j++) { if (show[i][j] != '*') // 非'*'表示已排查 { Remove_mine_count++; } } } // 获胜条件:已排查的格子数 = 总格子数 - 雷的总数 if (Remove_mine_count == ((ROW * COL) - MINE)) { printf("恭喜你,排除所有的雷,游戏胜利\n"); printf_keyboard(mine, ROW, COL); // 显示所有雷的位置 break; // 退出循环,游戏结束 } } } game.h #pragma once // 防止头文件被重复包含(只编译一次) // 包含所需的标准库头文件 #include <stdio.h> // 提供输入输出函数(如printf、scanf) #include "game.h" // 包含游戏相关的其他声明(注意:此处可能存在循环包含,实际应避免) #include <time.h> // 提供时间相关函数(如time,用于初始化随机数种子) #include "stdlib.h" // 提供标准库函数(如rand、srand,用于生成随机数) // 宏定义:游戏核心参数 #define ROW 9 // 实际游戏区域的行数(9行) #define COL 9 // 实际游戏区域的列数(9列) #define ROWS ROW+3 // 雷区数组的总行数(比实际行数多3,用于处理边界,避免越界访问) #define COLS COL+2 // 雷区数组的总列数(比实际列数多2,用于处理边界) #define MINE 10 // 游戏中雷的总数(10个) // 函数声明:声明游戏中用到的所有函数(供其他文件调用) // 打印游戏菜单(如开始/退出选项) void menu(); // 初始化棋盘数组 // 参数:board-要初始化的二维数组,rows-数组行数,cols-数组列数,set-初始化填充的字符 void set_keyboard(char board[ROWS][COLS], int rows, int cols, char set); // 打印展示棋盘(玩家界面或雷区) // 参数:board-要展示的二维数组,row-实际游戏区域行数,col-实际游戏区域列数 void printf_keyboard(char board[ROWS][COLS], int row, int col); // 在雷区数组中随机布置雷 // 参数:board-雷区数组,row-实际游戏区域行数,col-实际游戏区域列数,mine-要布置的雷数 void set_mine(char board[ROWS][COLS], int row, int col, int mine); // 处理玩家的排雷操作(核心游戏逻辑) // 参数:show-玩家界面数组,mine-雷区数组,row-实际游戏区域行数,col-实际游戏区域列数 void move_mine(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col); 阅读完本文您可以尝试下面操作:

内容整理自CSDN博客,仅供技术交流参考。

这条帮助是否解决了您的问题? 已解决 未解决

安全合格的云服务,让您的业务轻松上云!

立即选购
https://affim.baidu.com/unique_50626027/chat?siteId=21806899&userId=50626027&siteToken=f4b13c0dda3b403b51fd8811d5a360c7