【C语言】扫雷 <保姆级讲解>

游戏规则:

排出所有不是雷的地方,则赢;如选中了是雷的地方,则会被炸死。
每选中不是雷的地方,则会在该位置显示其周围八个坐标内雷的个数

构思

扫雷需埋雷,但是给用户看到的界面必须保持神秘感,因此需要两个二维数组,且大小完全相同,便于坐标一一对应。根据自己需要设置数组类型,建议两个数组类型设置相同,便于之后的函数调用。

每次登录,首先都得给用户提供开始游戏或退出游戏的窗口,选择后会进入扫雷游戏初始化用户界面的棋盘和布置雷的棋盘(用户不可见)系统布置雷(用户不可见),展示棋盘开始排雷,如果有雷——被炸死,没雷——显示周围雷的数量。

因此通过函数来实现以上标红的功能。并将项目分为三个文件:

main.c: 存放游戏整体逻辑(需包含自定义头文件)

game.c: 定义和实现函数(需包含自定义头文件)

game.h:声明函数,宏定义,所需头文件声明

为了使思路更加清晰和操作方便,我们可以使用XLSX表格来帮助我们分析:

布雷区:

此处我们想要设置的游戏规格是9*9棋盘,但是需要设置成11*11的数组,因为在后面显示非雷处周围雷的个数时,为了防止数组越界,我们需要在周围套上一圈保护层,这同时也使计算雷个数的函数内容更加清晰简洁。

展示区:

主函数

#include "game.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;
}

其中do while循环中的内容很常用,经常出现在三子棋等游戏中(建议熟练掌握) 

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 //此处注意ROWS和COLS的定义,是ROW+2,这样以后要更改游戏规模就可以是改动范围减小,便于代码维护

#define COUNT 10 //设置埋雷的个数

//菜单
void menu();

//进入扫雷游戏
void game();

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

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

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

//计算周围雷的数量
int MineCount(char mine[ROWS][COLS], int x, int y);

//排查雷
void FindMine(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col);


功能函数部分:

菜单:

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

}

游戏接口:

void game()
{
    char mine[ROWS][COLS] = {0};
    char show[ROWS][COLS] = {0};//这里只是一个习惯,不初始化也不影响。
    //初始化布雷区和展示界面
    InitBoard(mine, ROWS, COLS, '0');
    InitBoard(show, ROWS, COLS, '*');

    DisplayBoard(show, ROW, COL);
    //布置雷
    SetMine(mine, ROW, COL);

    //排查雷
    FindMine(show, mine, ROW, COL);

}

初始化棋盘:

注意:初始化棋盘包括后面所有函数,定义的都是11*11的数组

此处,除上条所说以外,还应该初始化11*11二维数组内的每一个元素,以防计算雷的个数时,遇到边缘区域会计算错误。

void InitBoard(char board[ROWS][COLS], int rows, int cols, char ret)
{
    //注意此处初始化两个数组,是按照ROWS*COLS的大小初始化的,这并不影响,因为后面的展示数组只会打印中间的ROW*COL部分
    //之所以必须这样初始化,是为了方便后面计算周围雷个数,可以避免数组越界,也可以避免因周围有一部分什么都没存而计算错误的情况
    int x, y;
    for(x = 0; x < rows; x++)
    {
        for(y = 0; y < cols; y++)
        {
            board[x][y] = ret;
        }
    }

}

展示棋盘:

打印棋盘时,只会打印中间9*9的部分

void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
    int x, y;
    printf("-------扫雷--------\n");//界面优化
    for(x = 0; x <= col; x++)//打印列的坐标,方便玩家输入坐标
    {
        printf("%d ", x);

    }

    printf("\n");
    for(x = 1; x <= row; x++)
    {
        printf("%d ", x);//打印行的坐标,方便玩家输入坐标
        for(y = 1; y <= col; y++)
        {
            printf("%c ", board[x][y]);
        }

        printf("\n");
    }
    printf("\n");//此为美观界面
}

布置雷:

需要用到:rand()函数,且须用srand((unsigned int)time(NULL))进行初始化,以防止伪随机数(即:有规律的随机数)的出现。

rand()%row 表示:产生0 到 row-1之间的数

and()%row+1 表示:产生1 到 row 之间的数

void SetMine(char mine[ROWS][COLS], int row, int col)
{
    int count = 0;

    while(count < COUNT)
    {
        int x = rand()%row + 1;
        int y = rand()%col + 1;

        if(mine[x][y] == '0')//要考虑是否已被占位
        {
            mine[x][y] = '1';
            count++;//用于计数,且一定要放在if语句中,确保一定布置了指定雷的个数
        }


    }
}

排查雷:

void FindMine(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col)
{
    int x;
    int y;
    int count = 0;

    while(count < row*col-COUNT)
    {
        printf("请输入排雷坐标:");
        scanf("%d %d",&x, &y);
        printf("\n");//此为美观界面
        if(x >= 1 && x <= row && y >= 1 && y <= col)
        {
            if(mine[x][y] == '1')
            {
                printf("很遗憾,你被炸死了!\n");
                DisplayBoard(mine, ROW, COL);
                break;
            }
            else
            {
                int c = MineCount(mine,x,y);
                show[x][y] = c + '0';//一个数加上一个字符'0',则会变成‘数’
                DisplayBoard(show, ROW, COL);
                count++;
            }
        }
        else
            printf("坐标非法,请重新输入");
    }

    if(count == row*col - COUNT)
        {
            printf("恭喜你!排雷成功!\n");
            DisplayBoard(mine, ROW, COL);
        }

}

计算周围雷的个数:

int MineCount(char mine[ROWS][COLS], int x, int y)
{

    return
    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] +
    mine[x+1][y+1] - 8*'0';
}

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值