思路
清晰的逻辑
菜单
棋盘
布置雷
排雷
判断输赢
text.c实现
game.c实现
game.h实现
递归部分详解
总结
思路 清晰的逻辑为方便将其分为三个文件:text.c(测试) game.c(函数实现) game.h(头文件声明)
在排雷的时候为了方便,我们需要将每一行每一列对应的行数,列数打印出来。
#define LEI 10
#define ROW 10
#define LOW 10
#define ROWS ROW+2
#define LOWS LOW+2
//在定义棋盘的长宽时,特意加上2,便于标记行数列数。
菜单
打印的菜单只需要有开始游戏、退出游戏的选项即可
void menu()
{
printf("*************************************\n");
printf("************1.开始游戏***************\n");
printf("************0.退出游戏***************\n");
printf("*************************************\n");
}
棋盘
1.雷盘
2.棋盘
扫雷需要先记录雷的信息再进行排雷,如果使用一个棋盘太过于复杂,所以我们使用两个棋盘,一个用于布置雷,一个用于玩家排雷。
两个棋盘初始化
布置雷的棋盘初始化,将字符‘0’作为非雷,字符‘1’作为雷。
玩家盘将字符‘*’作为还没有扫的地方
board(arr1, ROWS, LOWS, '0');//雷盘
board(arr2, ROWS, LOWS, '*');//玩家盘
因为两个的初始化方式不同,所以我们采用传参ret初始化
//初始化棋盘
void board(char arr1[ROWS][LOWS], int rows, int lows, char ret)
{
int i = 0;
for (i = 0; i < rows; i++)
{
int j = 0;
for (j = 0; j < lows; j++)
{
arr1[i][j] = ret;
}
}
布置雷
布置的雷放置需要随机,所以采用两个随机数来定位坐标。
//布置雷
void Get_lei(char arr1[ROWS][LOWS], int row, int low)
{
int count = LEI;
while (count)
{
int x = rand() % row + 1;
int y = rand() % low + 1;
if (arr1[x][y] == '0')
{
arr1[x][y] = '1';
count--;
}
}
//displayboard(arr1, ROW, LOW);//用于测试
}
排雷
当我们输入一个坐标时,我们需要知道这个坐标周围雷的个数,定义一个Get_num函数来获取雷个数。但此时只能获取一个坐标的信息,我们知道一般的扫雷,如果当前坐标雷的个数为0,就会展开,这个过程较为复杂,所以我们使用递归来实现
//玩家盘
static int Get_num(char arr1[ROWS][LOWS],int x, int y)//获得当前坐标周围雷的个数
{
int count = 0;
int i = 0;
for (i = x - 1; i <= x + 1; i++)
{
int j = 0;
for (j = y - 1; j <= y + 1; j++)
{
if (arr1[i][j] == '1')
{
count++;
}
}
}
return count;
}
//判断是否展开,实现函数
static void Judge(char arr2[ROWS][LOWS], char arr1[ROWS][LOWS], int x, int y)
{
if (x > 0 && x <= ROW && y > 0 && y <= LOW)
{
int ret = Get_num(arr1, x, y);
if (ret != 0)
arr2[x][y] = ret + '0';//记录雷的个数
//递归散开
else if (arr1[x][y] != ' ')
{
arr2[x][y] = '0';
arr1[x][y] = ' ';
int i = 0;
for (i = x - 1; i <= x + 1; i++)
{
int j = 0;
for (j = y - 1; j <= y + 1; j++)
{
Judge(arr2, arr1, i, j);
}
}
}
else
{
return;
}
}
}
判断输赢
输:即每排一次雷,检查一下雷盘对应的信息,如果是雷,就被炸死,如果不是,就继续排雷。
赢:当玩家将所有的非雷的区域都排查出来时,判断为赢。(这里采用一个计数器,没排一次雷计数器就++一下,当计数器与总的非雷的区域数目相同时,判断为赢)
void Out_lei(char arr2[ROWS][LOWS], int row, int low, char arr1[ROWS][LOWS])
{
int x = 0;
int y = 0;
while (1)
{
printf("请输入坐标:>");
scanf("%d,%d", &x, &y);
if (x >= 1 && x <= ROW && y >= 1 && y <= LOW)
{
if (arr1[x][y] == '1')
{
arr2[x][y] = '#';
displayboard(arr2, ROW, LOW);//排雷
printf("遗憾你输了\n");
break;
}
else
{
Judge(arr2, arr1, x, y);
displayboard(arr2, ROW, LOW);//排雷
}
}
else
{
printf("输入错误!\n");
}
//判断扫雷是否赢
int i = 0, flag = 0;
for (i = 1; i <= ROW; i++)
{
int j = 0;
for (j = 1; j <= LOW; j++)
{
if (arr2[i][j] != '*')
{
flag++;
}
}
}
if (flag == ROW*LOW - LEI)
{
printf("你赢了!\n");
break;
}
}
}
text.c实现
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
//菜单
void menu()
{
printf("*************************************\n");
printf("************1.开始游戏***************\n");
printf("************0.退出游戏***************\n");
printf("*************************************\n");
}
void game()
{
//初始化棋盘
char arr1[ROWS][LOWS] = { 0 };//雷盘
char arr2[ROWS][LOWS] = { 0 };//玩家盘
board(arr1, ROWS, LOWS, '0');
board(arr2, ROWS, LOWS, '*');
//打印棋盘
//displayboard(arr1, ROW, LOW);//布置雷
displayboard(arr2, ROW, LOW);//排雷
//布置雷
Get_lei(arr1,ROW,LOW);
//排雷
Out_lei(arr2,ROW,LOW, arr1);
}
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:
{
printf("退出游戏\n");
break;
}
default:
{
printf("选择错误\n");
break;
}
}
} while (input);
return 0;
}
game.c实现
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
//初始化棋盘
void board(char arr1[ROWS][LOWS], int rows, int lows, char ret)
{
int i = 0;
for (i = 0; i < rows; i++)
{
int j = 0;
for (j = 0; j < lows; j++)
{
arr1[i][j] = ret;
}
}
}
//打印棋盘
void displayboard(char arr1[ROWS][LOWS], int row, int low)
{
printf("<———扫雷游戏———>\n");
int i = 0;
for (i = 1; i <= row; i++)
{
int j = 0;
if (i == 1)
{
for (j = 0; j <= low; j++)
{
printf("%2d ", j);
}
printf("\n");
}
for (j = 1; j <= low; j++)
{
if (j == 1)
{
printf("%2d ", i);
}
printf("%2c ", arr1[i][j]);
}
printf("\n");
}
printf("<———扫雷游戏———>\n");
}
//布置雷
void Get_lei(char arr1[ROWS][LOWS], int row, int low)
{
int count = LEI;
while (count)
{
int x = rand() % row + 1;
int y = rand() % low + 1;
if (arr1[x][y] == '0')
{
arr1[x][y] = '1';
count--;
}
}
//displayboard(arr1, ROW, LOW);
}
//玩家盘
static int Get_num(char arr1[ROWS][LOWS],int x, int y)
{
int count = 0;
int i = 0;
for (i = x - 1; i <= x + 1; i++)
{
int j = 0;
for (j = y - 1; j <= y + 1; j++)
{
if (arr1[i][j] == '1')
{
count++;
}
}
}
return count;
}
//判断是否展开,实现函数
static void Judge(char arr2[ROWS][LOWS], char arr1[ROWS][LOWS], int x, int y)
{
if (x > 0 && x <= ROW && y > 0 && y <= LOW)
{
int ret = Get_num(arr1, x, y);
if (ret != 0)
arr2[x][y] = ret + '0';
//递归散开
else if (arr1[x][y] != ' ')
{
arr2[x][y] = '0';
arr1[x][y] = ' ';
int i = 0;
for (i = x - 1; i <= x + 1; i++)
{
int j = 0;
for (j = y - 1; j <= y + 1; j++)
{
Judge(arr2, arr1, i, j);
}
}
}
else
{
return;
}
}
}
void Out_lei(char arr2[ROWS][LOWS], int row, int low, char arr1[ROWS][LOWS])
{
int x = 0;
int y = 0;
while (1)
{
printf("请输入坐标:>");
scanf("%d,%d", &x, &y);
if (x >= 1 && x <= ROW && y >= 1 && y <= LOW)
{
if (arr1[x][y] == '1')
{
arr2[x][y] = '#';
displayboard(arr2, ROW, LOW);//排雷
printf("遗憾你输了\n");
break;
}
else
{
Judge(arr2, arr1, x, y);
displayboard(arr2, ROW, LOW);//排雷
}
}
else
{
printf("输入错误!\n");
}
//判断扫雷是否赢
int i = 0, flag = 0;
for (i = 1; i <= ROW; i++)
{
int j = 0;
for (j = 1; j <= LOW; j++)
{
if (arr2[i][j] != '*')
{
flag++;
}
}
}
if (flag == ROW*LOW - LEI)
{
printf("你赢了!\n");
break;
}
}
}
game.h实现
#pragma once
#include <stdio.h>
#include <stdlib.h>
#define LEI 10
#define ROW 10
#define LOW 10
#define ROWS ROW+2
#define LOWS LOW+2
//初始化棋盘
void board(char arr1[ROWS][LOWS],int rows,int lows,char ret);
//打印棋盘
void displayboard(char arr1[ROWS][LOWS], int row, int low);
//布置雷
void Get_lei(char arr1[ROWS][LOWS], int row, int low);
//玩家盘
void Out_lei(char arr2[ROWS][LOWS], int row, int low, char arr1[ROWS][LOWS]);
递归部分详解
递归条件:1.有停止的条件。2.每一次递归都会向这个条件靠拢。
那么这里的停止条件是什么呢?
递归:当返回雷的个数为0时,就符合继续递归的条件,我们需要将当前坐标周围的点全部排除。且需要将已经排查了的坐标做一个标记,否则就会不停的排查下去,就会形成死递归。所以
停止条件:当前这个坐标是已被排查过的,就停止递归。
因为每一次排查都会的一个标记,所以这就是那个不断向停止条件靠拢的过程。
//判断是否展开,实现函数
static void Judge(char arr2[ROWS][LOWS], char arr1[ROWS][LOWS], int x, int y)
{
if (x > 0 && x <= ROW && y > 0 && y <= LOW)
{
int ret = Get_num(arr1, x, y);
if (ret != 0)
arr2[x][y] = ret + '0';
//递归散开
else if (arr1[x][y] != ' ')
{
arr2[x][y] = '0';//玩家盘
arr1[x][y] = ' ';//雷盘
int i = 0;
for (i = x - 1; i <= x + 1; i++)
{
int j = 0;
for (j = y - 1; j <= y + 1; j++)
{
Judge(arr2, arr1, i, j);
}
}
}
else
{
return;
}
}
}
总结
到此这篇关于C语言实现递归版扫雷游戏实例的文章就介绍到这了,更多相关C语言递归版扫雷内容请搜索软件开发网以前的文章或继续浏览下面的相关文章希望大家以后多多支持软件开发网!