C语言:实现扫雷小游戏

要实现扫雷游戏代码的编写,我们首先要清楚扫雷的游戏规则:
1. 有一个显示盘界面,玩家可以在上面的坐标进行点击。
2. 玩家点击坐标,如果是雷,则被炸死,如果不是雷,分两种情况,一是周围无雷,那么将无雷的区域展开;二是周围有雷,那么将周围雷的个数显示在此坐标上。
3. 判断输赢。如果玩家在玩游戏过程中点到的坐标是雷,那么被炸死。如果最后只剩下雷,那么玩家排雷成功。

那么我们用代码实现这个游戏时,当然要遵循游戏规则。在上面的游戏规则之外,我们还添加了一条:如果玩家第一次就踩到了雷,那么设置为不会被炸死。下面我们就来看看具体怎么实现:
先说下基本思想:
1. 首先我们要设定两个棋盘。一个是用于给玩家看的显示棋盘。一个是用于布雷的雷盘。实现的方法是定义两个数组,并且初始化。注意我们这里要设置比显示出来的棋盘多一圈。比如显示10*10,那么初始化为12*12。为什么呢?显示棋盘是因为我们数组的下标是从0开始的,而一般生活中的思维都是从1开始,这里是为了便于玩家玩游戏时好操作。雷盘是因为我们在统计周围雷的个数时方便一些。这里我们设定将显示盘初始化为’*’,将雷盘初始化为’0’,将有雷的坐标初始化为’1’。
2. 布雷。也就是放置雷。这里我们要用到随机数种子的函数。产生随机数,当要放置的坐标不为’1’时,将此坐标置为’1’。如果放置的坐标不能放置雷的话,要将循环变量设置回初始的值。
3. 玩家玩游戏。首先玩家输入的坐标要在显示棋盘内。其次再看有没有踩到雷,如果踩到雷,分两种情况:是否为第一次踩雷。如果第一次踩雷,那么将此颗雷移动到别的没有雷的地方;如果不是,那么玩家被炸死,游戏结束。如果没有踩到雷,那么看此坐标周围是否有雷,有雷,将统计的雷的个数显示在此坐标,如果没有雷,将此坐标周围的坐标都展开,即将此坐标周围的坐标都设置为’ ‘。
4. 判断输赢。如果玩家在玩游戏途中,被炸死,那么玩家输了。如果玩家玩到最后,剩余的坐标数和雷的数量相同,那么玩家排雷成功。

下面是具体实现代码,供大家参考:

lei.h 头文件:声明程序中所用到的函数


#ifndef __LEI_H_
#define __LEI_H_

#define ROW 10
#define COL 10

#define ROWS 12
#define COLS 12

#define MINE 10  //设置雷的个数为20个


//初始化棋盘
void init_mine(char mine[ROWS][COLS], int row, int col);//雷盘 最外面一圈要全部初始化为无雷的 这样计算的时候好计算
void init_show(char show[ROWS][COLS], int row, int col);//显示盘 也要设置为12*12 因为一般观念是从1开始的 而数组下标是从0开始的 设置为12好计算一点

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

//布雷 设置雷
void set_mine(char mine[ROWS][COLS], int row, int col);//count为雷的总数

//统计雷的个数
int get_mine_count(char mine[ROWS][COLS], int i, int j);

//重新布雷
void reset_mine(char mine[ROWS][COLS], int x, int y, int row, int col);//x y为输入的坐标

//展开雷
void expand_mine(char mine[ROWS][COLS], int x, int y, char show[ROWS][COLS]);//x,y 为玩家输入周围无雷的坐标

//判断剩余未知区域的个数
int count_board(char show[ROWS][COLS], int row, int col);
#endif

main.c 主函数:用于测试各个函数

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<time.h>

#include"lei.h"

//菜单函数
void menu()
{
    printf("**********************\n");
    printf("*****   1.play   *****\n");
    printf("*****   0.exit   *****\n");
    printf("**********************\n");
}

