C语言实现扫雷

Suzhou
• 阅读 154

两个棋盘数组如下: 当在如下红框内99的棋盘中扫雷时,设置一个蓝色框1111的棋盘,在其中红框内格子中随机布置雷,在其余全部置0。 C语言实现扫雷

设置两个数组,一个数组用来后台存储雷的位置信息,另一个存放排雷过程中显示排查出来的雷和周围雷的数量信息显示给玩家。 ::: tip 设定后台存储的数组中,雷所处的位置是字符1,数组其他位置为字符0。前台显示的数组中,未排查到的位置是字符,排查到的位置实时显示雷或者周围雷的数量。 ::: 当用户选择一个位置时,如果该位置有一个雷,则提示用户踩雷,如果没有雷,则统计该位置周围的8个坐标中雷的数量,将统计数字放在该位置上。 *在数组中遍历选中位置周围8个位置时,当选中的位置位于整个棋盘的边界时,会有遍历的位置越界,可以将棋盘的四条边都向外扩展一个位置。**


game.h:

#define ROW 9
#define COL 9

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

#define EASY_COUNT 10

#include <stdlib.h>  //srand函数头文件
#include <time.h>  //time函数头文件

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

//打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col);  
//传过来的棋盘是mine数组,就需要用相同类型的数组接收,不能使用board[ROW][COL]

//布雷
void SetMine(char board[ROWS][COLS], int row, int col);

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

//返回座标(x,y)周围雷的数量
int get_mine_count(char mine[ROWS][COLS], int x, int y);

game.c:

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"

void InitBoard(char board[ROWS][COLS], int rows, int cols,char set)  //初始化是遍历整个数组
{
    int i = 0;
    int j = 0;
    for (i = 0; i < rows; i++)
    {
        for (j = 0; j < cols; j++)
        {
            board[i][j] = set;
        }
    }
}

void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
    int i = 0;
    int j = 0;
    printf("------扫雷游戏------\n");
    //打印列号
    for (i = 0; i <= col; i++)
    {
        printf("%d ", i);
    }
    printf("\n");
    for (i = 1; i <= row; i++)  //打印每行时除去蓝色框和红框之间的部分,即从(1,1)开始
    {
        printf("%d ", i);  //打印行号
        for (j = 1; j <= col; j++)  //打印一行中的每个信息
        {
            printf("%c ", board[i][j]);
        }
        printf("\n");
    }
    printf("------扫雷游戏------\n");
}

void SetMine(char board[ROWS][COLS], int row, int col)
{
    int count = EASY_COUNT;  //定义雷的数量,使用在game.h中定义EASY_COUNT,方便根据需要修改雷的数量
    //布置雷的思路:每次布置一个,count--,直到count=0。
    while (count != 0)
    {
        int x = rand() % row + 1;
        int y = rand() % col + 1;
        //雷出现的范围是红框内,即随机值的范围是1-9
        //当一个数字模9时,结果一定是0-8
        //rand函数在使用之前调用函数srand,srand只能调用一次,放在test.c中的test函数中
        if (board[x][y] == '0')  //为0时该位置没有布置0(不是雷)
        {
            board[x][y] = '1';  //布置雷
            count--;  //雷的数量-1
        }
        //当board[x][y]有雷时,if条件不满足,count值不变,再判断while条件,寻找下一个board[x][y]
    }
}

int get_mine_count(char mine[ROWS][COLS], int x, int y)  //计算某个坐标周围8个坐标的雷的数量
{
    //思路1:遍历该坐标周围的8个坐标,比较坐标中内容是否为参数'1',找到一个,count++
    //思路2:棋盘由0和1组成,可以将该坐标周围的8个字符全部相加。
        //由于0和1是字符形式,需要转换为数字。'数字'-'0'=数字。
        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 FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
    int x = 0;
    int y = 0;
    int win = 0;
    //当win=棋盘上坐标总数-雷的数量,表示全部雷排完,玩家获胜
    while (win<row*col- EASY_COUNT)  //当棋盘中还有需要排查的坐标时继续循环
    {
        printf("请输入排查雷的坐标:>");
        scanf("%d %d", &x, &y);
        if (x > 0 && x <= row && y > 0 && y <= col)  //判断坐标合法性
        {
            //坐标合法后可以有两种情况,是雷或者非雷
            if (mine[x][y] == '1')
            {
                printf("很遗憾,踩雷\n");
                DisplayBoard(mine, row, col);
                break;
            }
            else
            {
                //计算(x,y)坐标周围的8个坐标中雷的数量
                int count = get_mine_count(mine,x,y);  //为防止函数过大,设置函数获取雷的数量
                //需要把计算的count值用字符形式打印到show数组重显示给玩家
                show[x][y] = count + '0';  //数字+'0'='数字'。表示坐标(x,y)排雷成功
                DisplayBoard(show, row, col);
                win++;  //每排查一个坐标后,win++,直到棋盘上除了雷以外全部坐标都被排查
            }
        }
        else
        {
            printf("坐标非法,请重新输入\n");  //需要循环
        }
    }
    if (win == row * col - EASY_COUNT)
    {
        printf("恭喜你,排雷成功\n");
    }
}

test.c:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include "game.h"

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

void game()
{
    //布置雷的位置信息
    char mine[ROWS][COLS] = { 0 };  //数组mine中存放布置好的雷的信息
    //排查出的雷的信息
    char show[ROWS][COLS] = { 0 };  //数组show中存放排查出的雷的信息
    //初始化函数
    InitBoard(mine, ROWS, COLS,'0');  //初始化为0,把0传过去
    InitBoard(show, ROWS, COLS,'*');  //初始化为*,把*传过去
    //在初始化函数时,board[i][j]的值只能赋给一个值,需要在传参时候分别将要初始化的内容也传过去。

    //打印棋盘
    //DisplayBoard(mine,ROW,COL);  //打印棋盘的网格时,只需要打印红框内的位置
    DisplayBoard(show, ROW,COL);  //数组传参时数组show[ROWS][COLS]不变,后面的参数按照实际操作
    //布雷
    SetMine(mine, ROW, COL);  //在数组mine中随机找一些坐标放上字符1
    //DisplayBoard(mine, ROW, COL);  //布雷结束后再次打印棋盘

    //(数组mine的打印函数只在调试代码时候调用,在游戏中不打印)

    //扫雷
    FindMine(mine,show,ROW,COL);  //排雷的过程是在mine数组中查找信息放进show数组中
}

void test()
{
    srand((unsigned int)time(NULL));  //调用srand,time函数的返回值生成时间戳来设置srand
    int input = 0; 
    do
    {
        menu();
        printf("请选择:>");
        scanf("%d", &input);
        switch (input)  //根据输入值选择相应的输出内容
        {
        case 1:
            game();
            break;
        case 0:
            printf("退出游戏\n");
            break;
        default:
            printf("请重新选择\n");
            break;
        }
    } while (input);  //判断条件的要求:可以多次运行游戏
    //当input为1时,条件为真,进入do-while循环;当input为0时,条件为假,
    //离开do-while循环;input输入其他内容时,非0为真,进入do-while循环。
}

int main()
{
    test();
    return 0;
}
评论区
推荐文章

暂无数据

Suzhou
Suzhou
Lv1
这个网站设计堪称垃圾。CTRL+S过后的东西,重启电脑只能保存5行。多按几次CTRL+S还提示频繁保存不了。吐了。
9
文章
0
粉丝
0
获赞