我做了一个贪吃蛇游戏

· · 个人记录

rt

!!!请读完这几句话!!!

编译之前请选择适合自己(与自己系统)的 Icon,否则显示会出大问题。(默认是“Simplified Chinese”Icon,具体参见头文件下的注释)

建议不要更改已经预设好的Icon,除非你已经踩过命令提示符特殊字符显示的大坑(占用 2 个字符空间,显示时占用一个字符;换个版本之后占 22;再换个版本,又不一样)

如果有bug,那就将成为特性,我不会再更改了

提示:

玩法:(游戏内也有提示)

#include <iostream>
#include <vector>
#include <thread>
#include <chrono> 
#include <conio.h>
#include <windows.h>
#include <random>
#include <atomic>
#include <mutex>
using namespace std;
// 是那个神经写代码用英文ui呀,偶是我这个苕呀~

// 如果icon只有占了一个格子,请按需修改
// 建议的icon注释在后面了
// 原来中的中文字符(Simplified Chinese)是所有系统通用的(没错,win10以前、win10和win11特殊字符不通用)
// 请确保icon占两个字符(显示,不是占用空间)
// 如果看不懂上面文字中的意思,不是你理解的问题,是我脑子的问题(

//  Icon (before win10) (windows旧版命令提示符(开中文输入法之后下面有一行小字的))
//#define HEAD R"(●)"
//#define BODY R"(○)"
//#define WALL R"(▓)"
//#define DOORNM R"(☆)"
//#define DOORHL R"(★)"
//#define COIN R"(Θ)"
//  Icon (win10) (windows命令提示符)
//#define HEAD R"(●)"   
//#define BODY R"(○)"   
//#define WALL R"(▓ )"  
//#define DOORNM R"(☆)" 
//#define DOORHL R"(★)" 
//#define COIN R"(Θ)"   
//  Icon (win11) (Windows terminal(带标签页的))
//#define HEAD R"(@@)"  
//#define BODY R"(〇)"   
//#define WALL R"(▓▓)"  
//#define DOORNM R"([])"    
//#define DOORHL R"(%%)"    
//#define COIN R"(币)"   
//  Icon ("Simplified Chinese")
#define HEAD R"(头)" 
#define BODY R"(身)" 
#define WALL R"(墙)" 
#define DOORNM R"(门)"   
#define DOORHL R"(闫)"   
#define COIN R"(币)"

#define ARROWUP R"(/\)" // (↑)
#define ARROWLF R"(< )" // (←)
#define ARROWDN R"(\/)" // (↓)
#define ARROWRT R"( >)" // (→)

#define BLANK R"(  )"

// Size: DO NOT change the Minimum value, or display may crash
#define MINIR 15
#define MINIC 15
#define DFTR 20
#define DFTC 20
#define MIDR 30
#define MIDC 40
#define MAXR 40
#define MAXC 60

// Setting Sort: EZ -> HD -> IN -> SP
// Wall: control walls' density (per block)
const double WALLST[10] = {2.0/40, 4.0/40, 6.0/40, 3.0/40};
// Coin: control coins' density (per block)
const double COINST[10] = {1.0/40, 1.0/60, 1.0/100, 1.0/40};
// Target: the target you need to get for the win of the game
const int TARGETST[10] = {20, 20, 20, -1};// val -1 means that it will change with the size of the screen
// RSpeed: control wait time that will wait after a single step and after "3,2,1,GO" (val*4)
const int RSPEEDST[10] = {200, 180, 160, 180};
// HP: if 0, you will dead immediately after knock the wall or body
const int HPST[10] = {3, 2, 2, 2};
// Len: starting lenth
const int LENST[10] = {3, 3, 3, int(1e9)};

// Special Number
#define KEYESC 27

atomic <int> Mode(2);
atomic <double> WALLDENSITY, COINDENSITY; // Some Settings
atomic <int> TARGET, RSPEED, HP, STARTLEN; // Some Settings
atomic <int> R, C; // map size
atomic <int> animationSpeed; // Animation speed (1~4)
string DOOR = DOORNM; // Door Pattern
string mp[205][205]; // map for display
atomic <int> dirI; // direction (1~4 with dir[dirI][])
atomic <int> screenSize; // Screen Size Level (1~4)
int nx, ny, rp; // position & score
atomic <bool> gameContinue(true), exitSignal(false), pauseSignal(false);
atomic <int> dirChange; // if direction change (1~10)
const int dir[4][2] = {-1, 0, 0, -1, 1, 0, 0, 1}; // direction
atomic <int> winR, winC; // window's Size
atomic <bool> showResizeTipsKill(false); // if this thread should be killed
atomic <bool> exitRightNow(false);// Back to menu Right Now
mutex mpLock, kbInp; // 声明一个互斥锁

vector< pair<int, int> > v;// snack's body position