//游戏函数
void game()
{
    int x = 0;//玩家输入的坐标
    int y = 0;//玩家输入的坐标
    int tmp = 0;//判断是不是第一次踩雷
    int num = 0;//统计剩余区域的雷的个数 用于判断是不是排雷成功
    int count = 0;//统计周围雷的个数

    char mine[ROWS][COLS] = { 0 };//定义雷数组
    char show[ROWS][COLS] = { 0 };//定义显示数组

    //初始化数组  规定无雷的坐标为0 有雷的坐标为1
    memset(mine, '0', sizeof(mine));//将mine数组当前位置后面的sizeof(mine)个字节,用‘0’替换并返回给数组mine,即将数组初始化为‘0’
    memset(show, '*', sizeof(show));//将board数组当前位置后面的sizeof(board)个字节,用‘0’替换并返回给数组board,即将数组初始化为‘*’

    //布雷
    srand((unsigned)time(NULL));//将随机值初始值设为当前时间
    set_mine(mine, ROWS, COLS);
    display_board(mine, ROWS, COLS);
    printf("\n");
    display_board(show, ROWS, COLS);

    while (1)
    {
        printf("请输入坐标:>");
        scanf("%d%d", &x, &y);

        if (((x >= 1) && (x <= ROW)) && ((y >= 1) && (y <= COL)))//坐标在雷盘内
        {
            if (mine[x][y] == '1')//踩到雷
            {
                if (0 == tmp)//第一次踩到雷 重置雷 然后显示当前坐标周围的雷个数
                {
                    reset_mine(mine, ROWS, COLS, x, y);
                    count = get_mine_count(mine, x, y);
                    if (count == 0)//输入坐标周围无雷
                    {
                        show[x][y] = ' ';//如果周围没有雷,那么将这个坐标置为空格
                        expand_mine(mine, x, y, show);//展开其周围
                        display_board(show, ROWS, COLS);
                    }
                    else//输入坐标周围有雷
                    {
                        show[x][y] = count + '0';//如果周围有雷,将周围雷的个数显示在此坐标处 整形数据+'0'转变成相应的字符数据
                        display_board(show, ROWS, COLS);
                    }
                }
                else//tmp为0时为第一次踩到雷,设置为不被炸死,重置雷。不为0时,就被炸死了
                {
                    printf("你被炸死啦!\n");
                    display_board(mine, ROWS, COLS);
                    break;
                }
            }
            else//没有踩到雷
            {
                count = get_mine_count(mine, x, y);
                if (count == 0)
                {
                    show[x][y] = ' ';
                    expand_mine(mine, x, y, show);
                    display_board(show, ROWS, COLS);
                }
                else
                {
                    show[x][y] = count + '0';
                    display_board(show, ROWS, COLS);
                }
            }
        }
        else
        {
            printf("输入坐标不合法\n");
        }
        if (num = count_board(show, ROWS, COLS == MINE))
        {
            printf("排雷成功\n");
            display_board(show, ROWS, COLS);
            break;
        }
        tmp++;
    }
}

int main()
{
    int choose = 0;
    do
    {
        menu();
        printf("请选择:>");
        scanf("%d", &choose);
        switch (choose)
        {
        case 1:
            printf("play game\n");
            game();
            break;
        case 0:
            printf("exit game\n");
            break;
            return 0;
        default:
            printf("输入错误,请重新输入\n");
            break;
        }
    } while (choose);

    system("pause");
    return 0;
}

lei.c:用于实现各个函数

#include<stdio.h>

#include "lei.h"


//打印棋盘
void display_board(char mine[ROWS][COLS], int row, int col)
{
    int i = 0;
    int j = 0;
    printf("   1 2 3 4 5 6 7 8 9 10\n");
    printf("  ---------------------\n");
    for (i = 1; i < row - 1; i++)//row参数传递过来的是ROWS 所以这里循环条件为1-10 下同
    {
        printf("%2d|",i);
        for (j = 1; j < col - 1; j++)
        {
            printf("%c ",mine[i][j]);
        }
        printf("|\n");
    }
    printf("  ---------------------\n");
}

