上文:[摸鱼] 用冰茶姬生成随机迷宫

赶紧补完这个坑,,自己写的破游戏被班长丢到了班级活动里简直羞耻得要死(/ω\)

针对上次迷宫进行了细节优化,并添加了双人对战功能。

# 双人对战功能添加

# 写在前面

(吐血.jpg)。。这就叫软件的维护吗_(:з」∠)_

面对自己的代码楞半天 不知道怎么改,感慨之至遂作此画:

<img src = "https://s1.ax1x.com/2020/10/28/B1MqVH.png" width = "600px">

以后一定要记得给自己留一条后路 TAT

# 实现方法

通过代码复制(正经脸),改成两个人。检测到键盘输入时,判断哪个玩家移动了,进行相应移动,另一个玩家原地不动,分别输出新的位置就 OK 啦。详见代码叭 (「・ω・)「

# 功能优化

# 闪屏严重问题

上次代码是这样写的:

if (kbhit())
    {
        getch();
        char op = getch();
        system("cls");
        MAZE_Print();
    blabla...

每次都输出一次地图。。能不闪屏么。。

解决方法:只更新角色位置。将光标定位在角色位置,输出 '\b' 和空格 清除角色,再重新输出即可。

# 出入口不明确

被小伙伴说不知道往哪走~~(迷宫从左上走到右下不是常识么)~~。

解决方法:左上和右下再挖掉一面墙就能看出来了。。感谢 @Dragon_Hao (还木有链接..) 协助修改。

​ 虽然思路很简单,改这段代码的时候可费劲了(躺),吸取教训吸取教训..

# 控制台输出方阵难看

于是就把迷宫改成了长宽不一样的,让控制台里看上去方方的 hhh

其实用全角字符可以一下子占两格,看上去就方了 emmm

# 简化部分代码

QwQ.. 拆函数呗..


水完啦水完啦,,上代码 (๑>ڡ<)☆

Code:

#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <windows.h>
#include <conio.h>
#include <time.h>
#define rep(i, s, t) for (int i = s; i <= t; i++)
using namespace std;
const int N = 1e3 + 10;
int Row, Col, Seed;
char Map[N][N];
bool Vis_Map[N][N];
int X1 = 2, X2 = 2, Y1 = 1, Y2 = 1; // 两人物位置坐标
struct Disjoint_Set
{
    int Father, Size = 1;
} D_Set[N * N];
int GetID(int i, int j) // 获取节点编号
{
    return (i - 1) * Col + j;
}
int GetFa(int x)
{
    return D_Set[x].Father == x ? x : D_Set[x].Father = GetFa(D_Set[x].Father);
}
void D_Merge(int x, int y, int i, int j)
{
    int Fx = GetFa(x), Fy = GetFa(y);
    if (Fx == Fy)
        return;
    if (D_Set[Fx].Size < D_Set[Fy].Size)
        swap(Fx, Fy);
    D_Set[Fy].Father = Fx;
    D_Set[Fx].Size += D_Set[Fy].Size;
    Vis_Map[i][j] = 1;
    return;
}
void Build() // 建立迷宫
{
    //init
    srand(Seed);
    rep(i, 1, Row)
        rep(j, 1, Col)
    {
        D_Set[GetID(i, j)].Father = GetID(i, j);
        if (i == 1 || j == 1 || i == Row || j == Col)
            Map[i][j] = '#';
        else if (i & 1 && j & 1)
            Map[i][j] = '#';
        else if (i & 1 || j & 1)
            Map[i][j] = '*';
        else
            Map[i][j] = ' ';
    }
    //build
    while (D_Set[GetFa(GetID(2, 2))].Size != (Row / 2) * (Col / 2))
    {
        int i, j;
        do
        {
            i = rand() % Row + 1, j = rand() % Col + 1;
        } while (Map[i][j] != '*' || Vis_Map[i][j]);
        if (Map[i][j + 1] == '#')
            D_Merge(GetID(i - 1, j), GetID(i + 1, j), i, j);
        else
            D_Merge(GetID(i, j - 1), GetID(i, j + 1), i, j);
    }
    rep(i, 1, Row)
        rep(j, 1, Col)
            if (Map[i][j] == '*')
                if (Vis_Map[i][j])
                    Map[i][j] = ' ';
    else Map[i][j] = '#';
}
void MAZE_Print()
{
    Map[2][1] = ' '; // 挖墙 qwq
    Map[Row][Col - 1] = ' ';
    rep(i, 1, Row)
    {
        rep(j, 1, Col)
            printf("%c", Map[i][j]);
        printf("\n");
    }
}
void Set_Handle(int x, int y) // 改变光标位置,单独拆开来写了
{
    COORD pos = {y, x - 1};
    HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(hOutput, pos);
}
void Hide_Cursor() // 隐藏光标闪烁
{
    HANDLE Handle = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_CURSOR_INFO CursorInfo;
    GetConsoleCursorInfo(Handle, &CursorInfo);
    CursorInfo.bVisible = 0;
    SetConsoleCursorInfo(Handle, &CursorInfo);
}
void Process(int dx, int dy)
{
    Set_Handle(X1, Y1);
    printf("\b ");
    int tx = X1 + dx, ty = Y1 + dy;
    if (tx == Row && ty == Col - 1) // 胜利条件
    {
        Set_Handle(Row + 1, 0);
        printf("P1 win!\n");
        system("pause");
        exit(0);
    }
    if (Map[tx][ty] == '#' || ty < 1)
        Set_Handle(X1, Y1);
    else
        Set_Handle(X1 = tx, Y1 = ty);
    if (X1 == X2 && Y1 == Y2) // 判断两个角色重合
        printf("\bO");
    else
        printf("\b@");
}
void Process2(int dx, int dy) // 这边好像也可以压到上个函数里 emm?
{
    Set_Handle(X2, Y2);
    printf("\b ");
    int tx = X2 + dx, ty = Y2 + dy;
    if (tx == Row && ty == Col - 1) // 胜利条件
    {
        Set_Handle(Row + 1, 0);
        printf("P2 win!\n");
        system("pause");
        exit(0);
    }
    if (Map[tx][ty] == '#' || ty < 1)
        Set_Handle(X2, Y2);
    else
        Set_Handle(X2 = tx, Y2 = ty);
    if (X1 == X2 && Y1 == Y2)  // 判断两个角色重合
        printf("\bO");
    else
        printf("\b$");
}
void Update() // 持续获取键盘信息,更新状态
{
    while (1)
    {
        if (kbhit())
        {
            Hide_Cursor();
            char op1 = getch();
            if (op1 == -32)
            {
                char op = getch(); // 上下左右 72, 80, 75, 77
                switch (op)
                {
                case 72:
                    Process(-1, 0);
                    break;
                case 80:
                    Process(1, 0);
                    break;
                case 75:
                    Process(0, -1);
                    break;
                case 77:
                    Process(0, 1);
                    break;
                default:
                    Process(0, 0);
                }
                Process2(0, 0); // 另一个角色不动
            }
            else
            {
                if (op1 < 'a') // 切换大小写方便判断
                    op1 += 32;
                switch (op1)
                {
                case 'w':
                    Process2(-1, 0);
                    break;
                case 's':
                    Process2(1, 0);
                    break;
                case 'a':
                    Process2(0, -1);
                    break;
                case 'd':
                    Process2(0, 1);
                    break;
                default:
                    Process2(0, 0);
                }
                Process(0, 0); // 另一个角色不动
            }
        }
        //        Sleep(20);
    }
}
void init()
{
    printf("请选择迷宫大小:(输入序号)\n 1. 小\n 2. 中\n 3. 大\n 4. 巨大\n");
    scanf("%d", &Row);
    switch (Row)
    {
    case 1:
        Row = 11, Col = 21;
        break;
    case 2:
        Row = 21, Col = 41;
        break;
    case 3:
        Row = 31, Col = 61;
        break;
    case 4:
        Row = 37, Col = 81;
        break;
    }
    printf("输入地图种子:\n");
    scanf("%d", &Seed);
    system("cls");
    printf("生成中");
    Sleep(500);
    printf(".");
    Sleep(500);
    printf(".");
    Sleep(500);
    printf(".");
    system("cls");
}
int main()
{
    init();
    Hide_Cursor();
    Build();
    MAZE_Print();
    Process(0, 0);
    Process2(0, 0);
    Update();
    system("pause");
    return 0;
}

效果图:
<img src = "https://s1.ax1x.com/2020/10/28/B1GxRs.png" width = "500px">

反正咱已经废了 Orz

更新于