c语言小游戏---扫雷

程序思想:
多文件实现扫雷基本功能:
1)test.c : 功能的测试,函数的调用;
2)game.h : 包含头文件的引用,函数的声明;
3)game.c : 各函数的功能的实现。
功能的具体思想:
1. 雷盘的初始化:注意实际雷盘的大小与展示雷盘的大小;
2. 雷盘的打印 :注意展示雷盘的大小;
3. 布置雷盘 :随机分布雷时,注意 srand 的使用;
4. 统计雷的个数:注意边界坐标周围雷的统计;
5. 扩展式排雷 :注意扩展式排雷的条件;
6. 第一次不会被炸死:注意重新布雷时的范围;

test.c

#define _CRT_SECURE_NO_WARNINGS 1 

#include<stdio.h>
#include"game.h"


void game()
{
    char mine[ROWS][COLS];                   //扫雷实际数组
    char show[ROWS][COLS];                  // 展示数组
    srand((unsigned int)time(NULL));       //  产生随机数
    init_mine(mine, ROWS, COLS);
    init_show(show, ROW, COL);
    set_mine(mine, ROW, COL,MINECOUNT);
    display(show, ROW, COL);           //打印雷盘
    play_game(mine, show);           //  主逻辑函数

}

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

int main()
{
    int input = 0;
    do
    {
        menu();
        printf("请选择:>");
        scanf("%d", &input);
        switch (input)
        {
        case 1:
            game();
            break;
        case 0:
            break;
        default:
            printf("输入错误!");
        }
    } while (input);
    return 0;

}

game.c

#define _CRT_SECURE_NO_WARNINGS 1

#include"game.h"

void init_mine(char mine[ROWS][COLS], int row, int col)  // 初始化雷盘
{
    int i = 0;
    int j = 0;
    for (i = 0; i < row; i++)
    {
        for (j = 0; j < col; j++)
        {
            mine[i][j] = '0';
        }
    }
}

void init_show(char show[ROWS][COLS], int row, int col) //初始化展示的雷盘
{
    int i = 0;
    int j = 0;
    for (i = 1; i <= row; i++)
    {
        for (j = 1; j <= col; j++)
        {
            show[i][j] = '*';
        }
    }
}

void set_mine(char mine[ROWS][COLS], int row, int col,int count)   // 随机布雷
{

    while (count)
    {
        int x = rand() % row + 1;
        int y = rand() % col + 1;
        mine[x][y] = '1';
        count--;

    }

}


void display(char arr[ROWS][COLS], int row, int col)  // 打印雷盘
{
    int i = 0;
    int j = 0;
    printf("  ");
    for (i = 1; i <= row; i++)
    {
        printf(" %d", i);
    }
    printf("\n");
    for (i = 1; i <= row; i++)
    {
        printf("%2d", i);
        for (j = 1; j <= col;j++)
        {
            printf(" %c", arr[i][j]);
        }
        printf("\n");
    }
}

void reset_mine(char mine[ROWS][COLS], int row, int col,int x,int y, int count) // 第一次踩到雷,重新布雷
{
    mine[x][y] = '0';

    while (count)
    {
        int i = rand() % row + 1;
        int j = rand() % col + 1;
        if ((mine[i][j] != '1') && i != x && j != y)
        {
            mine[i][j] = '1';
            count--;
        }
    }
}

int  get_minecount(char mine[ROWS][COLS], int i, int j)   //统计雷的个数
{
    return mine[i - 1][j] +
        mine[i - 1][j - 1] +
        mine[i][j - 1] +
        mine[i + 1][j - 1] +
        mine[i + 1][j] +
        mine[i + 1][j + 1] +
        mine[i][j + 1] +
        mine[i - 1][j + 1] - 8 * '0';
}

void expand(char mine[ROWS][COLS], int x, int y, char show[ROWS][COLS], int *p)    //扩展函数
{

    int i = -1;
    int j = -1;
    for (i = -1; i < 2; i++)      //边界
    {
        for (j = -1; j < 2; j++)
        {
            if (i != 0 || j != 0)      // 避免排到自己
            {
                if (x+i >= 1 && x+i <= ROW && y+j >= 1 && y+j <= COL)     //x y坐标是否合法
                {
                    if (show[x+i][y+j]=='*')
                    {

                        int count = get_minecount(mine, x+i, y+j);
                        if (count != 0)                                   
                        {
                            show[x+i][y+j] = count + '0';
                            (*p)++;
                        }
                        else
                        {
                            show[x+i][y+j] = '0';
                            (*p)++;
                            expand(mine, x+i, y+j, show, p);
                        }

                    }

                }
            }
        }
    }


}

