栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

扫雷游戏(可展开,可标记)C语言实现

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

扫雷游戏(可展开,可标记)C语言实现

扫雷

实现原理实现过程

1.菜单2.初始化3.打印4.埋雷5.排雷6.坐标周围雷的数量7.标记雷

标记取消标记 8.展开非雷区9.游戏函数 总代码

game.hgame.ctest.c

实现原理

用两个二维数组,
一个用来存放雷的排布(相当于系统游戏数据)mine数组
一个用来展示(给人们看到的界面) show数组
产生随机n个坐标存放到mine数组,当做雷
由玩家输入二维数组的坐标,来实现排雷
全部雷找到,玩家胜利
碰到雷,游戏结束

实现过程 1.菜单

这就是一个人机交互的过程,也可以说是UI界面,一个好的菜单才能给玩游戏的玩家 有一个良好的体验
最简单的写法就是

void menu()
{
	printf("***********************n");
	printf("******** 1.Play *******n");
	printf("******** 0.Exit *******n");
	printf("***********************n");
}

是不是简单明了啊

这个可以按照大家自己的喜好来,每个人搞的UI都应该有个人的特点

2.初始化

和井字棋一样,扫雷也有初始的界面,因此我们也要对mine和show数组初始化

//初始化
void Init_Board(char arr[ROWS][COLS], int rows, int cols, char set)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < rows; i++)
	{
		for (j = 0; j < cols; j++)
		{
			arr[i][j] = set;
		}
	}
}

这和井字棋的初始化有略微的差异,井字棋的初始化只需要初始化一个数组,传入的形参就只需要arr数组、行、列,
但是,扫雷要初始化两个数组,两个数组的初始化内容不一样,因此我们再加入一个形参set,将要初始化的内容传给set

//埋雷数组
	char mine[ROWS][COLS];
	//展示数组
	char show[ROWS][COLS];

	//初始化数组
	Init_Board(mine, ROWS, COLS, '0');
	Init_Board(show, ROWS, COLS, '*');
3.打印

一开始我们写代码时,要将mine和show数组打印来看,所以形参用的arr
打印的界面也可以根据自己的喜好来创造

//打印
void Show_Board(char arr[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	printf("-------扫雷--------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");
	}
	printf("-------扫雷--------n");
}
4.埋雷

利用srand和rand函数产生n个随机坐标,来埋雷
注意,count–一定是在if里面的,只有埋雷成功,count才递减,所以循环次数是可能大于n的

//埋雷
void Set_Mine(char arr[ROWS][COLS], int row, int col)
{
	int count = EASY_COUNT;
	int x = 0;
	int y = 0;
	while (count)
	{
		x = rand() % row + 1;
		y = rand() % col + 1;
		if (arr[x][y] == '0')
		{
			arr[x][y] = '1';
			count--;
		}
		
	}
}
5.排雷

玩家输入排查的坐标,不是雷,游戏继续,是雷游戏结束

//排查雷
void Find_Mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;
	while (win < row * col - EASY_COUNT)
	{
		
			printf("请输入要排查的坐标:>");
			scanf("%d %d", &x, &y);
			fflush(stdin);
			if (x >= 1 && x <= row && y >= 1 && y <= col)
			{
				if (mine[x][y] == '1')
				{
					printf("很遗憾,被炸死了n");
					Show_Board(mine, ROW, COL);
					break;
				}
				else
				{
					Unfold_NoMine(mine, show, x, y);
					win++;
					Show_Board(show, ROW, COL);
				}
			}
			else
			{
				printf("坐标非法,请重新输入:n");
			}

	}
	if (win == row * col - EASY_COUNT)
	{
		printf("恭喜你,排雷成功!n");
	}
}
6.坐标周围雷的数量

排雷过程中,如果该坐标不是雷,那么我们要将在3*3的范围内看有几个雷,将雷的个数展示出来

//雷的个数
int Get_Mine_Count(char mine[ROWS][COLS], int x, int y)
{
	return mine[x-1][y] +
		mine[x-1][y-1] + 
		mine[x-1][y+1] + 
		mine[x][y-1] +
		mine[x+1][y] + 
		mine[x+1][y+1] +
		mine[x+1][y-1] + 
		mine[x][y+1]-8*'0';
		
}
7.标记雷

最开始时,我所想的标记是在排雷过程中直接进行,但是输入后会出现死循环,
调试后,发现标记和排雷应该是同步的,所以排雷的逻辑也得改(也就是说,上面的排雷的代码不是最终版,最终版在最后的总代码里)