void waitfor(long long t) {
    this_thread::sleep_for(chrono::milliseconds(t));
}
void anWait(int TOT, int i) {
    switch (animationSpeed) {
        case 1: waitfor(pow(abs((TOT*9/20.0-i+1)/(TOT*9/80.0)), 3)+10); break;
        case 2: waitfor(pow(abs((TOT*4/10.0-i+1)/(TOT*4/55.0)), 2)+10); break;
        case 3: waitfor(pow(abs((TOT*4/10.0-i+1)/(TOT*4/40.0)), 2)+10); break;
        case 4: waitfor(1); break;
    }
}
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
int getRand(int s, int t) {
    if(s > t) swap(s, t);
    return (rnd() % (t - s + 1)) + s;
}
void cmdGoto(int x,int y) {
    HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD pos;
    pos.X = y*2, pos.Y = x;
    SetConsoleCursorPosition(handle,pos);
}

void getConsoleSize(int& columns, int& rows) {
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {
        rows = csbi.srWindow.Right - csbi.srWindow.Left + 1;
        rows /= 2;
        columns = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
    } else {
        columns = 0;
        rows = 0;
    }
}
void showResizeTips() {
    // 预处理Tips
    string tmp = "";
    const int line = 3;
    string words[line] = {"Please resize(enlarge) the window", "until the box can be fully displayed", "请放大窗口"};
    for(int j=0;j<=C+17;j++) {
        tmp += WALL;
    }
    tmp += "\n";
    for(int i=1;i<=R+2;i++) {
        tmp += WALL;
        for(int j=1;j<=C+16;j++) {
            tmp += BLANK;
        }
        tmp += WALL;
        tmp += "\n";
    }
    for(int j=0;j<=C+17;j++) {
        tmp += WALL;
    }
    tmp += "\n";

    while(!showResizeTipsKill) {
        system("cls");
        cout << tmp;
        for(int i=1;i<=line;i++) {
            cmdGoto(i, 1);
            cout << words[i - 1];
        }

        for(int i=1;i<=5;i++) {
            if(showResizeTipsKill) {
                break;
            }
            waitfor(100);
        }
    }
    showResizeTipsKill = 0;
}
void keepWindow() {
    do {
        // 隐藏cmd光标 
        CONSOLE_CURSOR_INFO cursor_info = {1, 0};
        SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info); 
        // 撤销cmd快速编辑模式 
        HANDLE handle = GetStdHandle(STD_INPUT_HANDLE);
        DWORD mode;
        GetConsoleMode(handle, &mode);
        mode &= ~ENABLE_QUICK_EDIT_MODE; // 移除快速编辑模式
        mode &= ~ENABLE_INSERT_MODE; // 移除插入模式
        mode &= ~ENABLE_MOUSE_INPUT;
        SetConsoleMode(handle, mode);
        // 检测窗口大小
        int r, c;
        getConsoleSize(r, c);
        winR = r, winC = c;
        // 窗口过小提醒
        if(R + 3 > winR || C + 17 > winC) {
            lock_guard<mutex> guard(mpLock);
            thread thShow(showResizeTips);
            while(R + 3 > winR || C + 17 > winC) {
                waitfor(10);
                int r, c;
                getConsoleSize(r, c);
                winR = r, winC = c;
            }
            showResizeTipsKill = 1;
            thShow.join();
            system("cls");
        }
        waitfor(50);
    } while(!exitSignal);
}

