目录
一、游戏基本逻辑
扫雷游戏:一个棋盘上存在数个不知位置的地雷,需要玩家根据安全区域周围雷的个数判断地雷的具体位置,直到棋盘上仅剩地雷为止,扫雷成功,游戏胜利。
二、代码实现
1.最先显示的菜单menu
打印菜单。
void menu()
{
printf("************************************\n");
printf("******** 1.扫雷游戏 *************\n");
printf("******** 0.退出 *************\n");
printf("************************************\n");
}
2.game函数
void game()
{
char mineboard[ROWS][COLS];
char showboard[ROWS][COLS];
//初始化棋盘
Initboard(mineboard, ROWS, COLS,'0');
Initboard(showboard, ROWS, COLS,'*');
//打印棋盘
//Displayboard(mineboard, ROW, COL);
Displayboard(showboard, ROW, COL);
//布置雷
Setmine(mineboard, ROW, COL);
//Displayboard(mineboard, ROW, COL);
//排查雷
Putmine(mineboard,showboard, ROWS, COLS);
}
①.初始化棋盘函数
void Initboard(char board[ROWS][COLS], int rows, int cols,char ret)
{
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = ret;
}
}
}
②.布置雷函数
利用库的时间函数实现随机布置雷。
void Setmine(char board[ROWS][COLS], int row, int col)//设置雷
{
int i = 0;
while( i < count )
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (board[x][y] != '1')//判断合理性
{
board[x][y] = '1';
i++;
}
}
}
③.排查雷函数
包括判断坐标合理性、判断游戏是否失败或胜利功能。
void Putmine(char mine[ROWS][COLS], char show[ROWS][COLS], int rows, int cols)
{
int x = 0;
int y = 0;
int m = 0;
int n = 0;
int ret = 0;
int input = 0;
while (1)
{
while (1)
{
menu1();
scanf("%d", &input);
switch (input)
{
case 1:
{
while (1)
{
printf("请输入需要排查的坐标:> ");
scanf("%d %d", &x, &y);//需要判断合理性
if (x <= ROW && y <= COL)
{
break;
}
else
{
printf("输入的坐标错误,请重新输入。\n");
}
}
break;
}
case 2:
{
while (1)
{
printf("请输入需要标记的坐标:> ");
scanf_s("%d %d", &m, &n);//需要判断合理性
if (m <= ROW && n <= COL)
{
break;
}
else
{
printf("输入的坐标错误,请重新输入。\n");
}
}
sign_board(show, m, n);
break;
}
case 3:
{
{
while (1)
{
printf("请输入需要取消标记的坐标:> ");
scanf_s("%d %d", &m, &n);//需要判断合理性
if (m <= ROW && n <= COL)
{
break;
}
else
{
printf("输入的坐标错误,请重新输入。\n");
}
}
void_board(show, m, n);
break;
}
}
}
if (mine[x][y] == '1')
{
printf("很遗憾,您被炸死了\n");
Displayboard(mine, ROW, COL);
break;
}
if (mine[x][y] != '1')
{
/*int num = EASE_count(mine, x, y);
show[x][y] = num +'0';*/
Sqre_count(mine, show, x, y);
Displayboard(show, ROW, COL);
ret++;
if (ret == ROW * COL - count)
{
printf("恭喜你,游戏胜利。\n");
break;
}
}
}
break;
}
}
a.雷个数统计函数
static int EASE_count(char board[ROWS][COLS],int a,int b)//个数统计
{
return board[a - 1][b - 1]
+ board[a - 1][b]
+ board[a - 1][b + 1]
+ board[a][b + 1]
+ board[a][b - 1]
+ board[a + 1][b - 1]
+ board[a + 1][b]
+ board[a + 1][b + 1]
- 8 * '0';
}
b.展开一片函数
展开函数运用了递归的方法。
首先我们要知道递归需要有一个限制范围。
这个展开函数需要满足三个条件才可以继续执行
1.自身不是雷
2.自身周围八个坐标没有雷
3.不可以递归已经排查过的坐标
第一个问题很好理解,根据排查雷函数,只有当自身不是雷的时候才会调用展开一片函数,而如果自身周围有雷的话根本不会进行递归,所以不存在自身是雷这个问题。
if (mine[x][y] == '1')
{
printf("很遗憾,您被炸死了\n");
Displayboard(mine, ROW, COL);
break;
}
if (mine[x][y] != '1')
{
/*int num = EASE_count(mine, x, y);
show[x][y] = num +'0';*/
Sqre_count(mine, show, x, y);
Displayboard(show, ROW, COL);
ret++;
if (ret == ROW * COL - count)
{
printf("恭喜你,游戏胜利。\n");
break;
}
}
第二个问题是自身周围没有雷,调用雷个数统计函数可知坐标周围雷的个数,如坐标周围有雷则会结束函数,不会进行递归。
第三个问题是不递归之前已经递归过的坐标,只要检查show[i][j]就可以知道此坐标有没有被递归过,如果show[i][j]被递归过则此坐标在棋盘中将不会为‘*’。
static void Sqre_count(char board[ROWS][COLS],char show[ROWS][COLS],int a,int b)//展开
{
int x = 0;
x = EASE_count(board, a, b);
if (x == 0)
{
show[a][b] = ' ';
int i = 0;
for (i = a - 1; i <= a + 1; i++)
{
int j = 0;
for (j = b - 1; j <= b + 1; j++)
{
if (show[i][j] == '*')
Sqre_count(board, show, i, j);
}
}
}
else
{
show[a][b] = x + '0';
}
}
c.标记函数
static void sign_board( char show[ROWS][COLS], int a, int b)//标记
{
if (show[a][b] == '*')
{
show[a][b] = '_';
}
else
{
printf("此位置不可标记。\n");
}
}
d.取消标记函数
static void void_board(char show[ROWS][COLS], int a, int b)//取消标记
{
if (show[a][b] == '_')
{
show[a][b] = '*';
}
else
{
printf("此位置不可取消标记。\n");
}
}
e.判断是扫雷还是标记还是取消标记的菜单
static void menu1()
{
printf("************************************\n");
printf("******** 1.排查坐标 *************\n");
printf("******** 2.标记坐标 *************\n");
printf("******** 3.取消坐标 *************\n");
printf("************************************\n");
}
④.打印棋盘函数
void Displayboard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("----------扫雷游戏------------------\n");
for (i = 0; i <= row; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d ", i);
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("----------扫雷游戏------------------\n");
}
3.main函数
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
三、总代码
1.test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
//扫雷
//1.创建雷盘
//2.扫雷
//3.判断是否爆炸
void menu()
{
printf("************************************\n");
printf("******** 1.扫雷游戏 *************\n");
printf("******** 0.退出 *************\n");
printf("************************************\n");
}
void game()
{
char mineboard[ROWS][COLS];
char showboard[ROWS][COLS];
//初始化棋盘
Initboard(mineboard, ROWS, COLS,'0');
Initboard(showboard, ROWS, COLS,'*');
//打印棋盘
//Displayboard(mineboard, ROW, COL);
Displayboard(showboard, ROW, COL);
//布置雷
Setmine(mineboard, ROW, COL);
//Displayboard(mineboard, ROW, COL);
//排查雷
Putmine(mineboard,showboard, ROWS, COLS);
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
2.game.c
#pragma once
#include"game.h"
void Initboard(char board[ROWS][COLS], int rows, int cols,char ret)
{
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = ret;
}
}
}
void Displayboard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("----------扫雷游戏------------------\n");
for (i = 0; i <= row; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d ", i);
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("----------扫雷游戏------------------\n");
}
void Setmine(char board[ROWS][COLS], int row, int col)//设置雷
{
int i = 0;
while( i < count )
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (board[x][y] != '1')//判断合理性
{
board[x][y] = '1';
i++;
}
}
}
static int EASE_count(char board[ROWS][COLS],int a,int b)//个数统计
{
return board[a - 1][b - 1]
+ board[a - 1][b]
+ board[a - 1][b + 1]
+ board[a][b + 1]
+ board[a][b - 1]
+ board[a + 1][b - 1]
+ board[a + 1][b]
+ board[a + 1][b + 1]
- 8 * '0';
}
static void Sqre_count(char board[ROWS][COLS],char show[ROWS][COLS],int a,int b)//展开
{
int x = 0;
x = EASE_count(board, a, b);
if (x == 0)
{
show[a][b] = ' ';
int i = 0;
for (i = a - 1; i <= a + 1; i++)
{
int j = 0;
for (j = b - 1; j <= b + 1; j++)
{
if (show[i][j] == '*')
Sqre_count(board, show, i, j);
}
}
}
else
{
show[a][b] = x + '0';
}
}
static void sign_board( char show[ROWS][COLS], int a, int b)//标记
{
if (show[a][b] == '*')
{
show[a][b] = '_';
}
else
{
printf("此位置不可标记。\n");
}
}
static void void_board(char show[ROWS][COLS], int a, int b)//取消标记
{
if (show[a][b] == '_')
{
show[a][b] = '*';
}
else
{
printf("此位置不可取消标记。\n");
}
}
static void menu1()
{
printf("************************************\n");
printf("******** 1.排查坐标 *************\n");
printf("******** 2.标记坐标 *************\n");
printf("******** 3.取消坐标 *************\n");
printf("************************************\n");
}
void Putmine(char mine[ROWS][COLS], char show[ROWS][COLS], int rows, int cols)
{
int x = 0;
int y = 0;
int m = 0;
int n = 0;
int ret = 0;
int input = 0;
while (1)
{
while (1)
{
menu1();
scanf("%d", &input);
switch (input)
{
case 1:
{
while (1)
{
printf("请输入需要排查的坐标:> ");
scanf("%d %d", &x, &y);//需要判断合理性
if (x <= ROW && y <= COL)
{
break;
}
else
{
printf("输入的坐标错误,请重新输入。\n");
}
}
break;
}
case 2:
{
while (1)
{
printf("请输入需要标记的坐标:> ");
scanf_s("%d %d", &m, &n);//需要判断合理性
if (m <= ROW && n <= COL)
{
break;
}
else
{
printf("输入的坐标错误,请重新输入。\n");
}
}
sign_board(show, m, n);
break;
}
case 3:
{
{
while (1)
{
printf("请输入需要取消标记的坐标:> ");
scanf_s("%d %d", &m, &n);//需要判断合理性
if (m <= ROW && n <= COL)
{
break;
}
else
{
printf("输入的坐标错误,请重新输入。\n");
}
}
void_board(show, m, n);
break;
}
}
}
if (mine[x][y] == '1')
{
printf("很遗憾,您被炸死了\n");
Displayboard(mine, ROW, COL);
break;
}
if (mine[x][y] != '1')
{
/*int num = EASE_count(mine, x, y);
show[x][y] = num +'0';*/
Sqre_count(mine, show, x, y);
Displayboard(show, ROW, COL);
ret++;
if (ret == ROW * COL - count)
{
printf("恭喜你,游戏胜利。\n");
break;
}
}
}
break;
}
}
3.game.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define ROWS 11
#define COLS 11
#define ROW ROWS-2
#define COL COLS-2
#define count 10
void Initboard(char board[ROWS][COLS], int rows, int cols,char ret);
void Displayboard(char board[ROWS][COLS], int row, int col);
void Setmine(char board[ROWS][COLS], int row,int col);
void Putmine(char mine[ROWS][COLS],char show[ROWS][COLS], int row, int col);