void Mark_Mine(char show[ROWS][COLS])
{
	fflush(stdin);
	printf("要标记几个坐标:n");
	int count = 0;
	scanf("%d", &count);

	for (int i = 0; i < count; i++)
	{
		int x = 0;
		int y = 0;
		scanf("%d %d", &x, &y);
		show[x][y] = '△';
	}
}

上述代码是错误的逻辑

标记

玩家通过show数组展示出来的的数据,判断哪个坐标是雷,则可以对其进行标记

//标记
void Sign(char show[ROWS][COLS], int x, int y)
{
	if (show[x][y] == '*')
	{
		show[x][y] = '$';
	}
}

取消标记

玩家发现标记错误,则可以取消标记

//取消标记
void UnSign(char show[ROWS][COLS], int x, int y)
{
	if (show[x][y] == '$')
	{
		show[x][y] = '*';
	}
}
8.展开非雷区 4个条件 递归实现 1. 该坐标是否被排过 2. 该坐标周围的3*3范围内是否有雷 3. 该坐标是否是雷 4. 是否到达边界
//展开非雷区
void Unfold_NoMine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
	//判断是否到达边界(上、下、左、右)
	if (x == 0 || y == 0 || x == ROWS - 1 || y == COLS - 1)
	{
		return;
	}
	//判断是否排查过(如果没有被排查过那么,show数组元素的值应该是*)
	if (show[x][y] != '*')
	{
		return;
	}
	//x,y周围的雷数
	int count = Get_Mine_Count(mine, x, y);
	if (count > 0)
	{
		show[x][y] = count + '0';
		return;
	}
	//没有雷就递归展开
	else if(count == 0)
	{
		show[x][y] = '0';
		Unfold_NoMine(mine, show, x - 1, y);
		Unfold_NoMine(mine, show, x - 1, y-1);
		Unfold_NoMine(mine, show, x - 1, y+1);
		Unfold_NoMine(mine, show, x + 1, y-1);
		Unfold_NoMine(mine, show, x + 1, y);
		Unfold_NoMine(mine, show, x + 1, y+1);
		Unfold_NoMine(mine, show, x , y-1);
		Unfold_NoMine(mine, show, x , y+1);
	}
}
9.游戏函数

游戏的进行过程

void game()
{
	
	//埋雷数组
	char mine[ROWS][COLS];
	//展示数组
	char show[ROWS][COLS];

	//初始化数组
	Init_Board(mine, ROWS, COLS, '0');
	Init_Board(show, ROWS, COLS, '*');

	//埋雷
	Set_Mine(mine, ROW, COL);

	//打印
	//Show_Board(mine, ROW, COL);
	Show_Board(show, ROW, COL);

	//排查雷
	Find_Mine(mine,show, ROW, COL);
}

总代码 game.h
#pragma once

#define ROW 9
#define COL 9

#define ROWS ROW+2
#define COLS COL+2

#define EASY_COUNT 10

#include
#include
#include
#include

//初始化数组
void Init_Board(char arr[ROWS][COLS],int rows,int cols,char set);

//打印
void Show_Board(char arr[ROWS][COLS], int row, int col);

//埋雷
void Set_Mine(char arr[ROWS][COLS], int row, int col);

//排查雷
void Find_Mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

//雷的个数
int Get_Mine_Count(char mine[ROWS][COLS],int x,int y);

//标记
void Mark_Mine(char show[ROWS][COLS]);

//展开非雷区
void Unfold_NoMine(char mine[ROWS][COLS], char[ROWS][COLS], int x, int y);

//标记
void Sign(char show[ROWS][COLS],int x,int y);

//取消标记
void UnSign(char show[ROWS][COLS], int x, int y);
game.c
#define _CRT_SECURE_NO_WARNINGS 1


#include"game.h"

//初始化
void Init_Board(char arr[ROWS][COLS], int rows, int cols, char set)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < rows; i++)
	{
		for (j = 0; j < cols; j++)
		{
			arr[i][j] = set;
		}
	}
}


//打印
void Show_Board(char arr[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	printf("-------扫雷--------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");
	}
	printf("-------扫雷--------n");
}

//埋雷
void Set_Mine(char arr[ROWS][COLS], int row, int col)
{
	int count = EASY_COUNT;
	int x = 0;
	int y = 0;
	while (count)
	{
		x = rand() % row + 1;
		y = rand() % col + 1;
		if (arr[x][y] == '0')
		{
			arr[x][y] = '1';
			count--;
		}
		
	}
}

