C语言100多行扫雷游戏详解

在这里插入图片描述

文章目录

  • 前言
  • 1. 扫雷规则信息
  • 2. 扫雷整体框架
  • 3. 扫雷代码结构
  • 4. 代码分块解析
    • 4.1 菜单模块
    • 4.2 数据存储模块
    • 4.3 布置雷模块
    • 4.4 排查雷模块
  • 5. 整体代码如下:
  • 6. 总结

前言

1. 扫雷规则信息

此次的扫雷游戏是最简单的等级——【9*9雷盘埋10个雷】。玩家在玩扫雷游戏的时候,会根据输入的坐标进行扫雷。用字符 ‘1’ 表示,不是雷的用字符 ‘0’ 表示。当输入下标,扫到雷之后会被提示踩雷,结束游戏,并展示所有雷的信息。若没踩到雷,会在棋盘上打印出该位置周围8个位置有几个雷,就会继续输入坐标,直到把雷全部找出,才赢。接下来,我来简单说说扫雷的整个框架👇👇👇👇👇。

2. 扫雷整体框架

扫雷嘛,最主要就是用什么存储和怎样生成雷以及如何排查雷。所以,在整个扫雷游戏中,下图四个板块是最主要的。往后会讲到具体代码结构👀👀👀:

在这里插入图片描述

3. 扫雷代码结构

扫雷游戏,用的多文件编写。test_game.c源文件代码,主要是对游戏的测试game.c是对扫雷游戏的函数定义【可以说是功能的具体实现】。game.h头文件就是对数据的宏定义和函数的声明

在这里插入图片描述

4. 代码分块解析

  • 代码块主要分为三大模块:菜单模块数据存储模块布置雷模块排查雷模块。我们娓娓道来👌👌👌👌👇:

4.1 菜单模块

首先,不管玩什么游戏都不是一次就结束了,所以此处一定得用到循环结构,对于菜单,需要玩家选择,所以需要分支结构,再加上打印信息就可以,直接上代码:

void menu()
{
	printf("\t\t\t\t\t***************************\n");
	printf("\t\t\t\t\t********  扫雷游戏  *******\n");
	printf("\t\t\t\t\t***************************\n");
	printf("\t\t\t\t\t********  1 : play  *******\n");
	printf("\t\t\t\t\t********  0 : exit  *******\n");
	printf("\t\t\t\t\t***************************\n");
}

int main()
{
	int input = 0;
	do{
		menu();
		printf("请玩家选择—>:\n");
		scanf_s("%d", &input);
		switch (input)
		{
		case 1:
			//具体游戏实现代码
			break;
		case 0:
			printf("欢迎下次再玩!\n");
			break;
		default:
			printf("输入错误,请重新输入—>:\n");
			break;
		}
	} while (input);
	return 0;
}

运行结果如下👇👇👇👇:
在这里插入图片描述

4.2 数据存储模块

在上面菜单写好后,我们看到输入1之后就还没有信息出来,接下来就是对数据进行存储。对于数据存储模块,就是要考虑该游戏是用什么样的数据结构类型。首先我们先看一下成品扫雷游戏的界面。从下面的图中可以看出,除开棋盘上的数据外,就是一个一个的空格组成的,是9*9的棋盘。我们通过C语言知识的所学,会很快联想到数组,并且是二维数组这样的结构。所以,这个棋盘可以看作是9行9列二维数组
在这里插入图片描述

  1. 既然知道了是用9*9的二维数组来实现的扫雷的,那我们就要对棋盘进行定义了。所以,我们就定义一个二维数组的棋盘,在这里我们为了考虑代码的灵活性,我们对数组定义的时候,不要把数组大小写死,用到宏定义,这样能更灵活。然而,还需要考虑一个问题,就是我们用一个数组到底可不可以???👀👀👀👀。代码如下:
    在这里插入图片描述

布置雷的棋盘用字符 ‘0’ 初始化,显示雷的信息的棋盘用字符 ’*‘ 表示

#define Row 9
#define Col 9

#define Rows Row+2
#define Cols Col+2
//初始化棋盘的函数
void Init_Board(char Board_Mine[Rows][Cols], int rows, int cols, char set)
{
	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			Board_Mine[i][j] = set;
		}
	}
}

//打印棋盘信息的函数
void Print_Mine_Board(char Board_Mine[Rows][Cols], int row, int col)
{
	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 ", Board_Mine[i][j]);
		}
		printf("\n");
	}
}

结果如下【布置雷的棋盘打印出来是看一下初始化成功没有,正式扫雷的时候是不打印出来的】👇👇👇:
在这里插入图片描述

4.3 布置雷模块

我们在上面已经把布置雷的棋盘打印出来后,现在就是需要把雷放在上面。在游戏信息里面说了,用字符 ‘1’ 表示,不是雷用字符 ‘0’ 表示。所以,我们需要在雷棋盘的二维数组中加一些字符 ‘1’ ,为了让雷的位置是随机的,需要用到随机函数来把雷的字符放入二维数组中,接下来直接上代码👉👉👉:

#define Mines 10
//布置雷的函数
void Set_Mines(char Board_Mine[Rows][Cols], int row, int col)
{
	//布置雷的前提就是需要坐标,所以先定义坐标变量。
	int x = 0;
	int y = 0;
	//现在需要雷的数量,为了代码灵活性,就用宏定义来规定雷的数量
	int i = 0;
	while (i < Mines)
	{
		//此处生成坐标就需要用到随机函数,需要时间戳函数,在主函数定义一次就可以了
		x = rand() % row + 1;
		y = rand() % col + 1;
		//此处需要判断,就是看布置的位置是否是0,如果是0就布置在这位置,如果不是0,就说明随机函数生成的坐标把这个位置布置了
		if (Board_Mine[x][y] == '0')
		{
			Board_Mine[x][y] = '1';
			i++;//把i变量的调整放在后面,是为了防止雷的坐标重复,如果重复了就会导致雷的数量减少。
		}
	}
}

4.4 排查雷模块

既然我们把雷埋好以后,就该玩家排雷了吧!💪💪💪🧒。接下来我们需要在显示雷的数量的棋盘上排查,找出排查点周围8个点的雷的数量【下图是计算雷的个数的方法】。所以我们需要用到两个二维数组,把他们关联起来,先看代码👉:

在这里插入图片描述

//计算雷的数量
int GetMinesNumber(char Board_Mine[Rows][Cols], int x, int y)
{
	return Board_Mine[x - 1][y - 1] + Board_Mine[x][y - 1] + Board_Mine[x + 1][y - 1] +
		Board_Mine[x + 1][y] + Board_Mine[x + 1][y + 1] + Board_Mine[x][y + 1] + Board_Mine[x - 1][y + 1] +
		Board_Mine[x - 1][y] - 8 * '0';
 }

//排查雷的函数
void  Find_Mines(char Board_Mine[Rows][Cols], char Show_Mine[Rows][Cols], int row, int col)
{
	//怎么排查呢?当然是输入坐标了,所以得先定义坐标变量
	int x = 0;
	int y = 0;
	//输入坐标吧,由于排雷不可能一次就成功,所以得用循环
	int win = 0;
	while (win<Row*Col-Mines)
	{
		printf("请输入排查坐标—>:\n");
		scanf_s("%d %d", &x, &y);
		//输入过后立马判断合法性
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			//坐标合法后,就得看此坐标位置是否是雷,如果不是雷则计算周围8个位置有多少个雷
			if (Board_Mine[x][y] != '1')
			{
				//判断是否重复输入同一个坐标
				if (Show_Mine[x][y] == '*')
				{
					//计算雷的数量
					int count = GetMinesNumber(Board_Mine,x,y);
					//显示在另外一个棋盘上,先把返回来的数量赋值给另外个数组,由于返回的是整型,需要转为字符型,直接加上个字符0
					Show_Mine[x][y] = count + '0';
					//打印出来
					Print_Mine_Board(Show_Mine, Row, Col);
					win++;
				}
				else
				{
					printf("已经排查过了\n");
				}	
			}
			else
			{
				printf("很遗憾!你被炸死了!\n");
				Print_Mine_Board(Board_Mine, Row, Col);
				break;
			}
		}
		else
		{
			printf("输入坐标不合法!请重新输入->:\n");
		}
	}
	if (win == row * col - Mines)
	{
		printf("恭喜你!排雷成功!\n");
		Print_Mine_Board(Board_Mine, Row, Col);
	}
	
}

注意这种情况:
就这下面是正确的。在这里插入图片描述

写成下面这种会出现乱码:
在这里插入图片描述

写错后会出现下面错误结果👇👇👇:
在这里插入图片描述


5. 整体代码如下:

1.主函数文件 test_game.c

#include"game.h"
void menu()
{
	printf("\t\t\t\t\t***************************\n");
	printf("\t\t\t\t\t********  扫雷游戏  *******\n");
	printf("\t\t\t\t\t***************************\n");
	printf("\t\t\t\t\t********  1 : play  *******\n");
	printf("\t\t\t\t\t********  0 : exit  *******\n");
	printf("\t\t\t\t\t***************************\n");
}

void game()
{
	char Mine[Rows][Cols] = { 0 };//布置雷的棋盘。
	char Show[Rows][Cols] = { 0 };//显示雷的信息。
	//初始化棋盘
	Init_Board(Mine, Rows, Cols, '0');
	Init_Board(Show, Rows, Cols, '*');


	//打印棋盘
	//Print_Mine_Board(Mine,Row,Col);
	//printf("\n");
	Print_Mine_Board(Show,Row,Col);

	//布置雷
	Set_Mines(Mine, Row, Col);
	//布置好雷后,打印看看是否成功
	//Print_Mine_Board(Mine, Row, Col);

	//排查雷
	Find_Mines(Mine,Show, Row, Col);

}