void flick(int x, int y, string things) {
    do {
        {lock_guard<mutex> guard(mpLock); // 使用互斥锁
        if(mp[x][y] == BLANK) mp[x][y] = things;
        else if(mp[x][y] == things) mp[x][y] = BLANK;}
        for(int i=1;i<=5;i++) {
            if(gameContinue || exitSignal) return;
            waitfor(100);
        }
    } while(!gameContinue && !exitSignal);
}
bool fail(int ex, int ey, string things) {
    bool returnVal;
    const int CC = 13;
    thread th;
    {lock_guard<mutex> guard(kbInp);
    gameContinue = 0;
    if(ex != -1 && ey != -1) 
        th = thread(flick, ex, ey, things);

    string tmp[7];
    tmp[1] = "--------------------------";//13
    tmp[2] = "       GAME OVER :(       ";
    tmp[3] = "  Press [R] to restart    ";
    tmp[4] = "  Press [Esc] to exit     ";
    tmp[5] = "--------------------------";
    string tmpBk[6] = {"", "+", "|", "|", "|", "+"};
    string tmpFt[6] = {"", " +", " |", " |", " |", " +"};
    for(int i=1;i<=5;i++) {
        lock_guard<mutex> guard(mpLock); // 使用互斥锁
        mp[i][C+3] = tmpBk[i];
    }
    for(int j=1;j<=CC;j++) {
        anWait(CC+1, j);
        lock_guard<mutex> guard(mpLock); // 使用互斥锁
        for(int i=1;i<=5;i++)
            mp[i][C+2] = tmp[i].substr(max(int(tmp[i].size()-j*2), 0));
    }
    anWait(CC+1, CC+1);
    for(int i=1;i<=5;i++) {
        lock_guard<mutex> guard(mpLock); // 使用互斥锁
        mp[i][C+2] = tmpFt[i] + mp[i][C+2];
    }
    waitfor(100);

    again:
    switch(getch()) {
        case 'r': returnVal = 0; break;
        case KEYESC: returnVal = 1; break;
        default: goto again; break;
    }}
    gameContinue = 1;

    for(int i=1;i<=5;i++) {
        lock_guard<mutex> guard(mpLock); // 使用互斥锁
        mp[i][C+2] = mp[i][C+2].substr(2);
        mp[i][C+3] += "  ";
    }
    for(int j=1;j<=CC;j++) {
        anWait(CC+1, j);
        lock_guard<mutex> guard(mpLock); // 使用互斥锁
        mp[1][C+2] = mp[1][C+2].substr(2);
        for(int i=2;i<=4;i++)
            mp[i][C+2] = mp[i][C+2].substr(2);
        mp[5][C+2] = mp[5][C+2].substr(2);
        for(int i=1;i<=5;i++)
            mp[i][C+3] += "  ";
    }
    anWait(CC+1, CC+1);
    for(int i=1;i<=5;i++) {
        lock_guard<mutex> guard(mpLock); // 使用互斥锁
        mp[i][C+3] = "    ";
        mp[i][C+2] = "";
    }
    waitfor(100);

    if (th.joinable()) th.join();
    if(returnVal) {
        for(int j=0;j<=C+1;j++) {
            if(j != 0)
                anWait(C+6, j);
            {lock_guard<mutex> guard(mpLock); // 使用互斥锁
            for(int i=0;i<=R+1;i++) {
                mp[i][j] = "";
                if(j <= 4) {
                    mp[i][C+2] += "  ";
                }
            }}
        }
        for(int j=1;j<=5;j++) {
            anWait(C+6, C+1+j);
            {lock_guard<mutex> guard(mpLock); // 使用互斥锁
            for(int i=0;i<=R+1;i++) {
                if(mp[i][C+2].size() > 2) {
                    mp[i][C+2] = mp[i][C+2].substr(3);
                }
                else {
                    mp[i][C+2] = "";
                }
            }}
        }
        for(int i=1;i<=5;i++) {
            lock_guard<mutex> guard(mpLock); // 使用互斥锁
            mp[i][C+3] = "";
        }
    }
    return returnVal;
}
bool win() {
    bool returnVal;
    const int CC = 13;
    {lock_guard<mutex> guard(kbInp);
    gameContinue = 0;

    string tmp[7];
    tmp[1] = "--------------------------";//13
    tmp[2] = "      You win!!! :-)      ";
    switch(Mode) {
        case 1: tmp[3] = "      In EaZy Mode        "; break;
        case 2: tmp[3] = "      In HarD Mode        "; break;
        case 3: tmp[3] = "      In INsane Mode      "; break;
        case 4: tmp[3] = "      In SPcial Mode      "; break;
    }
    tmp[4] = "  Press [R] to restart    ";
    tmp[5] = "  Press [Esc] to exit     ";
    tmp[6] = "--------------------------";
    string tmpBk[7] = {"", "+", "|", "|", "|", "|", "+"};
    string tmpFt[7] = {"", " +", " |", " |", " |", " |", " +"};
    for(int i=1;i<=6;i++) {
        lock_guard<mutex> guard(mpLock); // 使用互斥锁
        mp[i][C+3] = tmpBk[i];
    }
    for(int j=1;j<=CC;j++) {
        anWait(CC+1, j);
        lock_guard<mutex> guard(mpLock); // 使用互斥锁
        for(int i=1;i<=6;i++)
            mp[i][C+2] = tmp[i].substr(max(int(tmp[i].size()-j*2), 0));
    }
    anWait(CC+1, CC+1);
    for(int i=1;i<=6;i++) {
        lock_guard<mutex> guard(mpLock); // 使用互斥锁
        mp[i][C+2] = tmpFt[i] + mp[i][C+2];
    }
    waitfor(100);

    again:
    switch(getch()) {
        case 'r': returnVal = 0; break;
        case KEYESC: returnVal = 1; break;
        default: goto again; break;
    }}
    gameContinue = 1;

    for(int i=1;i<=6;i++) {
        lock_guard<mutex> guard(mpLock); // 使用互斥锁
        mp[i][C+2] = mp[i][C+2].substr(2);
        mp[i][C+3] += "  ";
    }
    for(int j=1;j<=CC;j++) {
        anWait(CC+1, j);
        lock_guard<mutex> guard(mpLock); // 使用互斥锁
        for(int i=1;i<=6;i++)
            mp[i][C+2] = mp[i][C+2].substr(2);
        for(int i=1;i<=6;i++)
            mp[i][C+3] += "  ";
    }
    anWait(CC+1, CC+1);
    for(int i=1;i<=6;i++) {
        lock_guard<mutex> guard(mpLock); // 使用互斥锁
        mp[i][C+3] = "    ";
        mp[i][C+2] = "";
    }
    waitfor(100);

    if(returnVal) {
        for(int j=0;j<=C+1;j++) {
            if(j != 0)
                anWait(C+6, j);
            {lock_guard<mutex> guard(mpLock); // 使用互斥锁
            for(int i=0;i<=R+1;i++) {
                mp[i][j] = "";
                if(j <= 4) {
                    mp[i][C+2] += "  ";
                }
            }}
        }
        for(int j=1;j<=6;j++) {
            anWait(C+6, C+1+j);
            {lock_guard<mutex> guard(mpLock); // 使用互斥锁
            for(int i=0;i<=R+1;i++) {
                if(mp[i][C+2].size() > 2) {
                    mp[i][C+2] = mp[i][C+2].substr(3);
                }
                else {
                    mp[i][C+2] = "";
                }
            }}
        }
        for(int i=1;i<=6;i++) {
            lock_guard<mutex> guard(mpLock); // 使用互斥锁
            mp[i][C+3] = "";
        }
    }
    return returnVal;
}
int pause() {
    int returnVal;
    const int CC = 13;
    {lock_guard<mutex> guard(kbInp);
    gameContinue = 0;

    string tmp[7];
    tmp[1] = "--------------------------";//13
    tmp[2] = "        Game Pause        ";
    tmp[3] = "   Press [E] to continue  ";
    tmp[4] = "   Press [R] to restart   ";
    tmp[5] = "   Press [Esc] to exit    ";
    tmp[6] = "--------------------------";
    string tmpBk[7] = {"", "+", "|", "|", "|", "|", "+"};
    string tmpFt[7] = {"", " +", " |", " |", " |", " |", " +"};
    for(int i=1;i<=6;i++) {
        lock_guard<mutex> guard(mpLock); // 使用互斥锁
        mp[i][C+3] = tmpBk[i];
    }
    for(int j=1;j<=CC;j++) {
        anWait(CC+1, j);
        lock_guard<mutex> guard(mpLock); // 使用互斥锁
        for(int i=1;i<=6;i++)
            mp[i][C+2] = tmp[i].substr(max(int(tmp[i].size()-j*2), 0));
    }
    anWait(CC+1, CC+1);
    for(int i=1;i<=6;i++) {
        lock_guard<mutex> guard(mpLock); // 使用互斥锁
        mp[i][C+2] = tmpFt[i] + mp[i][C+2];
    }
    waitfor(100);

    again:
    switch(getch()) {
        case 'r': returnVal = 0; break;
        case 'e': returnVal = -1; break;
        case KEYESC: returnVal = 1; break;
        default: goto again; break;
    }}
    gameContinue = 1;

    for(int i=1;i<=6;i++) {
        lock_guard<mutex> guard(mpLock); // 使用互斥锁
        mp[i][C+2] = mp[i][C+2].substr(2);
        mp[i][C+3] += "  ";
    }
    for(int j=1;j<=CC;j++) {
        anWait(CC+1, j);
        lock_guard<mutex> guard(mpLock); // 使用互斥锁
        for(int i=1;i<=6;i++)
            mp[i][C+2] = mp[i][C+2].substr(2);
        for(int i=1;i<=6;i++)
            mp[i][C+3] += "  ";
    }
    anWait(CC+1, CC+1);
    for(int i=1;i<=6;i++) {
        lock_guard<mutex> guard(mpLock); // 使用互斥锁
        mp[i][C+3] = "    ";
        mp[i][C+2] = "";
    }
    waitfor(100);

    if(returnVal == 1) {
        for(int j=0;j<=C+1;j++) {
            if(j != 0)
                anWait(C+6, j);
            {lock_guard<mutex> guard(mpLock); // 使用互斥锁
            for(int i=0;i<=R+1;i++) {
                mp[i][j] = "";
                if(j <= 4) {
                    mp[i][C+2] += "  ";
                }
            }}
        }
        for(int j=1;j<=6;j++) {
            anWait(C+6, C+1+j);
            {lock_guard<mutex> guard(mpLock); // 使用互斥锁
            for(int i=0;i<=R+1;i++) {
                if(mp[i][C+2].size() > 2) {
                    mp[i][C+2] = mp[i][C+2].substr(3);
                }
                else {
                    mp[i][C+2] = "";
                }
            }}
        }
        for(int i=1;i<=6;i++) {
            lock_guard<mutex> guard(mpLock); // 使用互斥锁
            mp[i][C+3] = "";
        }
    }
    return returnVal;
}

