简单实现扫雷游戏!

本来想着可以写出与电脑上扫雷差异不大的东西,但由于技术不精,虽然模拟实现了扫雷,但写出来的东西与真正扫雷还有一定差距,不过这些都不影响整个游戏的体验。话不多说,直入主题:

先附上头文件game.h的代码,在头文件中我定义了游戏界面的大小 R 和 C 。根据游戏的规则,如果输入人一个坐标,那么显示出来的就是这个坐标所在的九宫格的雷数,因此为了方便计算雷数,虽然显示出来的游戏界面是R * C ,但是实际数组的大小为(R + 2) * (C + 2)。如下图:
这里写图片描述
同时,在头文件中声明了定义的所有函数,函数后面的注释对应它们的功能。

#ifndef __GAME_H__
#define __GAME_H__

#define EASY_COUNT 10     //雷数
#define R 9    //行
#define C 9    //列

#define ROWS R + 2
#define COLS C + 2


#include<stdio.h>

void Choose_Menu(int a[ROWS][COLS]);      //选择菜单界面
void Game_Initialize(int a[ROWS][COLS], int row, int col);  //初始化
void Set_Mine(int a[ROWS][COLS], int row, int col);         //布置雷
void Move_Mine(int a[ROWS][COLS], int row, int col, int x, int y);  //移动雷  如果第一次输入的坐标就是雷,则将此处的雷移动至别处,游戏继续。
void Game_Menu_Print(const int a[ROWS][COLS], int row, int col); //游戏中界面输出
void Game_Result_Print(const int a[ROWS][COLS], int row, int col);//游戏结束输出
void Find_Mine(int a[ROWS][COLS], int row, int col); //进行排雷的过程
int Get_Win(const int a[ROWS][COLS], int row, int col);     //判断游戏状态 未点开的坐标数
void Get_Mine(int a[ROWS][COLS], int row, int col);  //计算雷数
void Play_Game(int a[ROWS][COLS]); //游戏开始调用的总函数

#endif //__GAME_H__

下面附上game.c的代码,它是对game.h中函数的实现。
需要特别说明的是:

  • 移动雷函数的作用在于:如果没有移动雷的函数,那么如果在第一次输入坐标时,不幸输入了有雷的坐标,游戏就会立即结束,这样毫无游戏体验。因此,为了提升玩家游戏体验,当第一次输入坐标时,如果输入了有雷的坐标,那么程序就会在后台悄悄地将此处的雷移动至别处。当然这仅限第一次。
  • 由于在计算时,传入的是数组名,因此可以直接在调用的函数中修改数组的值,因此,Get_mine不需要返回值。
  • 整个代码的最难点在于当输入一个坐标后,由于该坐标所在的九宫格中雷数为0,因此会从此坐标向外蔓延,显示一片,知道边界全为数字为止。在这里我使用了递归的方法由中心点向外蔓延,具体是在函数Get_Mine中实现的。

以下为 game.c中的代码(下面为扫雷的整体模拟思路!):

