一、创建菜单函数
基础起手式do while循环没什么好说的
void menu()
{
printf("**************************\n");
printf("*********扫 雷*********\n");
printf("*****1.play 0.exit*****\n");
printf("**************************\n");
}
int main()
{
int input = 0;
do
{
menu();
printf("请输入选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
printf("游戏开始!\n");
game();//进入游戏
break;
case 0://输入0 do while 条件判定 0 结束循环
printf("退出游戏!\n");
break;
default:
printf("选择错误!\n");
break;
}
} while (input);
return 0;
}
二、扫雷游戏
流程
1.创建两个数组,一个用于布雷,一个用于显示
2.初始化两个数组
3.布雷
4. 开局开辟一块安全区
5.显示棋盘
6.开始扫雷游戏
void game()
{
//创建两个数组,一个用于布雷,一个用于显示
char mine[ROWS][COLS];
char show[ROWS][COLS];
//初始化
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
//布雷
SetMine(mine, ROW, COL);
DisplayBoard(mine, ROW, COL);
//开局开辟一块安全区
FindMineStart(mine, show, ROW, COL);
//显示棋盘
DisplayBoard(show, ROW, COL);
//开始扫雷
FindMine(mine, show, ROW, COL);
}
1.创建两个数组并初始化
创建两个ROW+2
行COL+2
列数组用于表示ROW
*COL
(ROW行COL列)的棋盘
写一个初始化函数,通过两次调用,对两个数组进行初始化
规定:
布雷数组:
0
表示无雷,1
表示有雷
显示数组:
*
表示未排查的雷区,排查过的雷区用数字标记附近雷的数量,附近无雷则用
空格表示安全区
void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set)
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
arr[i][j] = set;
}
}
}
2.打印棋盘函数
从数组下标[1]开始,打印ROW
行COL
列棋盘
void DisplayBoard(char arr[ROWS][COLS], int row, int col)
{
for (int i = 0; i <= 2*row+1; i++)
{
printf("-");
}
printf("\n");//"--------------"
for (int i = 0; i <= row; i++)
{
printf("%d ", i);//横坐标
}
printf("\n");
for (int i = 1; i <= row; i++)
{
printf("%d ", i);//纵坐标
for (int j = 1; j <= col; j++)
{
printf("%c ", arr[i][j]);
}
printf("\n");
}
for (int i = 0; i <= 2 * row + 1; i++)
{
printf("-");
}
printf("\n");//"--------------"
}
3.布雷函数
设定雷的数量为COUNT
需要用到随机值,rand函数(stdlib.h)、time函数(time.h)
创建随机坐标x,y,范围在1~9,第一次循环后要判断坐标是否已经布雷
void SetMine(char arr[ROWS][COLS], int row, int col)
{
int count = COUNT;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (arr[x][y] == '0')//判断
{
arr[x][y] = '1';
count--;
}
}
}
在main函数中加上srand((unsigned int)time(NULL));
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请输入选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
printf("游戏开始!\n");
game();
break;
case 0://输入0 do while 条件判定 0 结束循环
printf("退出游戏!\n");
break;
default:
printf("选择错误!\n");
break;
}
} while (input);
return 0;
}
4.扫雷函数主体
用x,y表示坐标
1.提示输入坐标
2.scanf函数输入坐标
3.判断坐标是否在棋盘范围内
4.判断是否踩雷,踩雷炸死游戏结束,未踩雷用扫雷工具显示周围雷数量(需要创建函数来实现)
5.扫完所有的雷,while循环结束
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
while (1)
{
printf("请输入坐标:>");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (show[x][y] == '*')
{
if (mine[x][y] == '1')
{
printf("你被炸死了\n");
DisplayBoard(mine, ROW, COL);
break;
}
else
{
//扫雷工具
FindMineTool(mine, show, ROW, COL, x, y);
//显示棋盘
DisplayBoard(show, ROW, COL);
}
}
else
{
printf("重复坐标\n");
}
}
else
{
printf("非法坐标\n");
}
}
}
5.扫雷工具函数
显示周边雷的数量
GetMineCount
函数表示
统计(x,y)周围的8个坐标的雷分布情况
arr[x][y]
得到'1'
的是字符型,可以通过'1' - '0'
转化为整形1
int GetMineCount(char arr[ROWS][COLS], int x, int y)
{
return arr[x][y - 1] + arr[x][y + 1] +
arr[x - 1][y - 1] + arr[x - 1][y] +
arr[x - 1][y + 1] + arr[x + 1][y - 1] +
arr[x + 1][y] + arr[x + 1][y + 1] - 8 * '0';
}
递归探索
我们玩扫雷游戏时候,并不是单纯一个一个坐标判断的,这样很浪费时间,实际上当坐标附近都没雷的时候,我们可以把这个坐标和四周的8个坐标判断为安全区,并以安全区为原点向外继续扫雷,直到附近有雷为止。可以用递归方法实现这个功能。
*
表示未排查的雷区,排查过的雷区用数字标记附近雷的数量,附近无雷则用
空格表示安全区。
void FindMineTool(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y)
{
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (show[x][y] == ' ')//当坐标是被标记过的安全区
{
return;//返回,结束
}
else if (GetMineCount(mine, x, y) != 0)//当坐标附件有雷时
{
show[x][y] = GetMineCount(mine, x, y) + '0';//显示雷的数量
return;
}
show[x][y] = ' ';//附件无雷为安全区,用空格表示
FindMineTool(mine, show, ROW, COL, x - 1, y - 1);
FindMineTool(mine, show, ROW, COL, x - 1, y);
FindMineTool(mine, show, ROW, COL, x - 1, y + 1);
FindMineTool(mine, show, ROW, COL, x, y - 1);
FindMineTool(mine, show, ROW, COL, x, y + 1);
FindMineTool(mine, show, ROW, COL, x + 1, y - 1);
FindMineTool(mine, show, ROW, COL, x + 1, y);
FindMineTool(mine, show, ROW, COL, x + 1, y + 1);
}
}
6.通关条件
扫雷通关条件就是扫完所有坐标,标记所有雷
棋盘最后剩余的*
坐标都是雷,也就是*
的数量等于设定的雷的数量COUNT
int FindMineWin(char show[ROWS][COLS], int row, int col)
{
int count = 0;
for (int i = 1; i <= row; i++)
{
for (int j = 1; j <= col; j++)
{
if (show[i][j] == '*')
count++;
}
}
return count;
}
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
while (FindMineWin(show, ROW, COL) > COUNT)
{
printf("请输入坐标:>");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (show[x][y] == '*')
{
if (mine[x][y] == '1')
{
printf("你被炸死了\n");
DisplayBoard(mine, ROW, COL);
break;
}
else
{
// 扫雷工具:
// 显示坐标周围的雷的数量
// 如果数量为0,就以坐标周围的8个点为原点
// 扩散扫雷,直到附近有雷为止
//
FindMineTool(mine, show, ROW, COL, x, y);
DisplayBoard(show, ROW, COL);
}
}
else
{
printf("重复坐标\n");
}
}
else
{
printf("非法坐标\n");
}
}
if (FindMineWin(show, ROW, COL) == COUNT)
{
printf("游戏通关\n");
DisplayBoard(mine, ROW, COL);
}
}
7.开局开辟一块安全区
每次开局我们输的前几个坐标都有直接被雷炸死的风险,开局被炸死非常影响游戏,我们需要一个功能可以实现,游戏开局就自动显示一块安全区,FindMineStart
函数
void FindMineStart(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int count = 1;
int x = 0;
int y = 0;
while (count)
{
x = rand() % row + 1;
y = rand() % col + 1;
if (mine[x][y] == '0')
{
if (GetMineCount(mine, x, y) == 0)
{
FindMineTool(mine, show, ROW, COL, x, y);
count--;
}
}
}
三、完整代码
头文件 game.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 9
#define COL 9
#define ROWS 9+2
#define COLS 9+2
#define COUNT 10
void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set);
void DisplayBoard(char arr[ROWS][COLS], int row, int col);
void SetMine(char arr[ROWS][COLS], int row, int col);
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
void FindMineStart(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
主函数 main.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void menu()
{
printf("**************************\n");
printf("*********扫 雷*********\n");
printf("*****1.play 0.exit*****\n");
printf("**************************\n");
}
void game()
{
//创建两个数组,一个用于布雷,一个用于显示
char mine[ROWS][COLS];
char show[ROWS][COLS];
//初始化
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
//布雷
SetMine(mine, ROW, COL);
DisplayBoard(mine, ROW, COL);
//开局开辟一块安全区
FindMineStart(mine, show, ROW, COL);
//显示棋盘
DisplayBoard(show, ROW, COL);
//开始扫雷
FindMine(mine, show, ROW, COL);
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请输入选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
printf("游戏开始!\n");
game();
break;
case 0://输入0 do while 条件判定 0 结束循环
printf("退出游戏!\n");
break;
default:
printf("选择错误!\n");
break;
}
} while (input);
return 0;
}
游戏功能函数 game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set)
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
arr[i][j] = set;
}
}
}
void DisplayBoard(char arr[ROWS][COLS], int row, int col)
{
for (int i = 0; i <= 2*row+1; i++)
{
printf("-");
}
printf("\n");//"--------------"
for (int i = 0; i <= row; i++)
{
printf("%d ", i);
}
printf("\n");
for (int i = 1; i <= row; i++)
{
printf("%d ", i);
for (int j = 1; j <= col; j++)
{
printf("%c ", arr[i][j]);
}
printf("\n");
}
for (int i = 0; i <= 2 * row + 1; i++)
{
printf("-");
}
printf("\n");//"--------------"
}
void SetMine(char arr[ROWS][COLS], int row, int col)
{
int count = COUNT;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (arr[x][y] == '0')
{
arr[x][y] = '1';
count--;
}
}
}
int GetMineCount(char arr[ROWS][COLS], int x, int y)
{
return arr[x][y - 1] + arr[x][y + 1] +
arr[x - 1][y - 1] + arr[x - 1][y] +
arr[x - 1][y + 1] + arr[x + 1][y - 1] +
arr[x + 1][y] + arr[x + 1][y + 1] - 8 * '0';
}
void FindMineTool(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y)
{
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (show[x][y] == ' ')//当坐标是被标记过的安全区
{
return;//返回,结束
}
else if (GetMineCount(mine, x, y) != 0)//当坐标附件有雷时
{
show[x][y] = GetMineCount(mine, x, y) + '0';//显示雷的数量
return;
}
show[x][y] = ' ';//附件无雷为安全区,用空格表示
FindMineTool(mine, show, ROW, COL, x - 1, y - 1);
FindMineTool(mine, show, ROW, COL, x - 1, y);
FindMineTool(mine, show, ROW, COL, x - 1, y + 1);
FindMineTool(mine, show, ROW, COL, x, y - 1);
FindMineTool(mine, show, ROW, COL, x, y + 1);
FindMineTool(mine, show, ROW, COL, x + 1, y - 1);
FindMineTool(mine, show, ROW, COL, x + 1, y);
FindMineTool(mine, show, ROW, COL, x + 1, y + 1);
}
}
void FindMineStart(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int count = 1;
int x = 0;
int y = 0;
while (count)
{
x = rand() % row + 1;
y = rand() % col + 1;
if (mine[x][y] == '0')
{
if (GetMineCount(mine, x, y) == 0)
{
FindMineTool(mine, show, ROW, COL, x, y);
count--;
}
}
}
}
int FindMineWin(char show[ROWS][COLS], int row, int col)
{
int count = 0;
for (int i = 1; i <= row; i++)
{
for (int j = 1; j <= col; j++)
{
if (show[i][j] == '*')
count++;
}
}
return count;
}
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
while (FindMineWin(show, ROW, COL) > COUNT)
{
printf("请输入坐标:>");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (show[x][y] == '*')
{
if (mine[x][y] == '1')
{
printf("你被炸死了\n");
DisplayBoard(mine, ROW, COL);
break;
}
else
{
// 扫雷工具:
// 显示坐标周围的雷的数量
// 如果数量为0,就以坐标周围的8个点为原点
// 扩散扫雷,直到附近有雷为止
//
FindMineTool(mine, show, ROW, COL, x, y);
DisplayBoard(show, ROW, COL);
}
}
else
{
printf("重复坐标\n");
}
}
else
{
printf("非法坐标\n");
}
}
if (FindMineWin(show, ROW, COL) == COUNT)
{
printf("游戏通关\n");
DisplayBoard(mine, ROW, COL);
}
}