//雷的个数
int Get_Mine_Count(char mine[ROWS][COLS], int x, int y)
{
	return mine[x-1][y] +
		mine[x-1][y-1] + 
		mine[x-1][y+1] + 
		mine[x][y-1] +
		mine[x+1][y] + 
		mine[x+1][y+1] +
		mine[x+1][y-1] + 
		mine[x][y+1]-8*'0';
		
}

//排查雷
void Find_Mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;
	while (win");
			scanf("%d %d", &x, &y);
			fflush(stdin);
			if (x >= 1 && x <= row && y >= 1 && y <= col)
			{
				if (mine[x][y] == '1')
				{
					printf("很遗憾,被炸死了n");
					Show_Board(mine, ROW, COL);
					break;
				}
				else
				{
					Unfold_NoMine(mine, show, x, y);
					win++;
					Show_Board(show, ROW, COL);
				}
			}
			else
			{
				printf("坐标非法,请重新输入:n");
			}
		}
		else if (num == 2)
		{
			printf("请输入坐标:n");
			scanf("%d %d", &x, &y);
			fflush(stdin);
			Sign(show, x, y);
			Show_Board(show, ROW, COL);
		}
		else if (num == 3)
		{
			printf("请输入坐标:n");
			scanf("%d %d", &x, &y);
			fflush(stdin);
			UnSign(show, x, y);
			Show_Board(show, ROW, COL);
		}
		else if(num == 4)
		{
			return;
		}
		
		
	}
	if (win == row * col - EASY_COUNT)
	{
		printf("恭喜你,排雷成功!n");
	}
}


void Mark_Mine(char show[ROWS][COLS])
{
	fflush(stdin);
	printf("要标记几个坐标:n");
	int count = 0;
	scanf("%d", &count);

	for (int i = 0; i < count; i++)
	{
		int x = 0;
		int y = 0;
		scanf("%d %d", &x, &y);
		show[x][y] = '△';
	}
}

//展开非雷区
void Unfold_NoMine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
	//判断是否到达边界(上、下、左、右)
	if (x == 0 || y == 0 || x == ROWS - 1 || y == COLS - 1)
	{
		return;
	}
	//判断是否排查过(如果没有被排查过那么,show数组元素的值应该是*)
	if (show[x][y] != '*')
	{
		return;
	}
	//x,y周围的雷数
	int count = Get_Mine_Count(mine, x, y);
	if (count > 0)
	{
		show[x][y] = count + '0';
		return;
	}
	//没有雷就递归展开
	else if(count == 0)
	{
		show[x][y] = '0';
		Unfold_NoMine(mine, show, x - 1, y);
		Unfold_NoMine(mine, show, x - 1, y-1);
		Unfold_NoMine(mine, show, x - 1, y+1);
		Unfold_NoMine(mine, show, x + 1, y-1);
		Unfold_NoMine(mine, show, x + 1, y);
		Unfold_NoMine(mine, show, x + 1, y+1);
		Unfold_NoMine(mine, show, x , y-1);
		Unfold_NoMine(mine, show, x , y+1);
	}
}

//标记
void Sign(char show[ROWS][COLS], int x, int y)
{
	if (show[x][y] == '*')
	{
		show[x][y] = '$';
	}
}

//取消标记
void UnSign(char show[ROWS][COLS], int x, int y)
{
	if (show[x][y] == '$')
	{
		show[x][y] = '*';
	}
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1


#include"game.h"

void menu()
{
	printf("***********************n");
	printf("******** 1.Play *******n");
	printf("******** 0.Exit *******n");
	printf("***********************n");
}


void game()
{
	
	//埋雷数组
	char mine[ROWS][COLS];
	//展示数组
	char show[ROWS][COLS];

	//初始化数组
	Init_Board(mine, ROWS, COLS, '0');
	Init_Board(show, ROWS, COLS, '*');

	//埋雷
	Set_Mine(mine, ROW, COL);

	//打印
	//Show_Board(mine, ROW, COL);
	Show_Board(show, ROW, COL);

	//排查雷
	Find_Mine(mine,show, ROW, COL);
}


int main()
{
	srand((unsigned int)time(NULL));
	int input = 0;
	do
	{
		menu();
		printf("请输入>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			exit(0);
			break;
		default:
			printf("请重新输入n");
			break;
		}
	} while (input);
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/713741.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号