C语言学习(10)-- 扫雷游戏讲解+程序

本文详细介绍了扫雷游戏的实现过程,包括创建棋盘、设置雷点、扫雷逻辑以及使用ASCII码计算周围雷点数。游戏的核心是通过递归展开无雷区域,并利用随机函数生成雷的位置。当所有非雷格子都被安全标记时,玩家获胜。

扫雷游戏大家都耳熟能详,描述一下主要功能:在棋盘中埋着已知的雷数。选择坐标后,会返回该坐标周围的雷点个数。根据提示的雷点个数,进行扫雷,争取获得游戏的胜利。

分析:首先要有一个棋盘,在这个棋盘中需要提前设置一定个数的雷。具体分析如下图

1.打印棋盘。我们需要两个二维数组,一个二维数组用来布置雷的位置,有一个二维数组用来显示我们排查雷的位置。映入眼帘的是9*9的棋盘,但是考虑到扫雷时需要反映出周围雷的个数,于是就存在越界的情况。解决方法:上下左右各加一行棋格。此时棋盘格为11*11,实际上只显示9*9即可。

void DisplayBoard(char board[ROWS][COLS],int row,int col)
{
    color(7);
    int i = 0;
    int j = 0;
    //打印列号
    for ( i = 0; i <= col; i++)
    {
        printf("%d ",i);
    }
    printf("\n");
    for ( i = 0; i <= col; i++)
    {
        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");
    }
    color(6);
	printf("\n-----扫雷游戏------\n");
}

2.设置雷。规定雷为1,非雷为0。用到随机函数在前面文章中都有讲过,不清楚的同学可以往前回顾一下。需要注意的就是随机函数所调用的头文件,以及此处随机函数所用的范围。

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

3.扫雷。过程:首先要输入一个坐标,于是需要判断这个坐标是否合法,如果不合法就重新输入,如果合法就要在该位置上显示周围雷的个数。如果周围雷数为0,就需要依次展开,这里需要用到递归。

get_mine_count()中为什么要-8*‘0’:当我们排查雷的信息时,需要显示目标位置周围雷的数量,而字符’0’的ASCII码是48,字符‘1’的ASCII码是49,我们把目标位置周围的坐标加起来然后减去字符‘0’x8,就得到了该目标位置雷的数量,然后把该字符数量显示到show数组中。

排雷成功:假设一共有10个雷,一共有9*9=81个格子,那如果我们一次雷都没有踩到并且全部格子都走完,我们就获胜。即9*9-雷数 = 所走的格子数,就胜利;如果9*9-雷数 > 所走的格子数,说明还没有走完,继续进行。

//获得坐标周围雷的个数
int get_mine_count(char mine[ROWS][COLS],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 Fide_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);
        //判断x,y的合法性
        if (x >=1 && x <= row && y >= 1 && y <= col)
        {
            //踩雷
            if (mine[x][y] == '1')
            {
                color(4); 
                printf("很遗憾,你被炸死了\n");
                DisplayBoard(mine,row,col);
                break;
            }
            //不是雷
            else{
                Unfold(mine, show, x, y);
                DisplayBoard(show,row,col);
                win ++;
            }
        }else
        {
            printf("输入坐标非法,请重新输入!\n");
        }
    }
    if (win == row*col-EASY_COUNT)
    {
        printf("恭喜你,排雷成功!\n");
        DisplayBoard(mine,row,col);
    }
}

展开的条件: 

  • 在坐标x,y处不为雷:mine[x][y] != 1(也就是踩雷的情况)
  • x,y没有越界(实际已经判断是否合法)
  • 在坐标x,y周围没有雷,get_mine_count == 0
  • 递归条件:查看该位置是否被排查过,如果被排查过就跳出。
//展开
void Unfold(char mine[ROWS][COLS],char show[ROWS][COLS],int x, int y)
{
	//判断是否排查过(如果没有被排查过那么,show数组元素的值应该是*)
	if (show[x][y] != '*')
	{
		return;
	}
	//x,y周围的雷数
    int count = get_mine_count(mine,x,y);
	if (count > 0)
	{
		show[x][y] = count + '0'; // 必须得是count + '0' 这样才是字符类型;
        return ;
	}else if (count == 0)
    {
        show[x][y] = ' ';
        //循环遍历x,y周围的八个位置
		Unfold(mine, show, x - 1, y);
		Unfold(mine, show, x - 1, y-1);
		Unfold(mine, show, x - 1, y+1);
		Unfold(mine, show, x + 1, y-1);
		Unfold(mine, show, x + 1, y);
		Unfold(mine, show, x + 1, y+1);
		Unfold(mine, show, x , y-1);
		Unfold(mine, show, x , y+1);
    }    
}

自定义函数后要进行函数声明。game.h

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


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

#define EASY_COUNT 10

void color(short x);
void InitBoard(char board[ROWS][COLS],int rows,int cols,char set);
void DisplayBoard(char board[ROWS][COLS],int row,int col);
void SetMine(char board[ROWS][COLS],int row,int col);
void Unfold(char mine[ROWS][COLS],char show[ROWS][COLS],int x, int y);
void Fide_mine(char mine[ROWS][COLS],char show[ROWS][COLS],int row,int col);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

贪睡脑子

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

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

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

打赏作者

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

抵扣说明:

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

余额充值