C语言实现扫雷完整算法详解(附完整代码~)

扫雷游戏是一款经典的益智游戏,玩家需要在一个二维网格中找出所有非雷区域的数字,同时避免踩到地雷。本文将介绍如何设计扫雷游戏,并逐步实现代码。那么如何用C语言实现扫雷呢?学习了二维数组之后,我们可将扫雷的网格区域存储为二维数组,从而使用C语言实现扫雷。

一.算法基本思路


首先,用一个二维数组存储雷的分布,雷的分布在游戏期间从始至终不变,但是我们看不到,我们用一个mine数组将其存储起来。用另一个二维数组存储排查出的雷的信息,在游戏期间展示给玩家,下文称为show数组。

主程序所要实现的主要功能是:1.定义,初始化数组    2.打印数组    3.随机设置雷   4.排查雷。5.计算某个坐标周围雷的个数。6.玩家选择一个坐标后,展开周围坐标直至周围有雷的坐标。

 注意:由于计算一个坐标周围雷的个数时,会计算周围八个坐标中雷的个数之和。因此,为了防止当坐标在边角时,计算周围雷的个数时发生数组越界的现象,mine数组和show数组都应在扫雷盘面的大小基础上各增加两行或两列。

因此,常量定义为:

#define ROW 9//可自由设置,扫雷盘面的行数
#define COL 9//可自由设置,扫雷盘面的列数
 
#define ROWS ROW+2//数组的行数
#define COLS COL+2//数组的列数
 
#define MINE 10//地雷个数,可以自由设置


二.算法详解


1.初始化数组与打印数组


将mine数组中的各元素均初始化为‘0’,将show数组中的各元素均初始化为‘*’,初始化与打印均可以由简单的遍历二维数组实现。

2.设置雷


设置雷可由rand()函数随机生成。

别忘了!使用rand()之前需要调用srand()生成时间戳,使用系统时间初始化!

注意!srand()不能写在随机数生成的循环中,因此可以将srand()放在主函数中,生成一次随机数种子即可。 下图布置了十个雷:


3.排查与标记


在扫雷游戏中,可以通过插小旗标记雷(再次点击取消标记),也可以通过点击方格翻开周围没有雷的区域。接受用户输入,通过分支选择进入标记(若想进入标记,则输入1)或是排查(若想排查,则输入0)。

而标记是有上限的,玩家最多标记个数即为该局游戏中雷的个数。若标记达到上限,玩家只有取消之前的标记才能继续添加标记。

玩家开始游戏时,则进入循环,游戏结束可以跳出循环。跳出循环时,要么是玩家已经展开除雷外的所有区域,游戏成功;要么是玩家踩到了雷,游戏结束。

玩家每排除一个坐标,则会翻开周围所有的安全区域(展开周围坐标直至周围有雷的坐标),这个功能可以findmine,后续讲解。

若坐标的周围有雷,则坐标会显示周围雷的个数,由dis_play函数实现,后续讲解。

4.CountMine函数计算周围雷的个数


一个坐标周围的坐标由八个坐标组成。因此,若该坐标周围有雷,排查该坐标后,该坐标应该显示周围八个坐标中雷的个数之和。

int count_zuo(char mine[Hangs][Lies], int x, int y)

{

    int c = mine[x - 1][y - 1] +

        mine[x - 1][y] +

        mine[x - 1][y + 1] +

        mine[x][y + 1] +

        mine[x][y - 1] +

        mine[x + 1][y - 1] +

        mine[x + 1][y + 1] +

        mine[x + 1][y] - 8 * '0';

        return c;

}
    /*注意:二维数组中所存的值是字符型,通过将周围的八个字符型加起来后减去八个‘0’的ARC2码值将其
    转换为整型*/


 5.display函数递归展开周围所有安全区域


传统的扫雷游戏中,当你点击一个坐标,若该坐标没有雷,则会展开该坐标周围所有的安全区域,直到周围有雷的坐标,上述过程可由递归实现。

1.若该坐标没有雷,则赋值为空格。之后,判断周围八个坐标的周围是否有雷,周围没有雷的坐标同样赋值为空格,周围没有雷的坐标则继续向外展开,直到遇到周围有雷的坐标或达到了扫雷盘面的边缘,则停止递归。

2.若该坐标有雷,则直接赋值为周围雷的个数。

因此,该函数代码如下:

void findmine(char show[Hangs][Lies], char mine[Hangs][Lies], int hang, int lie)

