c语言实现简单的扫雷小游戏

前言

  • 扫雷游戏规则

游戏目标 

在不触发地雷的前提下,揭开所有非雷的格子。若成功,则游戏胜利;若踩中雷,则游戏失败

示例说明

1.若揭开某格子后显示 3,表示其周围 8 个格子中有 3 个雷

2.若标记了所有雷的位置,且未触发任何雷,则游戏胜利

如图中红色框框中间的显示的是1,表示其周围 8 个相邻格子 中的地雷数量一共有1个

  • 整体的游戏框架

  • 基本内容 
打印菜单

在编程语言中,我们对main函数最好从简,然后再使用嵌套式的函数,这使得代码简洁易高效。所以我们在main函数中只需要从一个函数入手。

然后再从test函数进行写入

由于打印菜单的界面过于繁琐,不利于代码的简洁美观,所以我们可以把菜单页面放到函数menu中去

进入游戏

  • 核心内容
创建两个数组棋盘

在这里我们需要初始化两个二维数组,一个是含雷的(这个不能被看到),另一个是打印在我们需要看的。

之所以后续定义了ROWS和LISTS,是因为在排雷的过程中,如果遇到周围没有8个相邻格子的情况,我们需要创建一个11x11的二维数组,(这里以9x9的为例)来确保周围都有8个相邻格子的情况,为后续写函数提供便利

对棋盘初始化

为了能更好地能编辑设置二维数组的元素,我们在函数中用变量set来代替手动输入‘0‘和’*‘,这样只需要在调用函数的时候修改,有利于后续的优化修改

二维数组的大小也是一样 故在game.h头文件中定义ROW和LIST,后续想修改二维数组大小只需要修改ROW和LIST即可,注意,要在主函数中要声明#include “game.h”头文件

打印棋盘

打印给我们看的棋盘,我们用一个函数来表达,设置雷的棋盘不能被展示出来

为了更好的确定棋盘内每个元素的坐标,我们可以打印坐标,有利于我们观察

布置雷

布置雷有几个前提

1.布置雷
2.在合法的坐标内
3.设置的点没有雷

4.设置的雷要随机

下面注释掉的这一行是当我们编程的时候,想要确定写的对不对,便可以打印代码出来查看,但实际应用的时候应该注释掉

这里我们用count来保存想要放置雷的个数

x坐标和y坐标要保持在坐标1~9范围内

因为使用rand函数要设置随机值,我们可以依据时刻变化的时间来代值

排查雷

老规矩,还是为排查雷设置一个函数FindMine

排查雷也有几个前提

1.判断坐标的合法性

这时候我们就可以使用if语句

2.确认这个坐标没有被排查过

3.统计周围有几个雷

需要注意打印的2并非是2,而是需要2-‘0’才能得到计算机的2,1也是同理

所以在最后赋值的时候要加上‘0’

