尝试写一个扫雷

Version alpha:

更新时间:23/12/2

//现存问题:
//实际埋雷数不等于要求埋雷数,因为生成的随机数可能重复.
//要加个坐标系.
//不显示(或错误显示)周边雷数.
//埋雷未考虑增广区域.

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

#define SIZE 10

int matrix[SIZE + 2][SIZE + 2];     //记录雷位置的棋盘
                                    //**注意此棋盘的(1,1)对应展示棋盘的(0,0)**
char display[SIZE][SIZE];           //展示的棋盘.

void initialize(void);              //初始化棋盘.
void mine(int n);                   //埋雷.
void print_display(void);           //打印展示棋盘.
int operate(int x, int y);          //操作录入与判断.
int minecount(int x, int y);        //计算操作点周边雷数.
void change(int x, int y);          //变化展示棋盘,显示周边雷数(若无雷)(不含打印).
void boom(void);                    //显示爆炸(若有雷)(含打印).
void print_time(int gap);           //换算整理用时并打印.

int main(void) {
    long long int time_gap = time(NULL);
    initialize();
    int x, y;
    int n;
    int judge = 0;
    printf("How many mines?\n");
    scanf("%d", &n);
    mine(n);
    for(;;) {
        printf("\n");
        print_display();
        printf("\nPlease input:\n");
        scanf("%d%d", &x, &y);
        if(operate(x, y) == 1)   break;
        else {
            minecount(x, y);
            change(x, y);
            if(n == 0) {
                judge = 1;
                break;
            }
        }
    }
    time_gap = time(NULL) - time_gap;
    if(judge == 0) {
        boom();
        printf("Lose!\n");
        print_time((int)time_gap);
    } else {
        print_display();
        printf("Win!\n");
        print_time((int)time_gap);
    }
    return 0;
}

//初始化.
void initialize(void) {
    for(int i = 0; i < SIZE; i++) {
        for(int j = 0; j < SIZE; j++) {
            display[j][i] = '.';
        }
    }
    return;
}

//埋雷.
void mine(int n) {
    srand((unsigned int)time(NULL));
    for(int i = 0; i < n; i++) {
        int retx = rand() % SIZE;
        int rety = rand() % SIZE;
        matrix[retx + 1][rety + 1] = 1;
    }
    return;
}

//打印展示棋盘.
void print_display(void) {
    for(int i = 0; i < SIZE; i++) {
        for(int j = 0; j < SIZE; j++) {
            printf("%c ", display[j][i]);
        }
        printf("\n");
    }
    return;
}

//操作录入与判断.
int operate(int x, int y) {
    if(matrix[x + 1][y + 1] == 1) {
        return 1;
    } else {
        change(x, y);
        return 0;
    }
}

//计算操作点周边雷数.
int minecount(int x, int y) {
    x++; y++;
    int count = 0;
    for(int i = -1; i <= 1; i++) {
        for(int j = -1; j <= 1; j++) {
            if(matrix[x + i][y + i] == 1)   count++;
        }
    }
    return count;
}

//变化显示棋盘,显示周边雷数(若无雷).
void change(int x, int y) {
    display[x][y] = minecount(x, y) + 48;
    return;
}

//显示爆炸(若有雷).
void boom(void) {
    for(int i = 0; i < SIZE; i++) {
        for(int j = 0; j < SIZE; j++) {
            if(matrix[i + 1][j + 1] == 1)
                display[j][i] = '*';
        }
    }
    print_display();
    return;
}

//换算整理用时并打印.
void print_time(int time_gap) {
    int h = 0, m = 0, s = time_gap;
    for(;;) {
        if(time_gap > 59) {
            time_gap-=59;
            m++;
        } else  break;
    }
    for(;;) {
        if(m > 59) {
            m-=59;
            h++;
        } else  break;
    }
    if(m == 0)  printf("Time: %ds", s);
    else if(h == 0)  printf("Time: %dm %ds", m, s);
    else    printf("Time: %dh %dm %ds", h, m, s);
    return;
}

晚上十一点半突然有了这个想法。大概写了一个半小时,只实现了基本功能,甚至还有很多bug。基本没法正常游玩(正常运行都谢天谢地了)。

Version beta:

更新时间:23/12/3

//更新日志:

//v_alpha:实现基本功能.

