扫雷游戏---C语言讲解(超详细,一看就会)

本文详细介绍了Windows扫雷游戏的起源、游戏逻辑分析,包括菜单设计、二维数组的使用、雷的随机设定、玩家操作的实现以及代码结构的划分。着重展示了如何通过函数封装和随机数生成实现游戏的核心功能。
摘要由CSDN通过智能技术生成

一:扫雷游戏的简介

        扫雷游戏起源于1973年的”方块"游戏。1992年微软发布的Windows 3.1中加入该游戏,从此风靡全世界。玩扫雷游戏,可以锻炼观察和推理能力,培养细心和耐心。

        游戏目标是在最短时间根据点击各自出现的数字找出所有非雷格子,并且避免踩到雷,否则就满盘皆输。

二:扫雷游戏的分析

        因为一个游戏往往需要多层次代码来描述,书写。即须将纯粹实现游戏的代码放入一个或多个函数。将游戏的各个功能封装成一个个函数,分层次来写代码。

        第一:每个游戏都应该需要一个菜单,可以通过菜单给出选项供我们选择,例:输入 1 就进入游戏,输入 0 就退出游戏,等。

        第二:首先这里的 进入游戏 指是进入一个游戏函数代码框架,在这一游戏函数框架里书写实现一个或多个游戏功能的函数。

        第三:因为扫雷的大致框架就是一个 9*9 的二维数组,当点击一个格子后,若此坐标不是雷,则就出现此坐标周围的雷的个数,例:

        第四:我们需要给该二维数组给出10(可改变)个雷。

        第五:给出雷后就得进行游戏了,通过输入一个个坐标来判断周围雷的个数完成游戏。

        第六:若我们要实现这个游戏,为了描述这一游戏,重点就是必须得需要两个 9*9 的二维数组,一个数组主要作用是展现给玩家的面板,另一个数组主要作用是对某一坐标周围的雷进行计数,并将计算出的雷的个数返回给第一个二维数组的某坐标位置。这一过程就是点击格子返回数字的过程。

三:扫雷游戏的实现思路讲解

        首先第一步就必须要意识到要将游戏代码分为3步,至于为什么,我以前写的博文已经描述很清楚了,大家可以去看一下。

        三步的实现:

                1. game.h

                2. game.c

                3. test.c

        2.1.扫雷游戏的菜单

void menu()
{
	printf("*************************************************\n");
	printf("************* 1.play   0.exit *******************\n");
	printf("*************************************************\n");
}

                 在打印出菜单(1.play  0.exit)之后,该程序就会让我们输入一个数字(1/0),若玩家输入1,则就通过 switch 语句进行选择(game函数:实现游戏的具体过程步骤),若玩家输入 0,则就退出游戏。若输入其他数字,则提示用户“输入错误,请重新输入”,然后通过 do..while 循环再次让用户进行输入。并且还通过 do...while 循环进行多次的玩扫雷游戏,直到玩家不想再玩后输入 0 结束菜单。

void menu()
{
	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:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (input);
	return 0;
}

        2.2.对扫雷游戏的扫雷盘进行初始化

初始化之前我们先看一下扫雷盘一些特殊的坐标:

因为这些特殊的坐标,当点击这些格子时,因为要计算周围的雷的个数,遍历这一格子周围的格子,则可能会遇到数组越界,那该怎样做呢?我们就干脆建立一个 11*11 的二维数组,为了方便以后管理数组代码,我们这样定义:


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

再用一个 InitBoard 的函数对两个11*11 的二维数组扫雷盘进行初始化: 

// 初始化棋盘
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;
		}
	}
}

其中 ret 为任意字符,这就给了程序员更大的发挥空间,不过在这里我们将两个二维数组分别初始化为 '0' 和 ' * '  :

	char mine[ROWS][COLS] = {0};
	char show[ROWS][ROWS] = {0};

        2.3.对扫雷盘进行打印

之后我们对扫雷盘进行打印,使用 for 循环进行期盼的打印操作,当然这一功能也得需要一个函数(DisplayBoard函数)对这一功能进行封装:

// 打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	for (i = 0; i <= col; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	printf("  ");
	for (i = 1; i <= row; i++)
	{
		if (i == row)
			printf("-");
		else
			printf("--");
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d|", i);
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
}

对两个二维数组打印结果:

        2.4.设置雷的位置(随机的)

因为需要我们玩家进行扫雷,在此之前我们并不知道雷的位置在哪里,所以设置雷的时候应该是随机不确定的,这时就得使用到 rand 函数生成随机数字来实现这个操作,使用 setBoard函数来实现这一功能。

// 设置雷-- 10个雷
void SetBoard(char board[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int i = 10;
	while (i)
	{
		x = rand() % 9 + 1;
		y = rand() % 9 + 1;
		if (board[x][y] == '0')
		{
			board[x][y] = '1';    // *重点,方便之后计算周围雷的数目*
			i--;
		}
	}
}

注意:在使用 rand 函数之前,就得使用到 sand 及时间戳,并且包含两个库函数(<stdlib.h> and <time.h>)此时主函数就得改为:

#include<time.h>
#include<stdlib.h>


int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();
		printf("请输入:> ");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (input);
	return 0;
}