我们还要假设一种情况:如果我们设置了80个雷(这里以9x9的棋盘为例,那么一共就有81个格子,当我们排除完所有的未含雷的格子后,程序应该结束,不应该再继续下去,所以我们要设置一个条件循环

源码

game.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 9
#define LIST 9

#define ROWS ROW+2
#define LISTS LIST+2

#define EASY_count 80

//初始化棋盘
void Initboard(char board[ROWS][LISTS], int r, int c , char set);

//打印棋盘
void DisplayedBoard (char board[ROWS][LISTS], int r, int c );

//布置雷
void SetMine(char board[ROWS][LISTS], int r, int c);


//排查雷
void FindMine(char mine[ROWS][LISTS], char show[ROWS][LISTS], int r, int c);

game.c

#include "game.h"

int GetMineCount(char mine[ROWS][LISTS], int x, int y)
{
	return mine[x - 1][y] + mine[x - 1][y - 1] + mine[x][y - 1]
		+ mine[x + 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1] +
		mine[x][y + 1] + mine[x - 1][y + 1] - 8 * '0';
}
void Initboard(char board[ROWS][LISTS], int r, int c,char set)
{
	int i = 0;
	for (i = 0;i <r ;i++)
	{
		int j = 0;
		for (j = 0;j < c;j++)
		{
			board[i][j] = set; 
		}
	}
}

void DisplayedBoard (char board[ROWS][LISTS], int r, int c)
{
	int i = 0;//打印列
	for (i = 0;i <= c;i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1;i <= r;i++)
	{
		int j = 0;//打印行
		printf("%d ", i);
		for (j = 1;j <= c;j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
}

//1.布置雷
//2.在合法的坐标内
//3.设置的点没有雷
void SetMine(char board[ROWS][LISTS], int r, int c)
{
	int count = EASY_count;
	
	while (count)
	{
		int x = rand() % ROW + 1 ;
		int y = rand() % LIST + 1 ;
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			count--;
		}
	}
}
	
void FindMine(char mine[ROWS][LISTS], char show[ROWS][LISTS], int r, int c)
{
	int x = 0;
	int y = 0;
	

	int flag = 0;
	int win = 0;
	while ( win<r*c-EASY_count )
	{	
		printf("输入坐标排查雷\n");	
		scanf_s("%d %d", &x, &y);
		//判断坐标的合法性
		if (x >= 1 && x <= r && y >= 1 && y <= c)
		{
			
			
			if (mine[x][y] == '1')
			{
				printf("失败,雷的位置在\n");
				DisplayedBoard(mine, ROW, LIST);
				flag = 1;
				break;
			}
			else 
			{
				//如果这个坐标没有被排查过
				if (show [x][y] == '*')
				{
					//统计周围有几个雷
					int count = GetMineCount(mine, x, y);
					show[x][y] = count + '0';
					DisplayedBoard(show, ROW, LIST);
					win++;
				}
				else
				{
					printf("此坐标已经被排查过,请重新输入坐标\n");
				}
				
			}
		}
		else
		{
			printf("输入坐标有误,请重新输入\n");
		}
	}
	if (flag != 1)
	{
		printf("排雷成功,游戏胜利\n");
	}
}

main.c

#include "game.h"

void menu()
{
	printf("*****   扫雷游戏   *****\n");
	printf("*****  1.开始游戏  *****\n");
	printf("*****  0.退出游戏  *****\n");
}
void game()
{
	char mine[ROWS][LISTS];
	char show[ROWS][LISTS];
	//初始化棋盘
	Initboard(mine, ROWS, LISTS, '0');//‘0’为雷
	Initboard(show, ROWS, LISTS, '*');//'*''

	DisplayedBoard( show, ROW, LIST );
	//DisplayedBoard( mine, ROW, LIST );

	//布置雷
	SetMine(mine, ROW, LIST);
	//DisplayedBoard( mine, ROW, LIST );

	//排查雷
	FindMine(mine,show,ROW,LIST);
}
void test()
{
	menu();
	int input = 0;
	printf("请输入:");
	

	do {
		scanf_s("%d", &input);
		switch (input)
		{
			case 1:
				srand((unsigned int)(time(NULL)));
				printf("开始游戏\n");
				game();
				break;
			case 0:
				break;
			default :
				printf("输入错误 请重新输入\n");
				break;
		}
	} while (input);
	
}

int main()
{
	test();
	return 0;
}

拓展

1.我们发现这个代码还没有实现周围遇到0个雷的时候能自动向外拓展,直至出现相邻格子有雷的情况才会停止

2.或许我们还能在推断出雷的位置的时候,通过某种功能给有雷的地方做上标记,例如鼠标右键

...

我们可以看后进一步思考看如何做,而不拘泥于这一个简单的功能。

结语

扫雷小游戏是对c语言简单语言的综合性运用,学习并熟练运用其中的知识对提升写代码水平很有帮助。本人花了两天时间才完全自主写出来,其中也遇到许多的困难:比如打印数组时的坐标显示错误,初始化棋盘有问题等等.....学习总是充满坎坷的,但坚持学下去更可贵。

学习过程中不要抄代码,自己写才知道自己出现的错误点在哪里,这样才能反思总结,有所进步。

当秋天的第一片梧桐叶落下时,你会突然发现:那些曾经以为永远跨不过的坎,早已成为身后模糊的风景线。你值得被自己的勇气温柔以待。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值