// 主逻辑
void play_game(char mine[ROWS][COLS], char show[ROWS][COLS])
{
    int x = 0;
    int y = 0;
    int win = 0;        //统计排雷的个数
    int count = 0;     // 统计雷的个数
    while (win < ROW*COL - MINECOUNT)
    {
        printf("请输入坐标:>");
        scanf("%d %d", &x, &y);
        if (show[x][y] == count + '0')    //避免重复排雷
        {
            printf("已经排过雷\n");
        }
        if (x >= 1 && x <= ROW && y >= 1 && y <= COL)   //输入坐标是否合法
        {
            if (mine[x][y] == '1')
            {
                if (0 == win)      //为了游戏体验,第一次踩到雷,重新布雷
                {
                    reset_mine(mine, ROW, COL, x, y, 1);
                    display(mine, ROW, COL);
                    count = get_minecount(mine, x, y);
                    if (count == 0)
                    {
                        show[x][y] = '0';
                        win++;
                        expand(mine, x, y, show, &win);  //如果周围没有雷,进行扩展
                        display(show, ROW, COL);
                    }
                    else
                    {
                        show[x][y] = count + '0';
                        display(show, ROW, COL);
                    }
                }
                else
                {
                    printf("很遗憾,你被炸死了\n");
                    display(mine, ROW, COL);
                    break;
                }
            }
            else
            {
                count = get_minecount(mine, x, y);
                show[x][y] = count + '0';
                win++;
                expand(mine, x, y, show, &win);
                display(show, ROW, COL);
            }
        }

        else
        {
            printf("输入坐标不合法\n");
        }

    }
    if (win == ROW*COL - MINECOUNT)    
    {
        printf("排雷成功\n");
        display(mine, ROW, COL);
    }
}

game.h

#define _CRT_SECURE_NO_WARNINGS 1

#ifndef __GAME_H__
#define __GAME_H__


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



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



void init_mine(char mine[ROWS][COLS], int row, int col);
void init_show(char show[ROWS][COLS], int row, int col);
void display(char arr[ROWS][COLS], int row, int col);
void set_mine(char mine[ROWS][COLS], int x, int y,int count);
void play_game(char mine[ROWS][COLS], char show[ROWS][COLS]);
int  get_minecount(char mine[ROWS][COLS], int i, int j);
void reset_mine(char mine[ROWS][COLS], int row, int col, int x, int y, int count);
void expand(char mine[ROWS][COLS], int x, int y, char show[ROWS][COLS], int *p);




#endif //__GAME_H__

调试结果:

第一次踩到雷:
1) 随机雷阵

这里写图片描述

2)踩雷后重新布置的雷阵

这里写图片描述

被炸死:

这里写图片描述

扫描二维码关注公众号,回复: 165354 查看本文章

重复排雷:

这里写图片描述

排雷失败:

这里写图片描述

上面程序中,初始化雷盘的方法并不是非常的简介,我们可以利用 memset 函数进行初始化,具体代码如下:

void init_mine(char mine[ROWS][COLS], int row, int col)   // 初始化雷盘
{
    memset(mine, '0', row*col*sizeof(mine[0][0]));
}

memset 函数:
1. void *memset(void *s,int c,size_t n)
总的作用:将已开辟内存空间 s 的首 n 个字节的值设为值 c。
2. 例子

#include<stdio.h>

int  main()
{
    char *s = "Golden Global View";
    clrscr();
    memset(s, 'G', 6);
    printf("%s", s);
    getchar();
    return 0;
}
  1. memset() 函数常用于内存空间初始化。
    如:
    char str[100];
    memset(str,0,100);

  2. memset()的深刻内涵:用来对一段内存空间全部设置为某个字符,一般用在对定义的字符串进行初始化为‘ ’或‘/0’
    例:
    char a[100];memset(a, ‘/0’, sizeof(a));

    实现排雷的功能时,采用递归的思想,具体的思想为:
    将形参win传给expand函数,每次排雷,win计数一次,当win大于没有雷的格数时结束

void expand(char mine[ROWS][COLS], int x, int y, char show[ROWS][COLS], int *p)     //扩展函数
{

    int i = -1;
    int j = -1;
    for (i = -1; i < 2; i++)    //边界
    {
        for (j = -1; j < 2; j++)
        {
            if (i != 0 && j != 0)   // 避免排到自己
            {
                if (x+i >= 1 && x+i <= ROW && y+j >= 1 && y+j <= COL)   //x y坐标是否合法
                {
                    if (show[x+i][y+j]=='*')  //该位置没有排雷
                    {

                        int count = get_minecount(mine, x+i, y+j);//统计该位置周围雷的个数
                        if (count != 0)                                   
                        {
                            show[x+i][y+j] = count + '0';   
                            (*p)++;  //每排雷一次,计数一次
                        }
                        else
                        {
                            show[x+i][y+j] = '0'; //该位置周围没有雷时,向周围八个位置进行扩展排雷
                            (*p)++;
                            expand(mine, x+i, y+j, show, p);
                        }

                    }

                }
            }
        }
    }


}

总结:
在写程序时,不断调试会有不错的效果,当程序走的不是你所想的效果时,利用F11进行检查每一步,这样会看清楚到底是哪一步出了问题,有利于我们改掉程序中的bug。在写程序时加上必要的注释,后面调试过程中有利于帮助我们更快的知道是哪一环节有了问题。

猜你喜欢

转载自blog.csdn.net/zhangye3017/article/details/78357798