打印结果实例:

        2.5.玩家操作,进行扫雷游戏

同样的,我们也可以自定义一个函数(SearchBoard函数)来进行排雷操作,当然若是点击到雷的话,则游戏结束;若是没有,则就在原来的坐标上返回周围雷的个数,为了使得代码的可读性更高,就再次封装成一个函数(L_count函数)来计算周围雷的个数。

int L_count(char board1[ROWS][COLS], int x, int y)
{
	return (board1[x - 1][y - 1] + board1[x - 1][y + 1] + board1[x - 1][y] + board1[x][y - 1] + board1[x][y + 1] +
		board1[x + 1][y - 1] + board1[x + 1][y] + board1[x + 1][y + 1] -8* '0');
}

而 SearchBoard函数如下:


void SearchBoard(char board[ROWS][COLS], char board1[ROWS][COLS], int row, int col, char ret)
{
	int x = 0;
	int y = 0;
	int i = 0;
	while (i < row * col - LEI)
	{
		printf("请输入要排查雷的坐标:> ");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (board1[x][y] == '1')
			{
				printf("很遗憾,你被炸死了\n");
				printf("雷的布局是:> \n");
				DisplayBoard(board1, ROW, COL);
				return;
			}
			else
			{
				if (board[x][y] == ret)
				{
					int r = L_count(board1, x, y) ;
					board[x][y] = r+ '0';
					i++;
					DisplayBoard(board, ROW, COL);
				}
				else
				{
					printf("此坐标已被排过,请重新输入\n");
				}
			}
		}
		else
		{
			printf("输入坐标错误,请重新输入\n");
		}
	}
	if (i == row * col - LEI)
		printf("恭喜你,排雷成功了\n");
}

此处的LEI指的是雷的个数,这是用 #define 定义的,使得整个代码有了更高的广泛性。 

四:扫雷游戏完整代码以及运行结果

1. game.h

#pragma once


#include<stdio.h>
#include<time.h>
#include<stdlib.h>


#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define LEI 10

// 初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char ret);

// 打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col);

// 设置雷
void SetBoard(char board[ROWS][COLS], int row, int col);

// 排查雷
void SearchBoard(char board[ROWS][COLS], char board1[ROWS][COLS], int row, int col, char ret);

2. game.c

#define _CRT_SECURE_NO_WARNINGS

// 扫雷游戏函数的实现

#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;
	for (i = 0; i <= col; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	printf("  ");
	for (i = 1; i <= row; i++)
	{
		if (i == row)
			printf("-");
		else
			printf("--");
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d|", i);
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
}


// 设置雷-- 10个雷
void SetBoard(char board[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int i = 10;
	while (i)
	{
		x = rand() % 9 + 1;
		y = rand() % 9 + 1;
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			i--;
		}
	}
}

// 排查雷

int L_count(char board1[ROWS][COLS], int x, int y)
{
	return (board1[x - 1][y - 1] + board1[x - 1][y + 1] + board1[x - 1][y] + board1[x][y - 1] + board1[x][y + 1] +
		board1[x + 1][y - 1] + board1[x + 1][y] + board1[x + 1][y + 1] -8* '0');
}

void SearchBoard(char board[ROWS][COLS], char board1[ROWS][COLS], int row, int col, char ret)
{
	int x = 0;
	int y = 0;
	int i = 0;
	while (i < row * col - LEI)
	{
		printf("请输入要排查雷的坐标:> ");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (board1[x][y] == '1')
			{
				printf("很遗憾,你被炸死了\n");
				printf("雷的布局是:> ");
				DisplayBoard(board1, ROW, COL);
				return;
			}
			else
			{
				if (board[x][y] == ret)
				{
					int r = L_count(board1, x, y) ;
					board[x][y] = r+ '0';
					i++;
					DisplayBoard(board, ROW, COL);
				}
				else
				{
					printf("此坐标已被排过,请重新输入\n");
				}
			}
		}
		else
		{
			printf("输入坐标错误,请重新输入\n");
		}
	}
	if (i == row * col - LEI)
		printf("恭喜你,排雷成功了\n");
}

3. test.c

#define _CRT_SECURE_NO_WARNINGS

// 扫雷游戏

#include "game.h"

void menu()
{
	printf("*************************************************\n");
	printf("************* 1.play   0.exit *******************\n");
	printf("*************************************************\n");
}

void game()
{
	char mine[ROWS][COLS] = {0};
	char show[ROWS][ROWS] = {0};

	// 初始化棋盘
	InitBoard(mine, ROWS, COLS, '0');
	InitBoard(show, ROWS, COLS, '*');

	// 打印棋盘
	DisplayBoard(show, ROW, COL);

	// 设置雷
	SetBoard(mine, ROW, COL);

	// 排查雷
	SearchBoard(show, mine, ROW, COL,'*');

}

int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();
		printf("请输入:> ");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (input);
	return 0;
}

 程序运行实例:

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值