/*
//  扫雷的整体模拟思路
    只定义一个数组
    数组类型为整形
    数组默认值为-2 // 初始值
    进行布置雷,如果此处是雷则值为-1
    输入一个位置,会计算此处雷数
    如果此处周围雷数为0 显示空 同时向外蔓延炸开
    游戏中的输出界面 主要参考下面两个值:
    1.如果是-2 说明未排雷 输出‘*’  
    2.如果是0 或者 大于0的数字,说明排雷已经排过了这些坐标
    如果值为-1 不影响游戏中输出界面,只在最后输出游戏结果时,输出’@‘
    如果此处周围有雷,那么就只显示该位置,显示数字为周围雷数
    每次输入坐标后都检测剩余未点开的坐标数 如果只剩下了雷 则胜利  
    数组大小为显示界面横纵坐标各加2
*/
#include"game.h"
void Choose_Menu(int a[ROWS][COLS])
{
    int i = 1;
    while (i)
    {
        printf("\t\t\t******************************************************\n");
        printf("\t\t\t******************************************************\n");
        printf("\t\t\t*************请选择进行的操作:          *************\n");
        printf("\t\t\t*************1.开始游戏    0.退出游戏    *************\n");
        printf("\t\t\t******************************************************\n");
        printf("\t\t\t******************************************************\n");
        printf("\t\t\t输入:>_");
        scanf("%d", &i);
        switch (i)
        {
        case 1: Play_Game(a, R, C); break;
        case 0: printf("退出成功,请按任意键结束!\n"); break;
        default:printf("输入错误,请重新输入!\n"); break;
        }
    }
}
void Game_Initialize(int a[ROWS][COLS], int row, int col)
{
    int i = 0, j = 0;
    for (i = 0; i < row; i++)
    {
        for (j = 0; j < col; j++)
        {
            a[i][j] = -2;
        }
    }
}
void Set_Mine(int a[ROWS][COLS], int row, int col, int count)
{ 
    int x = 0;
    int y = 0;
    srand((unsigned int)time(NULL));
    while (count)
    {
        x = rand() % row + 1;
        y = rand() % col + 1;
        if (a[x][y] == -2)
        {
            a[x][y] = -1;
            count--;
        }
    }
}
void Move_Mine(int a[ROWS][COLS], int row, int col, int x, int y)
{
    int x0 = 0;
    int y0 = 0;
    srand((unsigned int)time(NULL));
    while (1)
    {
        x0 = rand() % row + 1;
        y0 = rand() % col + 1;
        if ((x0 != x || y0 != y) && a[x0][y0] != -1)
        {
            a[x0][y0] = -1;
            break;
        }
    }
}
void Game_Menu_Print(const int a[ROWS][COLS], int row, int col)
{
    int i = 0, j = 0;
    printf("\n\t\t\tGame_Menu:\n\n");
    //输出坐标

    printf("\t\t\t\t");
    for (i = 1; i <= col; i++)
    {
        if(i < 10)
        printf(" %d ", i);
        else printf("%d ", i);
    }
    printf("\n\n");

    //输出棋局
    for (i = 1; i <= row; i++)
    {
        printf("\t\t\t   %d ",i);
        for (j = 1; j <=col; j++)
        {
            if (a[i][j] == -2 || a[i][j] == -1)
                printf(" * ");
            else if(a[i][j] == 0)
                printf("   ");
            else printf(" %d ", a[i][j]);
        }
        printf("    %d\n", i);
    }
    //输出坐标
    printf("\n\t\t\t\t");
    for (i = 1; i <= col; i++)
    {
        if (i < 10)
            printf(" %d ", i);
        else printf("%d ", i);
    }
    printf("\n\n");
}
void Game_Result_Print(const int a[ROWS][COLS], int row, int col)
{
    int i = 0, j = 0;
    printf("\n\t\t\tGame_Result:\n\n");
    //输出坐标

    printf("\t\t\t\t");
    for (i = 1; i <= col; i++)
    {
        if (i < 10)
            printf(" %d ", i);
        else printf("%d ", i);
    }
    printf("\n\n");

    //输出棋局
    for (i = 1; i <= row; i++)
    {
        printf("\t\t\t   %d ", i);
        for (j = 1; j <= col; j++)
        {
            if (a[i][j] == -2)
            {
                printf(" * ");
            }
            else if (a[i][j] == -1)
            {
                printf(" @ ");
            }
            else if (a[i][j] == 0)
            {
                printf("   ");
            }
            else printf(" %d ", a[i][j]);
        }
                printf("    %d\n", i);
    }
    //输出坐标
    printf("\n\t\t\t\t");
    for (i = 1; i <= col; i++)
    {
        if (i < 10)
            printf(" %d ", i);
        else printf("%d ", i);
    }
    printf("\n\n");
}
int Get_Win(const int a[ROWS][COLS], int row, int col)
{
    int i = 0, j = 0;
    int ret = 0;
    for(i = 1; i <= row; i++)
        for (j = 1; j <= col; j++)
        {
            if (a[i][j] == -2)
                ret++;
        }
    return ret;
}
void Get_Mine(int a[ROWS][COLS], int row, int col)
{
    int i = 0;
    int j = 0;
    if ((a[row - 1][col - 1] == -1) + (a[row - 1][col] == -1) + (a[row - 1][col + 1] == -1) + (a[row][col - 1] == -1) + (a[row][col + 1] == -1) + (a[row + 1][col - 1] == -1) + (a[row + 1][col] == -1) + (a[row + 1][col + 1] == -1) != 0)
    {
        a[row][col] =  (a[row - 1][col - 1] == -1) + (a[row - 1][col] == -1) + (a[row - 1][col + 1] == -1) + (a[row][col - 1] == -1) + (a[row][col + 1] == -1) + (a[row + 1][col - 1] == -1) + (a[row + 1][col] == -1) + (a[row + 1][col + 1] == -1);
    }
    else
    {
        //只有在棋盘内才递归
        if (row >= 1 && row <= R && col >= 1 && col <= C)
        {
            a[row][col] = ((a[row - 1][col - 1] == -1) + (a[row - 1][col] == -1) + (a[row - 1][col + 1] == -1) + (a[row][col - 1] == -1) + (a[row][col + 1] == -1) + (a[row + 1][col - 1] == -1) + (a[row + 1][col] == -1) + (a[row + 1][col + 1] == -1));
            //向上
            if (a[row - 1][col] < 0)
                Get_Mine(a, row - 1, col);
            //向右
            if (a[row][col + 1] < 0)
                Get_Mine(a, row, col + 1);
            //向下
            if (a[row + 1][col] < 0)
                Get_Mine(a, row + 1, col);
            //向左
            if (a[row][col - 1] < 0)
                Get_Mine(a, row, col - 1);
        }
    }
}
void Find_Mine(int a[ROWS][COLS], int row, int col)
{
    int x = 0, y = 0;
    int win = Get_Win(a, row, col);;
    while (win)
    {
        //输入坐标
        Game_Menu_Print(a, row, col);
        printf("请输入要排查的坐标:");
        scanf("%d %d", &x, &y);
        //判断有效性
        if (x >= 1 && x <= row && y >= 1 && y <= col) //输入正确
        {

            //
            if (a[x][y] == -1)
            {
                if (win == row * col - EASY_COUNT)
                {
                    Move_Mine(a, row, col, x, y);
                    Get_Mine(a, x, y);
                    win = Get_Win(a, row, col);
                }
                else
                {
                    printf("\nGAME OVER!!!\n\n");
                    break;
                }
            }
            else
            {
                if (a[x][y] != -2)
                {
                    printf("坐标输入有误,请重新输入!\n");
                    continue;
                }
                Get_Mine(a, x, y);
                win = Get_Win(a, row, col);
            }

        }
        else
        {
            printf("坐标输入有误,请重新输入!\n");
        }
    }
    if (win == 0)
        printf("\nYou Win!\n\n");
}
void Play_Game(int a[ROWS][COLS], int row, int col)
{
    Game_Initialize(a, ROWS, COLS);
    Set_Mine(a, row, col,EASY_COUNT);
    Find_Mine(a, row, col);
    Game_Result_Print(a, row, col);
}

最后是主函数代码test.c

#include "game.h"
int main()
{
    int arr[ROWS][COLS] = { 0 };
    Choose_Menu(arr);
    return 0;
}

代码整体相比于真正的扫雷还相差很多,需要注意的问题就是:

  • 不能标记
  • 在炸开时,显示的边界不是连续的,如下图:
    这里写图片描述
    不过这都不影响整体的游戏过程,如果有需要可自行修改。
以上即为我模拟实现的扫雷游戏,不足之处还望指正!
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1扫雷游戏1

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值