//v_beta:
//增加了坐标系,增加了标雷功能,增加开始界面,修复了埋雷卡死bug,
//修复了显示周边雷数与实际周边雷数不匹配的问题,
//修复了要求埋雷数与实际埋雷数不相等的问题,增加了扩散效果,
//默认棋盘大小改至16*16,新增推荐埋雷数40的提示.
//增加了末尾的getchar()保证其运行结束后暂停.
//修改了游戏结束后显示的文本内容.
//修改了计时器显示错误的bug.

//需要改进:
//增加通过标记所有的雷来取胜的方式(目前是点完所有无雷的格点取胜).
//直接用类似-3 -8的输入方式来标记(这样做或许可以很方便地让第一次输入也可以做标记).
//更好的扩散效果.
//防呆机制.
//*****无法取胜!*****

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

#define SIZE 16

char version[100] = {"Beta"};

int matrix[SIZE + 2][SIZE + 2];     //记录雷位置的棋盘
                                    //**注意此棋盘的(1,1)对应展示棋盘的(0,0)**
char display[SIZE][SIZE];           //展示的棋盘.

void initialize(void);              //初始化棋盘.
void mine(int n, int x, int y);     //埋雷,初始位置minecount应为0.
void print_display(void);           //打印展示棋盘.
int operate(int x, int y);          //操作录入与判断.
void bfs_spread(int x, int y);      //基于广度优先搜索,实现扩散效果.
int minecount(int x, int y);        //计算操作点周边雷数.
void change(int x, int y);          //变化展示棋盘,显示周边雷数(若无雷)(不含打印).
void mark(void);                    //进入标雷模式.
void boom(void);                    //显示爆炸(若有雷)(含打印).
void print_time(int gap);           //换算整理用时并打印.

int main(void) {

    //开始界面.
    printf
    ("Ciallo! XD\n"
    "Welcome to my MineClearance! \n"
    "Version: %s. \n"
    "Author: Sylphii. \n\n"
    "It needs some explaination. \n"
    "When \"input\", you needs input "
    "the coordinate you want to click. \n"
    "And please use a space to separate \"x\" and \"y\". \n\n"
    " -- > x\n|\nv      eg: input \"1 1\" to infer (1,1).\ny\n\n"
    "If you want to mark a mine, "
    "please input \"-1 -1\" and press Enter. \n"
    "Then the operation mod will be changed to \"Mark\". \n"
    "Everytime you input, the mod will "
    "change to \"Click\" automatically. \n"
    "\n***********Warning***********\n"
    "Because of my foolishness, please don't input \"-1 -1\" at the beginning. \n"
    "***********Warning***********\n\n"
    "Now, press Enter to start...\n", version);
    getchar();

    //初始化.
    long long int time_gap = time(NULL);
    initialize();
    int x, y;
    int n;
    int judge = 0;

    //输入埋雷数并进行第一次操作.
    printf("How many mines?\n(Recommend: 40)\n");
    scanf("%d", &n);
    print_display();
    printf("\nPlease input:\n");
    scanf("%d%d", &x, &y);
    mine(n, x ,y);
    operate(x ,y);

    //后续操作.
    for(;;) {
        printf("\n");
        print_display();
        printf("\nPlease input:\n");
        scanf("%d%d", &x, &y);
        if(x == -1 && y == -1)
            mark();
        else {
            if(operate(x, y) == 1)
                break;
            else {
                change(x, y);
                if(n == 0) {
                    judge = 1;
                    break;
                }
            }
        }
    }

    //游戏结束.
    time_gap = time(NULL) - time_gap;
    if(judge == 0) {
        boom();
        printf("\nDamn it!\n");
        print_time((int)time_gap);
    } else {
        print_display();
        printf("\nGodness!\n");
        print_time((int)time_gap);
    }
    printf("\nPress Enter to continue...");
    getchar();
    getchar();
    return 0;
}

//初始化.
void initialize(void) {
    for(int i = 0; i < SIZE; i++) {
        for(int j = 0; j < SIZE; j++) {
            display[j][i] = '.';
        }
    }
    return;
}