void doorSwitch() {
    do{
        for(int i=1; i<=9; i++) {
            if(exitSignal) break;
            waitfor(100);
        }
        if(DOOR == DOORNM)
            DOOR = DOORHL;
        else if(DOOR == DOORHL)
            DOOR = DOORNM;
    } while(!exitSignal);
}

void print() {
    do{
        {lock_guard<mutex> guard(mpLock); // 使用互斥锁
        // system("cls");
        string tmp;
        for(int i = 0; i <= R + 1; i++) {
            for(int j = 0; j <= C + 3; j++) {
                if(i == nx + dir[dirI][0] && j == ny + dir[dirI][1] && dirChange) {
                    switch(dirI) {
                        case 0: tmp += ARROWUP; break;
                        case 1: tmp += ARROWLF; break;
                        case 2: tmp += ARROWDN; break;
                        case 3: tmp += ARROWRT; break;
                    }
                    dirChange--;
                    continue;
                }
                if(mp[i][j] == "dr") tmp += DOOR;
                else tmp += mp[i][j];
            }
            if(i == R-7) tmp += "      score:    ";
            if(i == R-6) tmp += "        " + to_string(rp) + R"(/)" + to_string(TARGET) + "    ";
            if(i == R-4) tmp += "      tips:    ";
            if(i == R-3) tmp += "        " + string(DOOR) + R"( -> Portals    )";
            if(i == R-2) tmp += "        " + string(COIN) + R"( -> Coins    )";
            if(i == R-1) tmp += "        " + string(WALL) + R"( -> Walls    )";
            // if(i == R) {
            //  for(auto i:v) tmp+=to_string(i.first)+":"+to_string(i.second)+" ";
            // }// debug
            if(R + 1 != i) tmp += "\n";
        }
        cmdGoto(0, 0);
        cout << tmp;}
        waitfor(10);
    } while(!exitSignal);
}