int main()
{
	srand((unsigned int)time(NULL));
	int input = 0;
	do{
		menu();
		printf("请玩家选择—>:\n");
		scanf_s("%d", &input);
		switch (input)
		{
		case 1:
			//具体游戏实现代码
			game();
			break;
		case 0:
			printf("欢迎下次再玩!\n");
			break;
		default:
			printf("输入错误,请重新输入—>:\n");
			break;
		}
	} while (input);
	return 0;
}

2.game.c 函数具体实现文件

#include"game.h"

//初始化棋盘函数
void Init_Board(char Board_Mine[Rows][Cols], int rows, int cols, char set)
{
	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			Board_Mine[i][j] = set;
		}
	}
}

//打印棋盘函数
void Print_Mine_Board(char Board_Mine[Rows][Cols], int row, int col)
{
	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 ", Board_Mine[i][j]);
		}
		printf("\n");
	}
}

//布置雷的函数
void Set_Mines(char Board_Mine[Rows][Cols], int row, int col)
{
	//布置雷的前提就是需要坐标,所以先定义坐标变量。
	int x = 0;
	int y = 0;
	//现在需要雷的数量,为了代码灵活性,就用宏定义来规定雷的数量
	int i = 0;
	while (i < Mines)
	{
		
		//此处生成坐标就需要用到随机函数,需要时间戳函数,在主函数定义一次就可以了
		x = rand() % row + 1;
		y = rand() % col + 1;
		//此处需要判断,就是看布置的位置是否是0,如果是0就布置在这位置,如果不是0,就说明随机函数生成的坐标把这个位置布置了
		if (Board_Mine[x][y] == '0')
		{
			Board_Mine[x][y] = '1';
			i++;//把i变量的调整放在后面,是为了防止雷的坐标重复,如果重复了就会导致雷的数量减少。

		}
		
	}
}

//计算雷的数量
int GetMinesNumber(char Board_Mine[Rows][Cols], int x, int y)
{
	return Board_Mine[x - 1][y - 1] + Board_Mine[x][y - 1] + Board_Mine[x + 1][y - 1] +
		Board_Mine[x + 1][y] + Board_Mine[x + 1][y + 1] + Board_Mine[x][y + 1] + Board_Mine[x - 1][y + 1] +
		Board_Mine[x - 1][y] - 8 * '0';
 }

//排查雷的函数
void  Find_Mines(char Board_Mine[Rows][Cols], char Show_Mine[Rows][Cols], int row, int col)
{
	//怎么排查呢?当然是输入坐标了,所以得先定义坐标变量
	int x = 0;
	int y = 0;
	//输入坐标吧,由于排雷不可能一次就成功,所以得用循环
	int win = 0;
	while (win<Row*Col-Mines)
	{
		printf("请输入排查坐标—>:\n");
		scanf_s("%d %d", &x, &y);
		//输入过后立马判断合法性
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			//坐标合法后,就得看此坐标位置是否是雷,如果不是雷则计算周围8个位置有多少个雷
			if (Board_Mine[x][y] != '1')
			{
				//判断是否重复输入同一个坐标
				if (Show_Mine[x][y] == '*')
				{
					//计算雷的数量
					int count = GetMinesNumber(Board_Mine,x,y);
					//显示在另外一个棋盘上,先把返回来的数量赋值给另外个数组,由于返回的是整型,需要转为字符型,直接加上个字符0
					Show_Mine[x][y] = count + '0';
					//打印出来
					Print_Mine_Board(Show_Mine, Row, Col);
					win++;
				}
				else
				{
					printf("已经排查过了\n");
				}	
			}
			else
			{
				printf("很遗憾!你被炸死了!\n");
				Print_Mine_Board(Board_Mine, Row, Col);
				break;
			}
		}
		else
		{
			printf("输入坐标不合法!请重新输入->:\n");
		}
	}
	if (win == row * col - Mines)
	{
		printf("恭喜你!排雷成功!\n");
		Print_Mine_Board(Board_Mine, Row, Col);
	}
	
}
  1. game.h 函数定义文件
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>

#define Row 9
#define Col 9

#define Rows Row+2
#define Cols Col+2

#define Mines 10

//初始化棋盘函数
void Init_Board(char Board_Mine[Rows][Cols], int row, int col, char set);

//打印棋盘函数
void Print_Mine_Board(char Board_Mine[Rows][Cols], int row, int col);

//布置雷的函数
void Set_Mines(char Board_Mine[Rows][Cols], int row, int col);

//计算雷的数量
int GetMinesNumber(char Board_Mine[Rows][Cols], int row, int col);

//排查雷的函数
void  Find_Mines(char Board_Mine[Rows][Cols], char Show_Mine[Rows][Cols], int row, int col);

6. 总结

以上是整个游戏代码,通过简单的扫雷游戏,可以加深对数组、函数、游戏设计思路的理解和使用。如果代码和描述有误的地方,请各位大佬指正。谢谢。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值