{

    int x, y;

    while (1)

    {

        printf("请输入你想要选择的坐标:");

        scanf("%d %d", &x, &y);

        if (x >= 1 && x <= hang && y >= 1 && y <= lie)

        {

            if (mine[x][y] == '1')

            {

                printf("不好意思,你被炸死了\n");

                dis_play(mine, Hang, Lie);

                break;

            }

            else

            {

                int countt=count_zuo(mine, x,y);

                show[x][y] = countt+'0';

                dis_play(show, Hang, Lie);

            }

        }

        else

        {

            printf("你输入不正确,请重新输入");

        }

    }

}
 

三.完整代码!!!


由于代码很多,为了让代码更加易读、逻辑性更强,将代码分为test.c,game.c,game.h三个文件编写。

1.test.c源文件

#define _CRT_SECURE_NO_WARNINGS

#include "game.h"

void menu()

{

printf("*****************\n");

printf("****1. play ****\n");

printf("****2. exit ****\n");

printf("*****************\n");

}

void game()

{

//排查雷的数组

char mine[Hangs][Lies] = { 0 };

//显示雷的信息数组

char show[Hangs][Lies] = { 0 };//定义两个二维数组

int_board(mine, Hangs, Lies,'0');

int_board(show, Hangs, Lies, '*');//初始化两个数组

//布置雷

setmine(mine, Hang, Lie);

//打印棋盘

dis_play(show, Hang, Lie);

//排查雷

findmine(show,mine, Hang, Lie);

}

void test()

{

int input;

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);

}

int main()

{

test();

return 0;

}

2.game.h头文件

#define _CRT_SECURE_NO_WARNINGS

#include<stdlib.h>

#include<time.h>

#include<stdio.h>

#pragma once

#define Hang 9

#define Lie 9

#define count 10

#define Hangs Hang+2

#define Lies Lie+2

void int_board(char arr[Hangs][Lies],int hangs, int lies, char fu);

void dis_play(char arr[Hangs][Lies], int hang, int lie);

void setmine(char arr[Hangs][Lies], int hang, int lie);

void findmine(char show[Hangs][Lies], char mine[Hangs][Lies], int hang, int lie);


3.game.c源文件
 

#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>

#include "game.h"



void int_board(char arr[Hangs][Lies], int hangs, int lies, char fu)

{

	int i = 0;

	for (i = 0; i <=hangs; i++)

	{

		int j = 0;

		for (j = 0; j <= lies; j++)

		{

			arr[i][j]=fu;

		}

 

	}

}





void dis_play(char arr[Hangs][Lies], int hang, int lie)

{

	int i = 0;

	printf("------扫雷游戏-----\n");

	for (int k = 0; k < 10; k++)

	{

		printf("%d ", k);

	}

	printf("\n");

	for ( i = 1; i <=hang; i++)

	{

		int j = 0;

		printf("%d ", i);

		for (j = 1; j <= lie; j++)

		{

 

			printf("%c ",arr[i][j]);

		}

		printf("\n");

	}

}







void setmine(char arr[Hangs][Lies], int hang, int lie)

{

	int cou = count;

	srand((unsigned int)time(NULL));

	while (cou)

	{

		int x = rand() % hang + 1;

		int y = rand() % lie + 1;

		if (arr[x][y] == '0')

		{

			arr[x][y] = '1';

		}

		cou--;

	}



}





int count_zuo(char mine[Hangs][Lies], int x, int y)

{

	int c = mine[x - 1][y - 1] +

		mine[x - 1][y] +

		mine[x - 1][y + 1] +

		mine[x][y + 1] +

		mine[x][y - 1] +

		mine[x + 1][y - 1] +

		mine[x + 1][y + 1] +

		mine[x + 1][y] - 8 * '0';

		return c;





}



void findmine(char show[Hangs][Lies], char mine[Hangs][Lies], int hang, int lie)

{

	int x, y;

	while (1)

	{

		printf("请输入你想要选择的坐标:");



		scanf("%d %d", &x, &y);

		if (x >= 1 && x <= hang && y >= 1 && y <= lie)

		{

			if (mine[x][y] == '1')

			{

				printf("不好意思,你被炸死了\n");

				dis_play(mine, Hang, Lie);

				break;

			}

			else

			{

				int countt=count_zuo(mine, x,y);

				show[x][y] = countt+'0';

				dis_play(show, Hang, Lie);

			}

		}

		else

		{

			printf("你输入不正确,请重新输入");

		}

	}

}













当然,这个游戏还有很多可以改进的地方,例如添加计时器、增加游戏难度等。但希望这篇文章能帮助你了解扫雷游戏的设计思路和实现过程。

  • 31
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

遇见小皖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值