void kbDetect() {
     do{
        lock_guard<mutex> guard(kbInp);
        if(_kbhit()) {
            switch(_getch()) {
                case 'w':  {
                    if(v.size() < 2 || make_pair(nx + dir[0][0], ny + dir[0][1]) != v[v.size() - 2]) {
                        dirI = 0;
                        dirChange = 10;
                    }
                    break;
                }
                case 'a': {
                    if(v.size() < 2 || make_pair(nx + dir[1][0], ny + dir[1][1]) != v[v.size() - 2]) {
                        dirI = 1;
                        dirChange = 10;
                    }
                    break;
                }
                case 's': {
                    if(v.size() < 2 || make_pair(nx + dir[2][0], ny + dir[2][1]) != v[v.size() - 2]) {
                        dirI = 2;
                        dirChange = 10;
                    }
                    break;
                }
                case 'd': {
                    if(v.size() < 2 || make_pair(nx + dir[3][0], ny + dir[3][1]) != v[v.size() - 2]) {
                        dirI = 3;
                        dirChange = 10;
                    }
                    break;
                }
                case KEYESC: {
                    pauseSignal = 1;
                    break;
                }
            }
        }
    } while(!exitSignal);
}

void spawnDoor() {
    int lx = -1000, ly = -1000;
    for(int i=1;i<=2;i++) {
        int x, y;
        do {
            x = getRand(1, R), y = getRand(1, C);
        } while((sqrt(pow(lx - x, 2) + pow(ly - y, 2)) < max(R, C) / 2)  || mp[x][y] != BLANK || (x >= nx - 3 && x <= nx + 3 && y >= ny - 3 && y <= ny + 3));
        lx = x, ly = y;
        lock_guard<mutex> guard(mpLock); // 使用互斥锁
        mp[x][y] = "dr";
    }
}
void spawnCoin(int t) {
    while(t--) {
        int x, y;
        do {
            x = getRand(1, R), y = getRand(1, C);
        } while(mp[x][y] != BLANK || (x >= nx - 1 && x <= nx + 1 && y >= ny - 1 && y <= ny + 3));
        lock_guard<mutex> guard(mpLock); // 使用互斥锁
        mp[x][y] = COIN;
    }
}
int setup() {
    int di;
    {lock_guard<mutex> guard(kbInp);
    dirI = getRand(0, 3);
    di = dirI;
    rp = 0;
    STARTLEN = LENST[Mode - 1];
    v.clear();
    nx = getRand(3, R-2), ny = getRand(3, C-2);

    // 初始化mp 
    {lock_guard<mutex> guard(mpLock); // 使用互斥锁
    for(int i=0;i<=R+1;i++) {
        mp[i][C + 1] = WALL;
    }}
    for(int j=1;j<=C;j++) {
        anWait(C+1, j);
        lock_guard<mutex> guard(mpLock); // 使用互斥锁
        mp[0][j] = WALL;
        for(int i=1;i<=R;i++) {
            mp[i][j] = BLANK;
        }
        mp[R + 1][j] = WALL;
    }
    anWait(C+1, C+1);
    {lock_guard<mutex> guard(mpLock); // 使用互斥锁
    for(int i=0;i<=R+1;i++) {
        mp[i][0] = WALL;
    }}
    {lock_guard<mutex> gurad(mpLock);
    for(int i=0;i<=R-8;i++){
        mp[i][C+2] = "                    ";
    }}
    waitfor(500);
    {lock_guard<mutex> gurad(mpLock);
    for(int i=0;i<=R+1;i++){
        mp[i][C+2] = "";
    }}}

    // 3 
    {lock_guard<mutex> guard(mpLock); // 使用互斥锁
    mp[nx][ny] = HEAD;
    v.push_back(make_pair(nx, ny)); 
    mp[nx + dir[di][0]*2][ny + dir[di][1]*2] = "3 ";}
    // 一些判断
    if(pauseSignal) {
        pauseSignal = 0;
        switch(pause()) {
            case 1: return 1; break;
            case 0: return 0; break;
            case -1: break;
        }
    }
    if(exitRightNow) {
        exitRightNow = false;
        return 1;
    }
    waitfor(RSPEED*5);

    // 2 
    {lock_guard<mutex> guard(mpLock); // 使用互斥锁
    mp[nx + dir[di][0]][ny + dir[di][1]] = BLANK;
    for(int i = 1; i <= R*C*WALLDENSITY; i++) {
        int x, y;
        do {
            x = getRand(1, R), y = y = getRand(1, C);
        } while(mp[x][y] != BLANK || (x >= nx - 1 && x <= nx + 1 && y >= ny - 1 && y <= ny + 3));
        mp[x][y] = WALL;
    }
    mp[nx + dir[di][0]*2][ny + dir[di][1]*2] = "2 ";}
    // 一些判断
    if(pauseSignal) {
        pauseSignal = 0;
        switch(pause()) {
            case 1: return 1; break;
            case 0: return 0; break;
            case -1: break;
        }
    }
    if(exitRightNow) {
        exitRightNow = false;
        return 1;
    }
    waitfor(RSPEED*4);

    // 1
    spawnDoor();
    spawnCoin(C*R*COINDENSITY);
    {lock_guard<mutex> guard(mpLock); // 使用互斥锁
    mp[nx + dir[di][0]*2][ny + dir[di][1]*2] = "1 ";}
    // 一些判断
    if(pauseSignal) {
        pauseSignal = 0;
        switch(pause()) {
            case 1: return 1; break;
            case 0: return 0; break;
            case -1: break;
        }
    }
    if(exitRightNow) {
        exitRightNow = false;
        return 1;
    }
    waitfor(RSPEED*4);

    // GO
    {lock_guard<mutex> guard(mpLock); // 使用互斥锁
    mp[nx + dir[di][0]*2][ny + dir[di][1]*2] = "GO";}
    // 一些判断
    if(pauseSignal) {
        pauseSignal = 0;
        switch(pause()) {
            case 1: return 1; break;
            case 0: return 0; break;
            case -1: break;
        }
    }
    if(exitRightNow) {
        exitRightNow = false;
        return 1;
    }
    waitfor(RSPEED*4);
    {lock_guard<mutex> guard(mpLock); // 使用互斥锁
    mp[nx + dir[di][0]*2][ny + dir[di][1]*2] = BLANK;}

    if(pauseSignal) {
        pauseSignal = 0;
        switch(pause()) {
            case 1: return 1; break;
            case 0: return 0; break;
            case -1: break;
        }
    }

    return -1;
}
void menu() {
    start:
        {lock_guard<mutex> guard(mpLock);
        for(int i=0;i<=7;i++) {
            mp[i][1] = "";
            mp[i][2] = "";
            mp[i][3] = "";
        }}
        {lock_guard<mutex> guard(kbInp); // 使用互斥锁
        int j = 2;
        {lock_guard<mutex> guard(mpLock);
        mp[0][2] = "   Menu: >Start< MapSize  Animation  About      ";
        mp[2][2] = "Choose your difficulty:";
        mp[3][2] = "  EaZy";
        mp[4][2] = "  HarD";
        mp[5][2] = "  INsane";
        mp[6][2] = "  SPcial";
        mp[7][2] = "(Press [E] to start)";}
        char ch = 0;
        while(1) {
            switch(ch) {
                case 's': {
                    j += (j > 3) ? 0 : 1;
                    break;
                }
                case 'w': {
                    j -= (j < 2) ? 0 : 1;
                    break;
                }
                case 'a': {
                    break;
                }
                case 'd': {
                    goto MapSize;
                    break;
                }
                case KEYESC: {
                    {lock_guard<mutex> guard(mpLock); // 使用互斥锁
                        cmdGoto(winR/2-3, winC/2-4);
                        puts("/------------------\\");
                        cmdGoto(winR/2-2, winC/2-4);
                        puts("|  Ready to Exit?  |");
                        cmdGoto(winR/2-1, winC/2-4);
                        puts("+--------+---------+");
                        cmdGoto(winR/2, winC/2-4);
                        puts("| [E]Yes | [Esc]No |");
                        cmdGoto(winR/2+1, winC/2-4);
                        puts("\\--------+---------/");
                        ch = 0;
                        while(1) {
                            switch(ch) {
                                case KEYESC: {
                                    goto nxt;
                                }
                                case 'e': {
                                    exitSignal = 1;
                                    system("cls");
                                    exit(0);
                                }
                            }
                            ch = getch();
                        }
                        nxt:
                        cmdGoto(winR/2-3, winC/2-4);
                        puts("                                    ");
                        cmdGoto(winR/2-2, winC/2-4);
                        puts("                                    ");
                        cmdGoto(winR/2-1, winC/2-4);
                        puts("                                    ");
                        cmdGoto(winR/2, winC/2-4);
                        puts("                                    ");
                        cmdGoto(winR/2+1, winC/2-4);
                        puts("                                    ");
                    }
                    break;
                }
                case 'e': {
                    Mode = j;
                    return;
                    break;
                }
            }
            COINDENSITY = COINST[j-1];
            WALLDENSITY = WALLST[j-1];
            RSPEED = RSPEEDST[j-1];
            TARGET = TARGETST[j-1];
            STARTLEN = LENST[j-1];
            HP = HPST[j-1];
            if(TARGET == -1) {
                TARGET = R*C/15;
            }
            {lock_guard<mutex> guard(mpLock);
            for(int i=1;i<=7;i++) mp[i][1] = "        ", mp[i][3] = "                             ";
            mp[j+2][1] = "     ->  ";}
            ch = getch();
        }}

    MapSize:
        {lock_guard<mutex> guard(mpLock);
        for(int i=0;i<=7;i++) {
            mp[i][1] = "";
            mp[i][2] = "";
            mp[i][3] = "";
        }}
        {lock_guard<mutex> guard(kbInp); // 使用互斥锁
        int k = screenSize;
        {lock_guard<mutex> guard(mpLock);
        mp[0][2] = "   Menu:  Start >MapSize< Animation  About      ";
        mp[2][2] = "Choose your size of map:";
        mp[3][2] = "  Minimum";
        mp[4][2] = "  Default";
        mp[5][2] = "  Midium";
        mp[6][2] = "  Maximum";
        mp[7][2] = "(Press [E] to set)";}
        char ch = 0;
        while(1) {
            switch(ch) {
                case 's': {
                    k += (k > 3) ? 0 : 1;
                    break;
                }
                case 'w': {
                    k -= (k < 2) ? 0 : 1;
                    break;
                }
                case 'a': {
                    goto start;
                    break;
                }
                case 'd': {
                    goto animation;
                    break;
                }
                case KEYESC: {
                    goto start;
                }
                case 'e': {
                    lock_guard<mutex> guard(mpLock);
                    if(screenSize != k) {
                        system("cls");
                    }
                    screenSize = k;
                    switch(screenSize) {
                        case 1: R = MINIR, C = MINIC; break;
                        case 2: R = DFTR, C = DFTC; break;
                        case 3: R = MIDR, C = MIDC; break;
                        case 4: R = MAXR, C = MAXC; break;
                    }
                    break;
                }
            }
            {lock_guard<mutex> guard(mpLock);
            for(int i=1;i<=7;i++) mp[i][1] = "        ", mp[i][3] = "                             ";
            mp[k+2][1] = "     ->  ";
            mp[screenSize+2][3] = " <- now                      ";}
            ch = getch();
        }}

    animation:
        {lock_guard<mutex> guard(mpLock);
        for(int i=0;i<=7;i++) {
            mp[i][1] = "";
            mp[i][2] = "";
            mp[i][3] = "";
        }}
        {lock_guard<mutex> guard(kbInp); // 使用互斥锁
        int k = animationSpeed;
        {lock_guard<mutex> guard(mpLock);
        mp[0][2] = "   Menu:  Start  MapSize >Animation< About      ";
        mp[2][2] = "Choose animation speed:";
        mp[3][2] = "  Smooth";
        mp[4][2] = "  Default";
        mp[5][2] = "  Fast";
        mp[6][2] = "  Very Fast";
        mp[7][2] = "(Press [E] to set)";}
        char ch = 0;
        while(1) {
            switch(ch) {
                case 's': {
                    k += (k > 3) ? 0 : 1;
                    break;
                }
                case 'w': {
                    k -= (k < 2) ? 0 : 1;
                    break;
                }
                case 'a': {
                    goto MapSize;
                    break;
                }
                case 'd': {
                    goto about;
                    break;
                }
                case KEYESC: {
                    goto start;
                }
                case 'e': {
                    animationSpeed = k;
                    break;
                }
            }
            {lock_guard<mutex> guard(mpLock);
            for(int i=1;i<=7;i++) mp[i][1] = "        ", mp[i][3] = "                             ";
            mp[k+2][1] = "     ->  ";
            mp[animationSpeed+2][3] = " <- now                      ";}
            ch = getch();
        }}

    about:
        {lock_guard<mutex> guard(mpLock);
        for(int i=0;i<=7;i++) {
            mp[i][1] = "";
            mp[i][2] = "";
            mp[i][3] = "";
        }}
        {lock_guard<mutex> guard(kbInp); // 使用互斥锁
        {lock_guard<mutex> guard(mpLock);
        mp[0][2] = "   Menu:  Start  MapSize  Animation >About<     ";
        mp[2][2] = "Creat by OrangeCitrus";
        mp[3][2] = "由橙子味的柑橘制作";
        mp[4][2] = "为什么要用英文?因为我有病(";
        mp[5][2] = R"(      /|_/| )";
        mp[6][2] = R"(|\_  | . .| )"; 
        mp[7][2] = R"(|__] \  ^ \ )";}
        char ch = 0;
        while(1) {
            switch(ch) {
                case 's': {
                    break;
                }
                case 'w': {
                    break;
                }
                case 'a': {
                    goto animation;
                    break;
                }
                case 'd': {
                    break;
                }
                case KEYESC: {
                    goto start;
                }
                case 'e': {
                    break;
                }
            }
            {lock_guard<mutex> guard(mpLock);
            for(int i=1;i<=7;i++) mp[i][1] = "        ", mp[i][3] = "                             ";}
            ch = getch();
        }}
}
int main() {
    system("cls");
    cmdGoto(0, 0);
    screenSize = 2;
    animationSpeed = 2;
    R = 20, C = 20;
    nx = R/2, ny = C/2;
//  system((string("mode con cols=") + to_string(winC * 2) + string(" lines=") + to_string(winR)).c_str());
    thread(keepWindow).detach();

    thread(doorSwitch).detach();
    thread(print).detach();
    thread(kbDetect).detach();

    {lock_guard<mutex> guard(mpLock); // 使用互斥锁
    mp[6][0] = "\tPress any key to get start.";
    mp[3][0] = "\tuse [W]/[A]/[S]/[D] to move,";
    mp[4][0] = "\t[Esc]/[E] to Quit/Enter.";}
    {lock_guard<mutex> guard(kbInp);
    getch();}
    {lock_guard<mutex> guard(mpLock); // 使用互斥锁
    mp[6][0] = "";
    mp[3][0] = "";
    mp[4][0] = "";}

    // 设置
    menu: 
    menu();
    {lock_guard<mutex> guard(mpLock);
    for(int i=0;i<=7;i++) {
        mp[i][1] = "";
        mp[i][2] = "";
        mp[i][3] = "";
    }}

    // 开始主程序 
    again:
    switch(setup()) {
        case 1: goto menu; break;
        case 0: goto again; break;
        case -1: break;
    }
    int hp = HP;
    do {
        int tx = nx + dir[dirI][0], ty = ny + dir[dirI][1];
        if(tx > R || tx < 1 || ty > C || ty < 1) {
            if(!hp) {
                if(fail(tx, ty, mp[tx][ty]))
                    goto menu;
                else
                    goto again;
            }
            hp--;
            goto stay;
        }

        // 下一个是DOOR 
        if(mp[tx][ty] == "dr") {
            {lock_guard<mutex> guard(mpLock); // 使用互斥锁
            mp[tx][ty] = BLANK;}
            for(int i = 1; i <= R; i++)
                for(int j = 1; j <= C; j++)
                    if(mp[i][j] == "dr") {
                        tx = i, ty = j;
                        nx = tx, ny = ty;
                        {lock_guard<mutex> guard(mpLock); // 使用互斥锁
                        mp[i][j] = DOORNM;}
                        for(int k=15;k>=1;k--) {
                            waitfor(k*10);
                            lock_guard<mutex> guard(mpLock); // 使用互斥锁
                            if(mp[i][j] == DOORNM)
                                mp[i][j] = DOORHL;
                            else if(mp[i][j] == DOORHL)
                                mp[i][j] = DOORNM;
                        }
                        spawnDoor();
                        lock_guard<mutex> guard(mpLock); // 使用互斥锁
                        mp[v[0].first][v[0].second] = BLANK;
                        v.erase(v.begin());
                        goto nxt;
                    }
        }
        //下一个是COIN 
        else if(mp[tx][ty] == COIN) {
            rp++;
            spawnCoin(1);
            goto nxt;
        }
        //下一个是WALL/BODY/HEAD 
        else if(mp[tx][ty] == WALL || mp[tx][ty] == BODY || mp[tx][ty] == HEAD) {
            if(!hp) {
                if(fail(tx, ty, mp[tx][ty]))
                    goto menu;
                else
                    goto again;
            }
            hp--;
            goto stay;
        }

        if(STARTLEN) {
            STARTLEN--;
            goto nxt;
        }

        // 删除蛇末尾 
        {lock_guard<mutex> guard(mpLock); // 使用互斥锁
        mp[v[0].first][v[0].second] = BLANK;}
        v.erase(v.begin());
        // 蛇向前进 
        nxt:
        v.push_back(make_pair(tx, ty));
        {lock_guard<mutex> guard(mpLock); // 使用互斥锁
        mp[v[v.size() - 2].first][v[v.size() - 2].second] = BODY;
        nx = tx, ny = ty;
        mp[tx][ty] = HEAD;}
        hp = HP;
        // 等待 
        stay:
        // 是否暂停
        if(pauseSignal) {
            pauseSignal = 0;
            switch(pause()) {
                case 1: goto menu; break;
                case 0: goto again; break;
                case -1: break;
            }
        }
        // 是否强制退出
        if(exitRightNow) {
            exitRightNow = false;
            goto menu;
        }

        waitfor(RSPEED);
    } while(rp < TARGET);

    if(win())
        goto menu;
    else
        goto again;

    return 0;
}

感谢游玩。

改自某位dalao10分钟写的小游戏

11.3 update

能且仅能使用c++11编译

编译命令加入-std=c++11

(是谁之前说要用c++14来着的...)