C 简易版扫雷实现

为了应付系里的游戏设计比赛所做的玩意。
使用 BFS 来拓展空地。
当然,也有许多缺陷:

  • 标记非雷区块时,剩余雷数不会减少,导致作弊利用。(因为要重写雷计数所以懒得改了orz)
  • 在面积较大的地图中的刷新闪烁容易引起不适。
  • 没有适当限制 BFS 层数,在雷数较少的时候容易一键遍历全图…
  • /**
     * 
     * @Xiaoxiaoniwa
     * 2017/12/10
     * https://iecho.cc/
     * version 4.0
     */
    #include "stdio.h"
    #include "math.h"
    #include "string.h"
    #include "stdlib.h"
    #include "windows.h"
    #include "conio.h"
    #include "time.h"
    // #define offline
    #define N 100
    /**
     * Public Declaration
     */
    bool quit;
    short MAP[N][N], sign[N][N];
    int width, height;
    int bombper;
    int bomb;
    struct node
    {
        int x, y;
    }addr;
    
    inline int print(short status, bool on, int i, int j);
    inline int win()
    {
        bool c = 1;
        for (int i = 0; i < height; i++)
            for (int j = 0; j < width; j++)
            {
                if (MAP[i][j] == -1)
                {
                    c = 0;
                    break;
                }
            }
        return c;
    
    }
    
    inline bool handle(int i, int j)
    {
        /***
        * endowed W as 1, NULL and * as 0
        * use sign to distinguish the original requestion and derived requestion
        * True->Origin
        * printf("handle map[%d][%d]\n", i, j);
        */
        if (i >= 0 && j >= 0 && i < height && j < width)
        {
            if (MAP[i][j] == -1)
            {
                MAP[i][j] = 0;
                handle(i, j-1);
                handle(i, j+1);
                handle(i+1, j);
                handle(i-1, j);
            }
        }
        return 0;
    }
    
    int printover(short status, bool on)
    {
        /*
         * -1 safe
         * 0 known and safe
         * 1 bomb
         * 2 mark
         * 3 bomb mark
         * 4 mouse on
         */
        putchar(on ? '[' : ' ');
        if (status == 0)
            printf(" ");
        else if (status == -1)
            printf(" ");
        else if (status == 1)
            printf("*");
        else if (status == 2)
            printf(" ");
        else if (status == 3)
            printf("X");
        putchar(on ? ']' : ' ');
    }
    
    inline act(char status)
    {
        if (status == 'w'){
            if (addr.y > 0)
                addr.y--;
        }
        else if (status == 's'){
            if (addr.y < height-1)
                addr.y++;
        }
        else if (status == 'a'){
            if (addr.x > 0)
                addr.x--;
        }
        else if (status == 'd'){
            if (addr.x < width-1)
                addr.x++;
        }
        else if (status == 'm'){
            if (MAP[addr.y][addr.x] == 3)
                MAP[addr.y][addr.x] = 1;
            else if (MAP[addr.y][addr.x] == 2)
                MAP[addr.y][addr.x] = -1;
            else if (MAP[addr.y][addr.x] == -1)
                MAP[addr.y][addr.x] = 2;
            else if (MAP[addr.y][addr.x] == 1)
                MAP[addr.y][addr.x] = 3;
        }
        else if (status == ' '){
            if (MAP[addr.y][addr.x] == 1)
            {
                system("cls");
                for (int i = 0; i < height; i++)
                {
                    for (int j = 0; j < width; j++)
                        printover(MAP[i][j], (i == addr.y && j == addr.x) ? 1 : 0);
                    putchar('\n');
                }
                printf("You lost!\n");
                quit = 1;
            }
            else
                handle(addr.y, addr.x);
        }
        else if (status == 'q' || status == 'Q')
        {
            printf("Are you sure to quit ? YES[Y] NO[N] \n");
            char t = _getch();
            if (t == 'y' || t == 'Y')
                quit = 1;
        }
    }
    
    inline chk(int i, int j)
    {
        return (MAP[i][j] == 1 || MAP[i][j] == 3) ? 1 : 0;
    }
    
    inline int print(short status, bool on, int i, int j)
    {
        /*
         * -1 safe
         * 0 known and safe
         * 1 bomb
         * 2 mark
         * 3 bomb mark
         * 4 mouse on
         */
        putchar(on ? '[' : ' ');
        if (status == 0)
        {
            int count = 0;
            if (j > 0)
                count += chk(i, j-1);
            if (j < height-1)
                count += chk(i, j+1);
            if (i < width-1)
                count += chk(i+1, j);
            if (i > 0)
                count += chk(i-1, j);
            if (i > 0 && j > 0)
                count += chk(i-1, j-1);
            if (i < height-1 && j < width-1)
                count += chk(i+1, j+1);
            if (i < height-1 && j > 0)
                count += chk(i+1, j-1);
            if (i > 0 && j < height-1)
                count += chk(i-1, j+1);
    
            putchar(count == 0 ? ' ' : '0' + count);
        }
        else if (status == -1)
            printf("#");
        else if (status == 1){
            bomb++;
            printf("#");
        }
        else if (status == 2)
            printf("X");
        else if (status == 3)
            printf("X");
        putchar(on ? ']' : ' ');
        #ifdef offline
        printf("%d", status);
        #endif
    }
    
    inline core()
    {
        /**
         * initial part
         */
        for (int i = 0; i < height; i++)
            for (int j = 0; j < width; j++)
                MAP[i][j] = ((int)(rand() % 100) < bombper) ? 1 : -1;
        //memset(MAP, -1, sizeof(MAP));
        while(1)
        {
            system("cls");
            bomb = 0;
            for (int i = 0; i < height; i++)
            {
                for (int j = 0; j < width; j++)
                    print(MAP[i][j], (i == addr.y && j == addr.x) ? 1 : 0, i, j);
                putchar('\n');
            }
            putchar('\n');
            printf("Quit[Q]  CHOOSE[SPACE]  MARK[M]  UP[W]  DOWN[S]  LEFT[A]  RIGHT[D]\n");
            printf("Bombs: %d\n", bomb);
            act(_getch());
            if (win())
            {
                system("cls");
                for (int i = 0; i < height; i++)
                {
                    for (int j = 0; j < width; j++)
                        printover(MAP[i][j], (i == addr.y && j == addr.x) ? 1 : 0);
                    putchar('\n');
                }
                printf("You win! Congratulations!\n");
                quit = 1;
            }
            if (quit)
                break;
        }
    }
    
    int main()
    {
        srand((unsigned int)(time(NULL)));
        printf("Please set the width and height of the map : ");
        scanf("%d%d", &width, &height);
        printf("Please set the percentage of bomb(without %% symbol) : ");
        scanf("%d", &bombper);
        addr.x = 0;
        addr.y = 0;
        core();
        system("pause");
        return 0;
    }

    CC BY-SA 4.0 C 简易版扫雷实现 by 小小泥娃的部落格 is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.

    发表评论