//布雷 设置雷
void set_mine(char mine[ROWS][COLS], int row, int col)
{
    int count = MINE;//雷的个数
    int i = 0;
    for (i = 0; i < count; i++)
    {
        int x = rand() % (row - 2) + 1;//(0-9)+1 即为1-10
        int y = rand() % (col - 2) + 1;
        if (mine[x][y] == '0')//如果要放置的坐标为'0',那么放置雷
        {
            mine[x][y] = '1';
        }
        else
        {
            i--;//如果条件不足没有放置雷,那么将i的值返回原始值,重新循环
        }

    }
}

//统计雷的个数
int get_mine_count(char mine[ROWS][COLS], int x, int y)
{
    return mine[x - 1][y - 1] - '0' + mine[x - 1][y] - '0' + mine[x - 1][y + 1] - '0'
        + mine[x][y + 1] - '0' + mine[x + 1][y + 1] - '0' + mine[x + 1][y] - '0' +
        mine[x + 1][y - 1] - '0' + mine[x][y - 1] - '0';//字符型数值-‘0’就是相应的int型,如果是雷的话,就返回1,
    //如果不是雷,就返回0,将周围的每一个位置都统计相加,就是周围一共雷的个数
}

//重新布雷
void reset_mine(char mine[ROWS][COLS], int row, int col, int x, int y)//x y为输入的坐标
{
    int count = 1;
    mine[x][y] = '0';//让此时的坐标为'0' 即无雷状态
    while (count)
    {
        int i = rand() % row + 1;//1-row
        int j = rand() % col + 1;//1-col

        if ((mine[i][j] != '1') && (i != x) && (j != y))//不为x y即不是这个坐标,并且不是有雷的坐标,那么把它置为有雷
        {
            mine[i][j] = '1';//将雷挪开,再让另一个不同的没有雷的位置设置为雷
        }
        count--;
    }
}

//展开雷
void expand_mine(char mine[ROWS][COLS], int x, int y, char show[ROWS][COLS])//x,y 为玩家输入周围无雷的坐标
{
    if (mine[x - 1][y - 1] == '0')
    {
        show[x - 1][y - 1] = get_mine_count(mine, x - 1, y - 1);
    }
    if (mine[x - 1][y] == '0')
    {
        show[x - 1][y] = get_mine_count(mine, x - 1, y);
    }
    if (mine[x - 1][y + 1] == '0')
    {
        show[x - 1][y + 1] = get_mine_count(mine, x - 1, y + 1);
    }
    if (mine[x][y + 1] == '0')
    {
        show[x][y + 1] = get_mine_count(mine, x, y + 1);
    }
    if (mine[x + 1][y + 1] == '0')
    {
        show[x + 1][y + 1] = get_mine_count(mine, x + 1, y + 1);
    }
    if (mine[x + 1][y] == '0')
    {
        show[x + 1][y] = get_mine_count(mine, x + 1, y);
    }
    if (mine[x + 1][y - 1] == '0')
    {
        show[x + 1][y - 1] = get_mine_count(mine, x + 1, y - 1);
    }
    if (mine[x][y - 1] == '0')
    {
        show[x][y - 1] = get_mine_count(mine, x, y - 1);
    }

}

//判断剩余未知区域的个数
int count_board(char show[ROWS][COLS], int row, int col)
{
    int i = 0;
    int j = 0;
    int count = 0;
    for (i = 0; i < row; i++)
    {
        for (j = 0; j < col; j++)
        {
            if (show[i][j] == '*')
            {
                count++;
            }
        }
    }
    return count;
}

下面是运行结果:
这里写图片描述

这里写图片描述

这里写图片描述

猜你喜欢

转载自blog.csdn.net/windyj809/article/details/80154498