//埋雷,初始位置minecount应为0.
void mine(int n, int x, int y) {

    //初次埋雷.
    srand((unsigned int)time(NULL));
    for(int i = 0; i < n; i++) {
        int retx = rand() % SIZE;
        int rety = rand() % SIZE;
        if(matrix[retx + 1][rety + 1] == 1)
            n++;
        else
            matrix[retx + 1][rety + 1] = 1;
    }

    //检查初始位置minecount是否为0.
    //是则继续.
    if(minecount(x, y) == 0)
        return;
    //否则删雷重埋.
    else {  
        for(;;) {
            //删雷,并记录个数以便重埋.
            int count = 0;
            for(int i = -1; i <= 1; i++) {
                for(int j = -1; j <= 1; j++) {
                    if(matrix[x + 1 + i][y + 1 + j] == 1) {
                        matrix[x + 1 + i][y + 1 + j] = 0;
                        count++;
                    }
                }
            }
            //重埋count个雷.
            for(int i = 0; i < count; i++) {
                int retx = rand() % SIZE;
                int rety = rand() % SIZE;
                if(matrix[retx + 1][rety + 1] == 1)
                    count++;
                else
                    matrix[retx + 1][rety + 1] = 1;
            }
            //再次初始位置判断,合格则返回.
            //不合格则循环该过程.
            if(minecount(x, y) == 0)
                return;
        }
    }
}

//打印展示棋盘.
void print_display(void) {
    printf("  ");
    for(int i = 0; i < SIZE; i++) {
        printf("%2d ", i);
    }
    printf("\n");
    for(int i = 0; i < SIZE; i++) {
        printf("%2d ", i);
        for(int j = 0; j < SIZE; j++) {
            printf("%c  ", display[j][i]);
        }
        printf("\n");
    }
    return;
}

//操作录入与判断.
int operate(int x, int y) {
    if(matrix[x + 1][y + 1] == 1) {
        return 1;
    } else {
        if(minecount(x, y) == 0)
            bfs_spread(x, y);
        else
            change(x, y);
    }
    return 0;
}

//基于广度优先搜索,实现扩散效果.
//左,上,右,下.
int wx[4] = {-1, 0, 1, 0};
int wy[4] = {0, -1, 0, 1};
//已经搜索过的点.
int pass[SIZE][SIZE];
void bfs_spread(int x, int y) {
    if(pass[x][y] != 1) {
        pass[x][y] = 1;
        change(x, y);
        for(int i = 0; i < 4; i++) {
            int tx = x + wx[i];
            int ty = y + wy[i];
            if(tx >= 0 && tx <= SIZE - 1 && ty >= 0 && ty <=SIZE - 1) {
                if(minecount(tx, ty) == 0)
                    bfs_spread(tx, ty);
                else
                    change(tx, ty);
            }
        }
        return;
    }
    else
        return;
}

//计算操作点周边雷数.
int minecount(int x, int y) {
    x++; y++;
    int count = 0;
    for(int i = -1; i <= 1; i++) {
        for(int j = -1; j <= 1; j++) {
            if(matrix[x + i][y + j] == 1)
                count++;
        }
    }
    return count;
}

//变化显示棋盘,显示周边雷数(若无雷).
void change(int x, int y) {
    display[x][y] = minecount(x, y) + 48;
    return;
}

//进入标雷模式.
void mark(void) {
    int x, y;
    printf("\nPlease mark:\n");
    scanf("%d %d", &x, &y);
    display[x][y] = '#';
    print_display();
    return;
}

//显示爆炸(若有雷).
void boom(void) {
    for(int i = 0; i < SIZE; i++) {
        for(int j = 0; j < SIZE; j++) {
            if(matrix[i + 1][j + 1] == 1)
                display[i][j] = '*';
        }
    }
    print_display();
    return;
}

//换算整理用时并打印.
void print_time(int time_gap) {
    int h = 0, m = 0, s = time_gap;
    for(;;) {
        if(s > 59) {
            s-=60;
            m++;
        } else
            break;
    }
    for(;;) {
        if(m > 59) {
            m-=60;
            h++;
        } else
            break;
    }
    if(m == 0)
        printf("Time: %ds", s);
    else {
        if(h == 0)
            printf("Time: %dm %ds", m, s);
        else
            printf("Time: %dh %dm %ds", h, m, s);
    }
    return;
}

修修补补加了一些新功能,增加了扩散效果,改了一些bug。

写的时候一直出现埋雷卡死和扩散卡死的情况。

而且扩散效果虽说基本实现了,但是会出现一些很呆的情况,比如角上的"0"格子对角的格子一定无雷,但是扩散效果却没有扩散到。究其原因是该扩散效果是从中心向四个方向进发的,只能扩散到周围的四个格子,而不是八个格子,可能需要大改。

标记功能每次都要输入"-1 -1"很呆,经朋友提醒或许可以直接在坐标前加负号来表示作标记,但这样做的问题是(0,0)没法作标记。可能需要用"-17 -17"来表示在(0,0)作标记。

玩到后期会出现一次操作打印两次的问题,待查明。

还要增加防呆机制,防止非法输入卡崩程序。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sylphii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值