C语言实现扫雷游戏的方法
作者:Jan_ssen
相信大家对扫雷一定都不陌生吧!但是你敢信仅仅使用一些C语言的初阶基础知识就能够制作一个扫雷简单小游戏?今天,我将带领大家一起走进扫雷,探究其基础算法奥秘。
一、基本思路
首先,既然是玩游戏,我们应该设计相应的菜单。
输入1后继续让玩家选择游戏难度:
我们在这里设计简单模式为6x6大小的面板,雷埋10个;中等模式为10x10大小的面板,雷埋30个;困难模式为14x14大小的面板,雷埋50个。
为了方便雷的布置与显示,我们设计了两张面板:show_board[ROW][COL]和mine_board[ROW][COL],其中show面板负责显示“空格”,mine面板负责记录周围雷的个数。
玩家通过输入每个格子所对应的坐标进行扫雷操作。
char** show_board = (char**)malloc(sizeof(char*) * (ROW + grade * 4));//二维数组动态内存分配 for (int i = 0; i < ROW + grade * 4; i++) { show_board[i] = (char*)malloc(sizeof(char) * (COL + grade * 4)); memset(show_board[i], ' ', (COL + grade * 4));//数组全部赋值为空格 } char** mine_board = (char**)malloc(sizeof(char*) * (ROW + grade * 4)); for (int i = 0; i < ROW + grade * 4; i++) { mine_board[i] = (char*)malloc(sizeof(char) * (COL + grade * 4)); memset(mine_board[i], '0', (COL + grade * 4));//数组全部赋值为‘0' }
二、代码实现
Step1.画图
想要进行扫雷游戏,首先应该有扫雷界面的设计,如下:
我们建立Showboard函数进行面板的基本绘制:
static void Showboard(char **board,int grade)//面板制作 { printf(" "); for (int i = 1; i <= ROW-2+4*grade; i++) { printf(" %3d", i); } printf("\n"); for (int i = 1; i <= ROW-2+4*grade; i++){ printf(" "); for (int k = 1; k <= COL-2+4*grade; k++) { printf("----"); } printf("\n"); printf("%2d|",i); for (int j = 1; j <= COL-2+4*grade; j++){ printf(" %c |",board[i][j]); } printf("\n"); } printf(" "); for (int k = 1; k <= COL-2+4*grade; k++) { printf("----"); } printf("\n"); }
成果图如下:
Step2. 埋雷
埋雷应做到一下几点:
1.展示面板show_board(这里传参后以形参board替代)赋值为1(BOOM宏定义为1) ;
2.为了提高用户体验,在被炸后能够展示出雷的位置,我们又建立了一个lei_board数组用来显示,并在埋雷时将对应位置赋值为'*';
3.埋雷要具有随机性,所以这里引用rand函数(主函数要种随机数种子);
static void SetMines(char **board,char **lei_board,int grade) { int i = 1; int x, y; while (i <= NUM+grade*20) { x = rand() % (ROW-2+4*grade) + 1; y = rand() % (COL-2+4*grade) + 1; if (board[x][y] != BOOM) { board[x][y] = BOOM; lei_board[x][y] = '*'; i++; } } }
Step3.计算周围雷的个数
当我们计算周围雷的个数时,自然而然地就会想到统计周围九宫格的雷的个数。如果要搜索的位置在面板中间,这很简单,但如果是以下这类情况,比如顶点格或者边格怎么办?如何知道该算哪个格?
为了避免这种特殊情况所带来的问题,我们不如直接在外面再套一圈,对于各类面板(即二维数组)的建立也直接按照增大的来,这样就无需讨论边角的特殊性了。
统计函数直接通过简单的函数返回来实现:
static int CountMine(char **board,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'; }
三、完整代码
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<time.h> #include<windows.h> #define BOOM '1' #define ROW 8 #define COL 8 #define NUM 10 static void SetMines(char **board,char **lei_board,int grade)//埋雷 { int i = 1; int x, y; while (i <= NUM+grade*20) { x = rand() % (ROW-2+4*grade) + 1; y = rand() % (COL-2+4*grade) + 1; if (board[x][y] != BOOM) { board[x][y] = BOOM; lei_board[x][y] = '*'; i++; } } } static void Showboard(char **board,int grade)//面板制作 { printf(" "); for (int i = 1; i <= ROW-2+4*grade; i++) { printf(" %3d", i); } printf("\n"); for (int i = 1; i <= ROW-2+4*grade; i++){ printf(" "); for (int k = 1; k <= COL-2+4*grade; k++) { printf("----"); } printf("\n"); printf("%2d|",i); for (int j = 1; j <= COL-2+4*grade; j++){ printf(" %c |",board[i][j]); } printf("\n"); } printf(" "); for (int k = 1; k <= COL-2+4*grade; k++) { printf("----"); } printf("\n"); } static int CountMine(char **board,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 Game(int grade)//游戏函数,grade为游戏难度等级 { char** show_board = (char**)malloc(sizeof(char*) * (ROW + grade * 4)); for (int i = 0; i < ROW + grade * 4; i++) { show_board[i] = (char*)malloc(sizeof(char) * (COL + grade * 4)); memset(show_board[i], ' ', (COL + grade * 4)); } char** mine_board = (char**)malloc(sizeof(char*) * (ROW + grade * 4)); for (int i = 0; i < ROW + grade * 4; i++) { mine_board[i] = (char*)malloc(sizeof(char) * (COL + grade * 4)); memset(mine_board[i], '0', (COL + grade * 4)); } char** lei_board = (char**)malloc(sizeof(char*) * (ROW + grade * 4)); for (int i = 0; i < ROW + grade * 4; i++) { lei_board[i] = (char*)malloc(sizeof(char) * (COL + grade * 4)); memset(lei_board[i], ' ', (COL + grade * 4)); } SetMines(mine_board,lei_board,grade); int x = 0, y = 0; int total = 0; while (1) { Showboard(show_board, grade); printf("请输入坐标:"); //printf("%d", '*'); scanf("%d %d", &x, &y); if (!(x > 0 && x <= ROW + 4 * grade - 2 && y > 0 && y <= COL + 4 * grade - 2)) { printf("扫雷的位置有问题!\n"); continue; } if (show_board[x][y] != ' ') { printf("该位置已经扫过了!\n"); continue; } if (mine_board[x][y] == '1') { printf("对不起,你被炸死了!\n"); Showboard(lei_board, grade); break; } else { int count = CountMine(mine_board, x, y); show_board[x][y] = count + '0'; total++; system("cls"); } if ((ROW - 2) * (COL - 2) - total <= NUM) { printf("恭喜你,游戏通过!\n"); break; } } for (int i = 0; i < ROW + grade * 4; i++) { free(show_board[i]); } free(show_board); for (int i = 0; i < ROW + grade * 4; i++) { free(mine_board[i]); } free(mine_board); for (int i = 0; i < ROW + grade * 4; i++) { free(lei_board[i]); } free(lei_board); } void Menu() { printf("#########################################\n"); printf("## 1.play ##\n"); printf("## 0.exit ##\n"); printf("#########################################\n"); } int main() { srand((unsigned long)time(NULL)); int quit = 0; while (!quit) { int select; Menu(); printf("请输入游戏选项:"); scanf("%d", &select); switch (select) { case 1: printf("#########################################\n"); printf("## 1.easy ##\n"); printf("## 2.middle ##\n"); printf("## 3.difficult ##\n"); printf("#########################################\n"); printf("请输入游戏难度:"); scanf("%d", &select); switch (select) { case 1: Game(0); break; case 2: Game(1); break; case 3: Game(2); break; } break; case 0: quit = 1; printf("感谢使用!"); break; default: printf("输入有误,请重新输入!\n"); break; } } }
期待大家在这个代码的基础上加入更多创新与改进,写出用户体验感更好,更加智能高端的扫雷程序!
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。