目录
一、问题描述
用C语言实现扫雷
在线扫雷游戏:http://www.minesweeper.cn/
二、基本思路
实现代码的逻辑
• 使⽤控制台实现经典的扫雷游戏• 游戏可以通过菜单实现继续玩或者退出游戏• 扫雷的棋盘是9*9的格⼦• 默认随机布置10个雷• 可以排查雷◦ 如果位置不是雷,就显⽰周围有⼏个雷◦ 如果位置是雷,就炸死游戏结束◦ 把除10个雷之外的所有雷都找出来,排雷成功,游戏结束
扫雷的过程中,布置的雷和排查出的雷的信息都需要存储,所以我们需要⼀定的数据结构来存储些信息。因为我们需要在9*9的棋盘上布置雷的信息和排查雷,我们⾸先想到的就是创建⼀个9*9的数组来存放 信息。那如果这个位置布置雷,我们就存放1,没有布置雷就存放0.专⻔给⼀个棋盘(对应⼀个数组mine)存放布置好的雷的信息,再 给另外⼀个棋盘(对应另外⼀个数组show)存放排查出的雷的信息。这样就互不⼲扰了,把雷布置到 mine数组,在mine数组中排查雷,排查出的数据存放在show数组,并且打印show数组的信息给后期 排查参考。
三、步骤
1.菜单界面
首先玩家进入程序,不管三七二十一先打印出来菜单(可以用do while语句实现)
输入对应的数字选择对应的游戏
void menu(void)
{
printf("\n**********游戏机***********\n");
printf("*********玩过都说好*******\n\n");
printf("**********************\n");
printf("******1.扫雷**********\n");
printf("******2.刮刮乐**********\n");
printf("******3.地铁跑酷**********\n");
printf("******4.王者荣耀**********\n");
printf("******5.老爹的早餐店**********\n");
printf("******0.exit******************\n");
printf("******************************\n");
printf("*****************************\n\n");
}
2.创建棋盘
试想一下扫雷游戏,当点了一个位置以后,如果不是雷 这一片都会展开并在点的这里统计周围雷的个数
基于这一点 假如说创建一个9*9大小的棋盘来存雷 那排查雷就要12*12大小
因为 行跟列都会改变,我们使用宏定义去定义大小跟雷
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define MINE 10
在扫雷中 刚开始的时候我们看棋盘是什么都看不见的,在玩的过程中会一点点显露出来并且记录周围的雷个数,所以这意味着需要两个数字来实现这个功能
char mine数组 用来存放布置好的雷
char show 数组 用来存放排查出的雷的信息
char mine[ROWS][COLS];
char show[ROWS][COLS];
3.初始化棋盘
将棋盘全部初始化为传入的set这个字符
void Board_Init(char Board[ROWS][COLS], int rows, int cols, char set)
{
int i, j = 0;
for (i = 0; i < rows; i++) //棋盘的初始化
{
for (j = 0; j < cols; j++)
{
Board[i][j] = set;
}
}
}
当然也可以用这个库函数来实现
memset()这个库函数实现--------包含头文件 #include<string,h>
复制字符 set(一个无符号字符)到参数 board所指向的字符串的前 n 个字符
//这个set作用是需要初始化什么就传什么字符
void Board_Init(char board[ROWS][COLS],int rows,int cols,char set)
{
//(rows*cols*sizeof(board[0][0])) 行*列*单个元素大小 就是整个数组大小
memset(&board[0][0],set,rows*cols*sizeof(board[0][0]));
}
因为 mine 用来存放布置好的雷, show 用来存放排查出的雷的信息,所以
将mine初始化设为0,雷后面设为1
将show刚开始设为* ,进入游戏什么都看不见
Board_Init(mine, ROWS, COLS, '0');
Board_Init(show, ROWS, COLS, '*');
4.打印棋盘
为了方便玩家好找坐标去排查,不用一个个去数,我们可以将行跟列分别打印在第一行
void DisPlayBorad(char arr[ROWS][COLS], int row, int col)
{
int i, j = 0; // 打印出棋盘
printf("\n--------------------------------\n");
for (i = 0; i <= col; i++)
{
printf("%d", i); // 打印显示行
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d", i); //打印显示列
for (j = 1; j <= col; j++)
{
printf("%c", arr[i][j]);
}
printf("\n");
}
}
单独打印出来0123456789 换行以后在每一次 i++ 之后进入 j 之前打印出来 i
放在前面给玩家当个指导
5.布置雷
我们可以先宏定义一个雷的个数
雷个数越多我们的难度越大,可以通过控制雷的个数控制难度,使用宏方便修改
#define MINE 10
这个函数作用是将雷随机的放入数组中
为了保证每一次的值真正随机,在主函数里面给她一个时间戳种子
并且包含两个头文件
#include<stdlib.h>
#include<time.h>
srand((unsigned int)time(NULL))
每布置一个雷减一个次数并且把那个位置设为1
当次数为0(count==0)的时候,就不往进放了
里面的if语句作用是为了在没有雷的地方进行布置
而rand()函数生成的随机数范围在0 ~ 32767之间
所以我们要给她% 行/列 数,生成的num就是0大于等于0,小于自己的数
因为为了方便统计我们的数组是12*12 但实际是9*9
所以最外面的一圈不能被放置雷的,所以就有了
int x = rand() % row + 1;
int y = rand() % col + 1;
void SetMine(char mine[ROWS][COLS], int row, int col)
{
//布置10个雷
//⽣成随机的坐标,布置雷
int count = MINE;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count--;
}
}
}
6.排查雷
这个代码实现对棋盘雷的排查,玩家输入坐标
是雷了被炸死
不是雷这个位置统计周围的雷个数
只有被炸死或者排除完雷才能跳出,不然一直在这个函数中循环
顺便给大家补充个知识点
int类型变成char类型
只需要1 + ‘0’ = ‘1’
同理
char类型变为int类型
只需要‘1’-‘0’=1
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x, y = 0;
//x y坐标
int win = 0;
//win是剩余没有排查没有雷的的位置
while (win < ((row * col) - MINE)) //当剩余的地方小于没有雷的位置时,说明还可以排继续循环
{
printf("Enter the coordinates for troubleshooting(选择你要排查的坐标)->");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
printf("The game is over, you're dead(游戏结束你死了)!!!!!!!");
printf("打印出来了你看吧");
DisPlayBorad(mine, ROW, COL);
//位置是1为雷 被炸死游戏结束
break;
}
else
{
int n = GetMineCount(mine, x, y);
show[x][y] = n + '0';
DisPlayBorad(show, ROW, COL);
win++;
}
}
else
{
printf("Re-enter(请重新输入)\n");
}
}
if (win == ((row * col) - MINE))
{
//当剩余的地方等于没有雷的位置时,说明排完了,游戏结束赢了
printf("Complete the game(赢咯)\n");
DisPlayBorad(mine, ROW, COL);
}
}
正因为这个函数返回值为整形int,但是传给show数组里面类型是char类型
正如上面说的int类型变成char类型,只需要用这个数加上一个字符0
所以就有了上述代码中的这个操作
int n = GetMineCount(mine, x, y);
show[x][y] = n + '0';
这个函数功能是当这个位置不是雷 统计一下周围有几个雷并以整形返回
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
return ((mine[x + 1][y] + mine[x][y + 1] + mine[x - 1][y] + mine[x][y - 1] + mine[x + 1][y + 1] + mine[x + 1][y - 1] + mine[x - 1][y + 1] + mine[x - 1][y - 1]) + (8 * '0'));
}
8.主要逻辑实现
这个函数主要实现整体逻辑
void game(void)
{
char mine[ROWS][COLS]; //存放布置好的雷
char show[ROWS][COLS]; //存放排查出的雷的信息
//初始化棋盘
//1. mine数组最开始是全'0'
//2. show数组最开始是全'*'
Board_Init(mine, ROWS, COLS, '0');
Board_Init(show, ROWS, COLS, '*');
//打印棋盘
DisPlayBorad(show, ROW, COL);
//1. 布置雷
SetMine(mine, ROW, COL);
//2. 排查雷
FindMine(mine, show, ROW, COL);
printf("\n歇一下 20秒后进入菜单");
Sleep(20000);
system("cls"); //睡眠10s 自动清屏
}
四、代码实现
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include <stdlib.h>
#include<time.h>
#include <windows.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define MINE 10
void menu(void)
{
printf("\n**********游戏机***********\n");
printf("*********玩过都说好*******\n\n");
printf("**********************\n");
printf("******1.扫雷**********\n");
printf("******2.刮刮乐**********\n");
printf("******3.地铁跑酷**********\n");
printf("******4.王者荣耀**********\n");
printf("******5.老爹的早餐店**********\n");
printf("******0.exit******************\n");
printf("******************************\n");
printf("*****************************\n\n");
}
void Board_Init(char Board[ROWS][COLS], int rows, int cols, char set)
{
int i, j = 0;
for (i = 0; i < rows; i++) //棋盘的初始化
{
for (j = 0; j < cols; j++)
{
Board[i][j] = set;
}
}
}
void DisPlayBorad(char arr[ROWS][COLS], int row, int col)
{
int i, j = 0; // 打印出棋盘
printf("\n--------------------------------\n");
for (i = 0; i <= col; i++)
{
printf("%d", i); // 打印显示行
}
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 mine[ROWS][COLS], int row, int col)
{
//布置10个雷
//⽣成随机的坐标,布置雷
int count = MINE;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count--;
}
}
}
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
return ((mine[x + 1][y] + mine[x][y + 1] + mine[x - 1][y] + mine[x][y - 1] + mine[x + 1][y + 1] + mine[x + 1][y - 1] + mine[x - 1][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, y = 0;
int win = 0;
while (win < ((row * col) - MINE))
{
printf("Enter the coordinates for troubleshooting(选择你要排查的坐标)->");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
printf("The game is over, you're dead(游戏结束你死了)!!!!!!!");
printf("打印出来了你看吧");
DisPlayBorad(mine, ROW, COL);
break;
}
else
{
int n = GetMineCount(mine, x, y);
show[x][y] = n + '0';
DisPlayBorad(show, ROW, COL);
win++;
}
}
else
{
printf("Re-enter(请重新输入)\n");
}
}
if (win == ((row * col) - MINE))
{
printf("Complete the game(赢咯)\n");
DisPlayBorad(mine, ROW, COL);
}
}
void game(void)
{
char mine[ROWS][COLS]; //存放布置好的雷
char show[ROWS][COLS]; //存放排查出的雷的信息
//初始化棋盘
//1. mine数组最开始是全'0'
//2. show数组最开始是全'*'
Board_Init(mine, ROWS, COLS, '0');
Board_Init(show, ROWS, COLS, '*');
//打印棋盘
DisPlayBorad(show, ROW, COL);
//1. 布置雷
SetMine(mine, ROW, COL);
//2. 排查雷
FindMine(mine, show, ROW, COL);
printf("\n歇一下 20秒后进入菜单");
Sleep(20000);
system("cls"); //睡眠10s 自动清屏
}
int main(void)
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu(); //进来先打印出来一个菜单
printf("please input number(输入对应数字 选择游戏):>");
scanf("%d", &input);
Sleep(1000);
switch (input)
{
case 1: //根据选择的数字进入对应的case
system("cls");
printf(">>>>>>>>>>>>>>>>>>>>>>> game start(游戏开始)!!!!!!!!!!!!!!\n");
Sleep(1000);
game();
break;
case 2:
system("cls");
printf("Lie to you(呆瓜 根本没有刮刮乐,只有一个扫雷哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈)\n");
Sleep(1000);
break;
case 3:
system("cls");
printf("Lie to you(呆瓜 根本没有地铁跑酷,只有一个扫雷哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈)\n");
Sleep(1000);
break;
case 4:
system("cls");
printf("Lie to you(呆瓜 根本没有王者荣耀,只有一个扫雷哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈)\n");
Sleep(1000);
break;
case 5:
system("cls");
printf("Lie to you(呆瓜 根本没有老爹的早餐店,只有一个扫雷哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈)\n");
Sleep(1000);
break;
case 0:
system("cls");
printf(">>>>>>>>>>>>>>>>>>>>>>> game over(游戏结束)!!!!!!!!!\n");
Sleep(1000);
break;
default:
system("cls");
printf(">>>>>>>>>>>>>>>>>>>>>>> Re-enter(重新选择)_________________\n");
Sleep(1000);
break;
}
} while (input);
return 0;
}
希望对你有帮助