《C++小游戏》

· · 休闲·娱乐

游戏持续更新中,目前版本V1.8 \ 最近可能会断更一段时间,因为最近训练强度上来了摸不了鱼了qwq,感觉别人都是巨佬,而自己还是个蒟蒻 \ 代码长度:1627

废话不多说直接上代码!

喜欢的点个赞支持一下吧 \ (小声bb:感觉自己的码风排版都还不错,希望有人能看懂自己的代码并提出点改进建议(比如怪物巡逻机制,这是我个人目前还不满意的))

#include<bits/stdc++.h>
#include<conio.h>
#include<windows.h>
#define rint register int 
#define mmt(a,b) memset(a,b,sizeof(a))
#define test(x) cout<<#x<<" = "<<x<<endl
#define made by Polynswin
#define endl '\n'
#define enter putchar(endl)
//#define int long long
using namespace std;
const int inf=0x3f3f3f3f,N=5e2+10;
const int dir_get_dpx[9]={0,0,-1,-1,-1,0,1,1,1},
          dir_get_dpy[9]={0,1,1,0,-1,-1,-1,0,1},
          item_cht[N] = {-1, 4, 5, 6, 7};
int mapw, maph, score, cnt, dir;
int lasts, lasts2, fps, run, vision_radius, startTime, choose=1, Rclick, key, mob_dizzy_time = 4000, shown_dir;
int item[N], item_len=4;
vector<int> item_score= {-1, 20, 10, 15, 20},
            item_color= {-1, 1, 2, 5, 6};
bool clean_screen = true, enable =false, update_map, custom_map;
vector<string> item_name={"", "guide", "flash", "bomb", "vision"};
vector<string> mode_name = 
{       "",
        "特殊道具", "迷宫塌方", "收集钥匙", "爆炸伤害", "怪物追击", 
        "灯光不足(尚未开放)", "双人对战(尚未开放)", "特殊道具2(尚未开放)",
};
double cntttt=3, b_r = 0.75;//blocking_radius
int debug_cnt = 1,player_speed,mob_speed;
int last_time[N] = {-1, 0, -5001},
     interval[N] = {-1, 2000, 5000};
string numball[N] = {" ","①","②","③","④","⑤","⑥","⑦","⑧","⑨"};
int mode_init[N][N]=
{
    {},
    {-1, 10, 10, 2, 2, 1, 10},
    {-1, 20, 20, 5, 4, 3, 40} ,
    {-1, 40, 40, 12, 4, 8, 60},
    {-1, 100, 100, 100, 10, 20, 100},
    {-1, 0, 0, 0, 0},
},
    mode_item[N][N]=
{
    {},
    {-1, 1, 2, 0, 1},
    {-1, 3, 5, 3, 2},
    {-1, 7, 8, 5, 5},
    {-1, 20, 40, 20, 10},
    {-1, 0, 0, 0},
},
    mode_item_init[N][N]=
{
    {},
    {-1, 1, 1, 1, 0},
    {-1, 3, 1, 1, 0},
    {-1, 4, 2, 2, 0},
    {-1, 0, 3, 3, 1},
    {-1, 0, 0, 0},
}
    ;
bool mode[N];
string state;
char ptmap[N][N], mapx[N][N], map2[N][N];
bool game_over = false, out_of_menu = false;
bool debug=0,vis[N][N];
struct pos{
    int x,y;
    bool operator == (const pos &a) const
    {
        return a.x==x && a.y==y;
    }
    bool operator != (const pos &a) const
    {
        return a.x!=x || a.y!=y;
    }
}p, cam, vision, cam_dp, aim, last_pos, anchor, start, vision2, vision_init;
pos fa[N][N];
struct Path{
    pos ps;
    bool highlight;
};
struct Mob{
    int x,y,dir;
    int last_time_dizzy;
    pos locate;
    bool chasing;
};
char mob_cht = '!',mob_dizzy_cht = '~';
pos pre[N][N];
vector<Mob> mob;
vector<pos> wall, keys;
vector<Path> path;
void Color(int a);
void Setpos(int x,int y);
void RealSetpos(int x,int y);
void SlowDisplay(int x,string p);
void HideCursor();
void showCursor();
void win();
void lose();
int sprand(int l,int r);
int pow2(int x){  return x * x;  }
double _pow2(double x){  return x * x;  }
double calc_dist(pos a,pos b){  return sqrt( pow2(a.x-b.x) + pow2(a.y-b.y) ); }
void canvas(pos x,int color,string s){ Setpos(x.x,x.y); Color(color); cout<<s; }
double set_float(double x,int t){return int(x*pow(10,t))/pow(10,t);}
void fps_count();
void paint();
void button_check();
void player_check();
void player_move();
void game_update();
void print_menu();
void enter_menu();
void enter_custom_choose();
void enter_game(bool custom);
void enter_updates();
void enter_rule();
void enter_rule_item();
void enter_rule_mode();
void data_update();
void enter_setting();
void enter_difficulty_setting();
void enter_mode_setting();
void generate_item(int idx,int n);
void generate_mob(int n);
void generate_block(int n);
void generate_key(int n);
void generate_maze();
string str(int x);
pos find(pos x);
void ending_of_game();
bool join(pos a, pos b);
bool wall_check(int x);
bool dfs_get_way(pos cur);
bool bfs_get_way(pos s);
bool check_time(int x);
void mob_move();
void mob_detect(int i);
bool detecting_check(pos a,pos b);
void debug_out(string text);
bool mob_dizzy(int i);
bool press(char k,char x){bool res = k == x; if('a'<=x&&x<='z')res|= k == x - 'a' + 'A'; if('A'<=x&&x<='A')res|= k == x - 'A' + 'a';return res; }
inline void read(int &x);
inline void ffout(int x);
inline void ffout(int x,char b);
void enter_editor();
void save_map();
void load_map();
signed main()
{
    //made by Polynswin
    //部分windows代码 借鉴于胎神 luogu@TSzza 
    int i,j;
    srand(time(0));
    HideCursor();
    enter_menu();
    return 0;
}


bool bfs_get_way(pos s)
{
    for(rint i=1; i<=maph; ++i)
        for(rint j=1; j<=mapw; ++j)
            vis[i][j] = false;
    queue<pos> q;
    q.push(s);
    vis[s.x][s.y] = true;
    pre[s.x][s.y] = {-1,-1} ;//注:不重置也可以正常run 
    while(!q.empty())
    {
        pos u = q.front();
        q.pop();
        for(rint i=1; i<=4; ++i)
        {
            int tx = u.x+dir_get_dpx[(i<<1)-1], ty = u.y+dir_get_dpy[(i<<1)-1];
            if(tx<0 || ty<0 || tx>maph || ty>mapw || vis[tx][ty] || mapx[tx][ty]=='#')continue;
            vis[tx][ty] = true;
            pre[tx][ty] = u ;
            if(mapx[tx][ty] == '*')
            {
                pos cur = {tx,ty};
                while(pre[cur.x][cur.y] != pos({-1,-1}) )
                {
                    cur = pre[cur.x][cur.y];
                    path.push_back(Path({cur.x,cur.y,false}));
                }
                for(rint i=0; i<=(path.size()-1>>1); ++i)
                    swap(path[i],path[path.size()-i-1]);
                return true;
            }
            q.push(pos({tx,ty}));
        }
    }
    return false;
}
void edst_clean(int seth,int setw)
{
    for(rint i=1;i<=seth;++i)
        {canvas( {i,0}, 8, "  "); canvas( {i,setw+1}, 8, "  "); }
    for(rint i=0;i<=setw+1;++i)
        {canvas( {seth+1,i}, 8, "  "); canvas( {0,i}, 8, "  "); }
    for(rint i=1; i<=seth; ++i)
        for(rint j=1; j<=setw; ++j)
            canvas({i,j},0,"  ");

}
void enter_edst_cur2(int seth,int setw,bool *e_mode)
{

    int ent = 10, column = 2, cur = 1, len = mode_name.size() ;
    edst_clean(seth, setw);
    while(1)
    {
        for(rint i=1; i<=len; ++i)      
        {
            int tx = 1+(i-1)/column*2, ty = 2 + (i-1)%column*ent;
            if(cur == i)canvas({tx, ty-1},0, " >");
            else canvas({tx, ty-1},0, "  ");
            if(i==len)
            {
                canvas({tx,ty},0, "返回上一级");
                break;
            }
            int col=0;
            if(e_mode[i])col=2;
            canvas( {tx,ty}, col, mode_name[i]);
        }
        char k = getch();
        if(press(k, 'w'))cur = (cur-1 - column + len) % len + 1;
        if(press(k, 's'))cur = (cur-1 + column)%len + 1;
        if(press(k, 'a'))cur = (cur-2 + len) % len + 1;
        if(press(k, 'd'))cur = cur % len + 1;
        if(press(k, 'o'))
            if(cur!=len)e_mode[cur] ^= 1;
            else break;
        if(press(k, 27))break;
    }
    edst_clean(seth, setw);
}
void enter_edcs_setting()
{

}
void enter_editor()
{
    int curx = 1,cury = 1, chs = 1;
    int ct_maph = 10, ct_mapw = 10, tool_len, item_chs = 1;
    string state = "map";
    pos ct_start = {0,0}, ct_vision = {10,10},ed_vision = {10,10};
    int ct_item_init[N] = {-1, 0, 0, 0, 0};
    char ct_map[N][N];
    bool ct_mode[N];
    mmt(ct_mode,false);
    vector<char> tool_bar = {'1', ' ', '#', '*', 's', '@', (char)mob_cht, (char)item_cht[1]}; tool_len = tool_bar.size() - 1;
    mmt(ct_map,' ');
    cam_dp = {7,1};
    system("cls");
    update_map = true;
    while(1)
    {
        if(!ct_mode[1]) item_chs = 1;
        if(update_map)
        {
            canvas({-7,1},0, "map width: "+str(ct_mapw)+"    ");
            canvas({-6,1},0, "map height:"+str(ct_maph)+"    ");

            for(rint i=0;i<=ct_maph+1;++i)
                {canvas( {i,-1}, 8, "  "); canvas( {i,ct_mapw+2}, 8, "  "); }
            for(rint i=-1;i<=ct_mapw+2;++i)
                {canvas( {ct_maph+2,i}, 8, "▁▁"); canvas( {-1,i}, 8, "▁▁"); }

            for(rint i=0; i<=ct_mapw+1; ++i)
                {canvas( {ct_maph+1,i}, 0, "■"); canvas( {0,i}, 0, "■"); }
            for(rint i=1; i<=ct_maph; ++i)
                {canvas( {i,0}, 0, "■"); canvas( {i,ct_mapw+1}, 0, "■"); }
            for(rint i=1;i<=ct_maph;++i)
            {
                for(rint j=1;j<=ct_mapw;++j)
                {
                    Setpos(i,j);
                    if(ct_map[i][j] == '#'){ Color(0); cout<<"■"; }
                    if(ct_map[i][j] == '*'){ Color(8); cout<<"* "; }
                    if(ct_map[i][j] == 's'){ Color(8); cout<<"s "; }
                    if(ct_map[i][j] == '@'){ Color(8); cout<<"^ "; }
                    if(ct_map[i][j] == ' '){ Color(0); cout<<"  "; }
                    if(ct_map[i][j]==mob_cht){ Color(8); cout<<"●";}
                    for(rint k=1;k<=item_len;++k)
                        if(ct_map[i][j] == item_cht[k])
                            { Color(item_color[k]); cout<<"☆"; }
                }
            }
            for(rint i=1;i<=tool_len; ++i)
                if( i==chs)canvas({-4,i<<1},0,"↓");
                else canvas({-4,i<<1},0,"  ");
            for(rint i=1;i<=tool_len; ++i)
            {
                Setpos(-3,i<<1);
                if(tool_bar[i] == '#'){ Color(0); cout<<"■"; }
                if(tool_bar[i] == '*'){ Color(8); cout<<"* "; }
                if(tool_bar[i] == 's'){ Color(8); cout<<"s "; }
                if(tool_bar[i] == ' '){ Color(3); cout<<"×"; }
                if(tool_bar[i] == '@'){ Color(8); cout<<"^ "; }
                if(tool_bar[i]==mob_cht){ Color(8); cout<<"●";}
                if(i == 7 ){ Color( item_color[item_chs] ); cout<<"☆"; }
            }
            for(rint i=1;i<=tool_len; ++i)
                canvas({-2,i<<1},0,numball[i]);
//          if(clock()%1000 < 500)canvas({curx,cury},0, "  "); 
            canvas({curx+1,cury},0, "↑"); 
        }
        update_map = false;
        if(kbhit())
        {
            char k =getch();
            if(state == "map")
            {
                if(press(k, 'w'))curx = (curx-2+ct_maph) % ct_maph + 1, update_map = true;
                if(press(k, 's'))curx = curx%ct_maph + 1, update_map = true;
                if(press(k, 'a'))cury = (cury-2+ct_mapw) % ct_mapw + 1, update_map = true;
                if(press(k, 'd'))cury = cury%ct_mapw + 1, update_map = true;

                if('1'<=k&&k<=tool_len + '0')
                {
                    if(k == '7' && chs == 7)
                    {
                        if(ct_mode[1]) item_chs = item_chs%item_len + 1;    
                        else item_chs =  1; 
                        tool_bar[7] = item_cht[item_chs];
                    }
                    chs = k - '0'; update_map = true;
                }
            }
            if(press(k, 27))
            {
                cam_dp = {7,ct_maph>>1};
                int setw = 22,seth = 10, cur = 1,len;
                vector<string> text = {" ", "修改游戏参数", "修改游戏模式", "加载地图", "保存地图", "退出编辑器"};
                len = text.size() - 1;
                int column = 2, ent = 14;
                edst_clean(seth, setw);
                while(1)
                {
                    for(rint i=1; i<=len ; ++i)
                    {
                        int tx = 1+(i-1)/column*2, ty = 2 + (i-1)%column*ent;
                        if(cur == i)canvas({tx, ty-1},0, " >");
                        else canvas({tx, ty-1},0, "  ");
                        canvas( {tx,ty}, 0, text[i]);
                    }
                    char k = getch();
                    if(press(k, 'w'))cur = (cur-1 - column + len) % len + 1;
                    if(press(k, 's'))cur = (cur-1 + column)%len + 1;
                    if(press(k, 'a'))cur = (cur-2 + len) % len + 1;
                    if(press(k, 'd'))cur = cur % len + 1;
                    if(press(k, 27))
                    {
                        update_map = true;
                        break;
                    }
                    if(press(k, 'o'))
                    {
                        if(cur == 1)
                        {
                            int cur2 = 1, column2 = 1, len2 = 4;
                            vector<string> text = {"", "迷宫宽度:", "迷宫长度:", "初始视野宽度:", "初始视野长度:"
                                , "初始引导之星数量:", "初始闪现数量:", "初始炸弹数量:", "初始探远星数量:"
                            };
                            vector<int*> value = {NULL, &ct_mapw, &ct_maph, &ct_vision.x, &ct_vision.y};
                            for(rint i=1; i<=item_len; ++i)
                                value.push_back(&ct_item_init[i]);
                            len2 = text.size() - 1;
                            edst_clean(seth, setw);
                            while(1)
                            {
                                for(rint i=1; i<=len2; ++i)
                                {
                                    if(i == cur2)canvas({i,2},0 , " >");
                                    else canvas({i,2},0 , "  ");
                                    canvas({i,3},0 , text[i]);
                                    canvas({i,3+text[i].size()/2},0 , str(*value[i]) + "    ");
                                }
                                char k = getch();
                                if(press(k, 27))
                                    break;
                                if(press(k, 'w'))cur2 = (cur2-1 - column2 + len2) % len2 + 1;
                                if(press(k, 's'))cur2 = (cur2-1 + column2)%len2 + 1;
                                if(press(k, 'o'))
                                {
                                    showCursor();
                                    canvas({cur2,3+text[cur2].size()/2},0 , "    ");
                                    Setpos(cur2,3+text[cur2].size()/2);
                                    cin>>*value[cur2];
                                    HideCursor();
                                }
                            }
                            edst_clean(seth, setw);
                        }
                        if(cur == 2) enter_edst_cur2(seth,setw,ct_mode);
                        if(cur == len - 2)
                        {
                            edst_clean(seth, setw);
                            canvas({seth>>1,setw/2-7}, 0, "这会覆盖当前地图编辑,你确定要这么做吗"); 
                            canvas({seth/2+2,setw/2-4}, 0, "确认"); 
                            canvas({seth/2+2,setw/2+4}, 0, "取消"); 
                            bool confirm = 1;
                            while(1)
                            {
                                if(confirm)canvas({seth/2+2,setw/2-5}, 0, " >"), canvas({seth/2+2,setw/2+3}, 0, "  ");
                                else canvas({seth/2+2,setw/2-5}, 0, "  "), canvas({seth/2+2,setw/2+3}, 0, " >");
                                char k =getch();
                                if(press(k, 'a') || press(k, 'd')) confirm ^= 1;
                                if(press(k, 'o'))break;
                            }
                            if(!confirm)
                            {
                                edst_clean(seth, setw);
                                continue;
                            }
                            ifstream in("maze.pm");
                            in>>ct_mapw>>ct_maph>>ct_vision.x>>ct_vision.y;
                            for(rint i=1; i<=item_len; ++i)
                                in>>ct_item_init[i];
                            for(rint i=1; i<=mode_name.size() - 1; ++i)
                                in>>ct_mode[i];
                            for(rint i=1; i<=ct_maph; ++i)
                                for(rint j=1; j<=ct_mapw; ++j)
                                {
                                    int x;
                                    in>>x;
                                    ct_map[i][j]=char(x);
                                    if(ct_map[i][j] == 's') ct_start = pos({i,j});
                                }
                            in.close();
                            for(rint i=0; i<=ct_mapw+1; ++i)
                                ct_map[0][i] = ct_map[ct_maph+1][i] = '#';
                            for(rint i=1; i<=ct_maph; ++i)
                                ct_map[i][0] = ct_map[i][ct_mapw+1] = '#';
                            edst_clean(seth, setw);
                            canvas({seth>>1,setw/2-2}, 0, "地图已读取"); 
                            Sleep(2000);
                            break;

                        }
                        if(cur == len - 1)
                        {
                            ofstream out("maze.pm");
//                          out<<ct_mob.size()<<" ";
//                          for(rint i=0; i<mob.size(); ++i)
//                              out<<"{"<<mob[i].x<<","<<mob[i].y<<"} ";
                            out<<ct_mapw<<" "<<ct_maph<<" "<<ct_vision.x<<" "<<ct_vision.y<<endl;
                            for(rint i=1; i<=item_len; ++i)
                                out<<ct_item_init[i]<<" ";
                            out<<endl;
                            for(rint i=1; i<=mode_name.size() - 1; ++i)
                                out<<ct_mode[i]<<" ";
                            out<<endl;
                            for(rint i=1; i<=ct_maph; ++i)
                            {
                                for(rint j=1; j<=ct_mapw; ++j)
                                    out<<int(ct_map[i][j])<<" ";
                                out<<endl;
                            }
                            out<<endl;
                            out.close();
                            edst_clean(seth, setw);
                            canvas({seth>>1,setw/2-2}, 0, "地图已保存"); 
                            Sleep(2000);
                            break;
                        }
                        if(cur == len)
                            enter_menu();
                    }
                }
                update_map = true;
                system("cls");
                cam_dp = {7,1};
            }
//          if(press(k, 'q'))
//          {
//              if(state == "map")
//              update_map = true;
//          }
        }
        if(GetAsyncKeyState('O')&0x8000)
        {
            if(tool_bar[chs] == 's')
            {
                ct_start = {curx,cury};
                if(ct_map[ct_start.x][ct_start.y] == 's') ct_map[ct_start.x][ct_start.y] = ' ';
             } 
            ct_map[curx][cury] = tool_bar[chs];
            update_map = true;
        }
    }
}
void load_map()
{
    ifstream in("maze.pm");
    vector<int*> value = {NULL, &mapw, &maph, &vision_init.x, &vision_init.y};
    for(rint i=1; i<=item_len; ++i)     
        value.push_back(&mode_item_init[0][i]);
    int len = value.size() - 1;
    for(rint i=1; i<=len; ++i)  in>>*value[i];
    for(rint i=1; i<=mode_name.size() - 1; ++i) in>>mode[i];
    for(rint i=1; i<=item_len ; ++i) item[i] = mode_item_init[0][i];
//  debug_out(str(mapw));
//  debug_out(str(maph));
//  debug_out(str(maph));
    for(rint i=0; i<=mapw+1; ++i)
        mapx[0][i] = mapx[maph+1][i] = '#';
    for(rint i=1; i<=maph; ++i)
        mapx[i][0] = mapx[i][mapw+1] = '#';
    for(rint i=1; i<=maph; ++i)
        for(rint j=1; j<=mapw; ++j)
        {
            int x;
            in>>x;

//          debug_out(str(i)+" "+str(j)+" "+str(x));
//          system("pause");
//          debug_out(str(i)); debug_out(str(j));
            if(x == '!') mob.push_back(Mob( {i,j,1, 0, {0,0}, false} ));
            if(x == '#' || x == '*') mapx[i][j] = x;
            if(x == 's') 
            {
                p = pos({i,j});
                continue;//纪念第一个调了我1个小时的bug,continue 打成 break 了 
            }
            bool flag = false;
            for(rint k=1; k<=item_len; ++k)
                if(x == item_cht[k])
                {
                    flag = true;
                    break;
                }
            if(flag || x == '@') 
            {
                map2[i][j] = x;
                if(x == '@')
                {
                    key++;
                    keys.push_back(pos({i,j}));
                }
            }
        }
//  system("pause");

}
void save_map()
{
    ofstream out("maze.pm");
    out<<mob.size()<<" ";
    for(rint i=0; i<mob.size(); ++i)
        out<<"{"<<mob[i].x<<","<<mob[i].y<<"} ";
    out.close();
    for(rint i=1; i<=maph; ++i)
    {
        for(rint j=1; j<=mapw; ++j)
            out<<int(mapx[i][j])<<" ";
        out<<endl;
    }
    out<<endl;
    for(rint i=1; i<=maph; ++i)
    {
        for(rint j=1; j<=mapw; ++j)
            out<<int(map2[i][j])<<" ";
        out<<endl;
    }
    out<<endl;
}

void debug_out(string text)
{
//  return;
    Setpos(++debug_cnt,-20);
    cout<<text<<"                     ";
    debug_cnt%=20;
}
bool mob_dizzy(int i)
{
    return clock()-mob[i].last_time_dizzy <= mob_dizzy_time;
}
void mob_move()
{
    update_map = true;
    for(rint i=0;i<mob.size();++i)
    {
        if(mob_dizzy(i))continue;
        mob_detect(i);
        if(!mob[i].chasing)
        {
//          continue;
            int tx= mob[i].x + dir_get_dpx[mob[i].dir * 2 -1],
                ty= mob[i].y + dir_get_dpy[mob[i].dir * 2 -1];
            int t=(mob[i].dir+1)%4+1;
            vector<int> go_dir = {0,1,2,3,4};

            go_dir.erase(go_dir.begin()+ (mob[i].dir+1)%4+1 );

            mob[i].dir = go_dir[sprand(1, go_dir.size()-1)];

            while(mapx[tx][ty]=='#' && go_dir.size()>1)
            {
                int ri=sprand(1, go_dir.size()-1);
                mob[i].dir = go_dir[ri];
                tx= mob[i].x + dir_get_dpx[mob[i].dir * 2 -1],
                ty= mob[i].y + dir_get_dpy[mob[i].dir * 2 -1];
                go_dir.erase(go_dir.begin()+ ri );
            }
            if(mapx[tx][ty]=='#')
            {
                mob[i].dir = t;
                tx= mob[i].x + dir_get_dpx[mob[i].dir * 2 -1],
                ty= mob[i].y + dir_get_dpy[mob[i].dir * 2 -1];
                if(mapx[tx][ty]=='#')continue;
            }
            mob[i].x= tx; mob[i].y= ty;
        }
        else
        {
            if(mob[i].locate.x == mob[i].x)
            {
                mob[i].y += mob[i].y>p.y ? -1:1 ;
                continue;
            }
            double k = (mob[i].locate.y-mob[i].y)*1.0 / (mob[i].locate.x-mob[i].x) ;
            double c = -k * mob[i].x + mob[i].y;
            int ty=mob[i].y + ( (mob[i].y>mob[i].locate.y) ? -1:1 ),
                tx=mob[i].x + ( (mob[i].x>mob[i].locate.x) ? -1:1 );
//          debug_out("out");
            if(_pow2(-k*mob[i].x + ty - c) <= b_r*b_r * ( k*k + 1) && mapx[mob[i].x][ty]!='#')mob[i].y = ty;
            else if(mapx[tx][mob[i].y]!='#')mob[i].x = tx ;
        }
    }
//  debug_out("move_over");
}
bool detecting_check(pos a,pos b,int idx)
{
    if(a.x==b.x)
    {
        int l=min(a.y,b.y),r=max(a.y,b.y);
        for(rint i=l; i<=r; ++i)
            if(mapx[a.x][i]=='#')return false;
        return true;
    }
    //y = kx + c
    //-kx + y - c = 0
    double k = (b.y-a.y)*1.0 / (b.x-a.x) ;
    double c = -k * a.x + a.y;
    int l=min(a.x,b.x), r=max(a.x,b.x);
//  debug_out("step1");
    for(int i=l; i<=r; ++i)
    {
//      debug_out("loop");
        for(int j=k*i + c; j>=min(a.y,b.y) && j<=max(a.y,b.y) ;--j)
            if(_pow2(-k*i + j - c) <= b_r*b_r * ( k*k + 1))
            {
//              canvas({i-cam.x+1,j-cam.y+1}, 0, "@ ");
                if(mapx[i][j]=='#')return false;
            }
            else break; 
        for(int j=ceil( k*i + c); j>=min(a.y,b.y) && j<=max(a.y,b.y) ;++j)
            if(_pow2(-k*i + j - c) <= b_r*b_r * ( k*k + 1))
            {
//              canvas({i-cam.x+1,j-cam.y+1}, 0, "@ ");
                if(mapx[i][j]=='#')return false;
            }
            else break;
    }
    return true;
}
void mob_detect(int i)
{
//  debug_out("detecting");
    if(abs(mob[i].x-p.x)+abs(mob[i].y-p.y)>=20)return;
        if( detecting_check({mob[i].x,mob[i].y}, p, i) )
        {
            mob[i].chasing = true;
//          debug_out("detected");
            mob[i].locate = p;
        }
        else 
        {

        if(mob[i].locate.x==mob[i].x && mob[i].locate.y==mob[i].y )mob[i].chasing = false;
//          vector<int> pb_dir;//possible direction
//          for(rint j=1;j<=4;++j)
        }



//  debug_out("over");
}
bool check_time(int x)
{
    return clock()-last_time[x] >= interval[x];
}
bool dfs_get_way(pos cur)
{
    debug_out(str(cur.x)); debug_out(str(cur.y));
    if(mapx[cur.x][cur.y] == '*')return true;
    if(vis[cur.x][cur.y])return false;
    vis[cur.x][cur.y]=true;
    if(cur.x!=start.x||cur.y!=start.y)path.push_back( Path( {cur, false} ));
    for(int i=1;i<=4;i++)
    {
        int tx=cur.x+dir_get_dpx[i*2-1],ty=cur.y+dir_get_dpy[i*2-1];
        if(mapx[tx][ty]=='#' || tx<0 || ty<0 || tx>maph || ty>mapw)continue;
        if(dfs_get_way( {tx,ty} ))return true;
    }
    path.pop_back();
    vis[cur.x][cur.y]=false;
    return false;
}
struct node{
    int idx;
    double dis;
};
vector<node> t;
bool cmp(node a, node b){
    return a.dis<b.dis;
}
pos find(pos x)
{
    return (fa[x.x][x.y].x == x.x && fa[x.x][x.y].y == x.y) ? x : fa[x.x][x.y] = find(fa[x.x][x.y]);
}
bool join(pos a, pos b)
{
    pos af = find(a), bf = find(b);
    if(af.x != bf.x || af.y != bf.y)
    {
        fa[bf.x][bf.y]=af;
        return true;
    }
    return false;
}
bool wall_check(int x)
{
    if(wall.empty())return false;
    int ax,ay,bx,by;
    if(wall[x].x&1)ax = wall[x].x, ay = wall[x].y-1, bx = wall[x].x, by = wall[x].y+1;
    else ax = wall[x].x-1, ay = wall[x].y, bx = wall[x].x+1, by = wall[x].y;
    if( join( {ax,ay}, {bx,by} ) )
    {
//      test(wall[x].x);
//      test(wall[x].y);
        mapx[wall[x].x][wall[x].y] = ' ';
        wall.erase(wall.begin()+x);
        return true;
    }
    wall.erase(wall.begin()+x);
    return false;
}
void generate_maze()
{

    mmt(mapx,' ');
    int tot = 0;
    wall.clear();
    for(rint i=1;i<=maph;++i)
        for(rint j=1;j<=mapw;++j)
        {
            fa[i][j] = { i, j };
            if( i&1 && j&1 )mapx[i][j]=' ',tot++;
            else mapx[i][j]='#';
            if( (i&1) ^ (j&1) )wall.push_back(pos( {i,j} ) );
        }
    for(rint i=0;i<=maph+1;++i)
        mapx[i][0]=mapx[i][mapw+1]='#';
    for(rint i=1;i<=mapw;++i)
        mapx[0][i]=mapx[maph+1][i]='#';
    for(rint i=1; i<=tot && !wall.empty(); ++i)
        while(wall_check( sprand( 0, wall.size()-1 ) ) && !wall.empty());
    mapx[maph][mapw] = '*';
    wall.clear();
    if(mode[5])
    {
        for(rint i=1; i<=maph; ++i)
            for(rint j=1; j<=mapw; ++j)
                if(mapx[i][j]=='#')wall.push_back(pos({i,j}));
        for(rint i=1; i<=mode_init[choose][6]; ++i)
        {
            int rx=sprand(1,maph),
                ry=sprand(1,mapw);
            while(mapx[rx][ry]!='#')rx=sprand(1,maph),ry=sprand(1,mapw);
            mapx[rx][ry]=' ';
        }
    }

}
void generate_item(int idx,int n)
{
    for(int i=1;i<=n;++i)
    {
        int rx=sprand(1,maph),
            ry=sprand(1,mapw);
        while(mapx[rx][ry]!=' ' || map2[rx][ry]!=' ')rx=sprand(1,maph),ry=sprand(1,mapw);
        map2[rx][ry]=item_cht[idx];
    }
}
void generate_mob(int n)
{
    for(int i=1;i<=n;++i)
    {
        int rx=sprand(1,maph),
            ry=sprand(1,mapw);
        while(mapx[rx][ry]!=' ' || map2[rx][ry]!=' ')rx=sprand(1,maph),ry=sprand(1,mapw);
        mob.push_back(Mob( { rx, ry, 1, 0, {0,0}, false} ));
    }
}
void generate_key(int n)
{
    key = n;
    for(int i=1;i<=n;++i)
    {
        int rx=sprand(1,maph),
            ry=sprand(1,mapw);
        while(mapx[rx][ry]!=' ' || map2[rx][ry]!=' ')rx=sprand(1,maph),ry=sprand(1,mapw);
        map2[rx][ry]='@';
        keys.push_back( pos({rx,ry}) );
    }
}
void generate_block(int n)
{
    int ln=sprand(1,n>>1);
    for(rint i=1;i<=ln;++i)
    {
        int ri=sprand(0,path.size()-1);
        int rx = path[ri].ps.x,ry = path[ri].ps.y;
        int tot = 0;
        while(mapx[rx][ry]!=' ' || map2[rx][ry]!=' ')
        {
            rx=sprand(1,maph),ry=sprand(1,mapw);
            if(tot>=1000)break;
        }
            if(tot>=1000)break;
        mapx[rx][ry]= '#';
    }
    for(rint i=1;i<=n-ln;++i)
    {
        int rx=sprand(1,maph),
            ry=sprand(1,mapw);
        while(mapx[rx][ry]!=' ' || map2[rx][ry]!=' ')rx=sprand(1,maph),ry=sprand(1,mapw);
        mapx[rx][ry]= '#';
    }
}
void game_update()
{
    paint();
    if(clean_screen)
    {
        clean_screen = false;
        system("cls");
    }
    for(rint i=1;i<=vision.x;++i)
        {canvas( {i,0}, 8, "  "); canvas( {i,vision.y+1}, 8, "  "); }
    for(rint i=0;i<=vision.y+1;++i)
        {canvas( {vision.x+1,i}, 8, "▁▁"); canvas( {0,i}, 8, "▁▁"); }
    for(rint i=1; i<=vision.x; ++i)
        for(rint j=1; j<=vision.y; ++j)
        {
            int tx=i+cam.x-1,ty=j+cam.y-1;
            Setpos(i,j);
            if(tx<0 || ty<0 || tx>maph+1 || ty>mapw+1 )
            {
                Color(0);
                cout<<"  ";
                continue;
            }
//          Color(0); cout<<"--";
            if(ptmap[tx][ty]==' '){ Color(0); cout<<"  ";}
            if(ptmap[tx][ty]==0){ Color(7); cout<<"●";}
            if(ptmap[tx][ty]==1){ Color(3); cout<<"●";}
            if(ptmap[tx][ty]==2){ Color(4); cout<<"●";}
            if(ptmap[tx][ty]==3){ Color(8); cout<<"☆";}
            if(ptmap[tx][ty]=='#'){ Color(0); cout<<"■";}
            if(ptmap[tx][ty]=='*'){ if(mode[3]&&key)Color(5);else Color(8); cout<<"* ";}
            if(ptmap[tx][ty]=='@'){ Color(8); cout<<"^ ";}
            if(ptmap[tx][ty]==mob_cht){ Color(8); cout<<"●";}
            if(ptmap[tx][ty]==mob_dizzy_cht){ Color(7); cout<<"●";}
            if(ptmap[tx][ty]==item_cht[1]){ Color(1); cout<<"☆";}
            if(ptmap[tx][ty]==item_cht[2]){ Color(2); cout<<"☆";}
            if(ptmap[tx][ty]==item_cht[3]){ Color(5); cout<<"☆";}
            if(ptmap[tx][ty]==item_cht[4]){ Color(6); cout<<"☆";}
        }
    canvas({-2,0},0,"time = " + str(  (clock()*1.0-startTime)/1000 ) + "  score = "+str(score) + "   fps =" + str(fps)); 
    canvas({-1,0},0,"x,y = " + str(p.x) + " " + str(p.y) + "   "); 
    int top=0,cur=0;
    while(top<item_len)
    {
        top++;
        if(mode[2] && top==1 && !mode[3])continue;
        if(!mode[1] && top>1)continue;
        canvas({vision.x+2+cur/2,1+cur%2*6}, 0, item_name[ top ] +" = "+ str(item[top]) + "       ");
        cur++; 
    }
    if(mode[3])canvas({vision.x+2+cur/2,1+cur%2*6}, 0, "key = "+ str(key) ),cur++;
    if(!check_time(2))
    {
//      if(last_pos.x != -1 && (last_pos.x!=cx || last_pos.y!=cy) )canvas({last_pos.x,last_pos.y},0, "   ");
        string out;
        if(anchor.x==p.x)
            if(anchor.y < p.y)shown_dir = 1;
            else shown_dir = 5;
        if(anchor.y==p.y)
            if(anchor.x < p.x)shown_dir = 3;
            else shown_dir = 7;
        if(anchor.x<p.x && anchor.y>p.y) shown_dir = 2 ;
        if(anchor.x<p.x && anchor.y<p.y) shown_dir = 4 ;
        if(anchor.x>p.x && anchor.y<p.y) shown_dir = 6 ;
        if(anchor.x>p.x && anchor.y>p.y) shown_dir = 8 ;
        int cx = p.x - cam.x + 1 + dir_get_dpx[shown_dir], cy = p.y - cam.y + 1 + dir_get_dpy[shown_dir];
        if(shown_dir == 1)out = "→";
        if(shown_dir == 5)out = "←";
        if(shown_dir == 3)out = "↑";
        if(shown_dir == 7)out = "↓";
        if(shown_dir == 2)out = "↗";
        if(shown_dir == 4)out = "↖";
        if(shown_dir == 6)out = "↙";
        if(shown_dir == 8)out = "↘"; 
        if((clock()-last_time[2]) % 1000 < 500) canvas({cx,cy},0, out) ;
    }
    else if(shown_dir)shown_dir = 0;
}
void player_move()
{
    update_map = true;
    if(GetAsyncKeyState('W')&0x8000)
    {
        if(mapx[p.x-1][p.y]!='#' || debug)p.x--;
        dir=2;
    }
    if(GetAsyncKeyState('S')&0x8000  )
    {
        if(mapx[p.x+1][p.y]!='#' || debug)p.x++;
        dir=4;
    }
    if(GetAsyncKeyState('A')&0x8000  )
    {
        if(mapx[p.x][p.y-1]!='#' || debug)p.y--;
        dir=3;
    }
    if(GetAsyncKeyState('D')&0x8000  )
    {
        if(mapx[p.x][p.y+1]!='#' || debug)p.y++;
        dir=1;
    }
    if(maph-vision.x>0)cam.x=min( max(p.x-(vision.x-1 >> 1), 0) , maph-vision.x+2);
    else cam.x= maph-vision.x+2>>1; 
    if(mapw-vision.y>0)cam.y=min( max(p.y-(vision.y-1 >> 1), 0) , mapw-vision.y+2); 
    else cam.y= mapw-vision.y+2>>1; 
    if(mode[1])
        for(rint i=3; i>=0 ; --i)
        {
            int tx= p.x+dir_get_dpx[dir*2-1]*i, ty= p.y+dir_get_dpy[dir*2-1]*i;
            if(tx<0 || tx>maph || ty<0 || ty>mapw || mapx[tx][ty]=='#')continue;
            aim = {tx,ty};
            break;
        } 
}
void player_check()
{
    if(mapx[p.x][p.y] == '*' && (!key || !mode[3])) win();
    for(rint i=1; i<=item_len ; ++i)
        if(map2[p.x][p.y]==item_cht[i])
        {
            item[i]++;
            map2[p.x][p.y] = ' ';
            score += item_score[4];
            update_map = true;
        }
    for(rint i=0; i<mob.size() ; ++i)
        if(p == pos( {mob[i].x,mob[i].y} ) && !mob_dizzy(i) ) lose();
    if(map2[p.x][p.y]=='@' && mode[3])
    {
        update_map = true;
        key --;
        for(rint i=0; i<keys.size(); ++i)
            if(keys[i].x == p.x && keys[i].y == p.y)
                keys.erase(keys.begin() + i);
        map2[p.x][p.y] = ' ';
    }

}
void paint()
{
    for(rint i=1;i<=vision.x;++i)
        for(rint j=1;j<=vision.y;++j)
        {
            int tx=i+cam.x-1,ty=j+cam.y-1;
            if(tx<0 || ty<0 || tx>maph+1 || ty>mapw+1 )
                continue;
            ptmap[tx][ty]=mapx[tx][ty];
        }
    for(rint i=1;i<=vision.x;++i)
        for(rint j=1;j<=vision.y;++j)
        {
            int tx=i+cam.x-1,ty=j+cam.y-1;
            if(tx<0 || ty<0 || tx>maph+1 || ty>mapw+1 )
                continue;
            if(map2[tx][ty]!=' ')ptmap[tx][ty]=map2[tx][ty];
        }
    if(mode[1])ptmap[aim.x][aim.y]=2;
    for(rint i=0;i<mob.size();++i)
        if(!mob_dizzy(i))ptmap[mob[i].x][mob[i].y]=mob_cht;
        else ptmap[mob[i].x][mob[i].y]=mob_dizzy_cht;
    ptmap[p.x][p.y]=1;
}
void button_check()
{

    if(kbhit())
    {
        char k=getch();
        if( press( k, 'r') )
        {
            update_map = true;
            Rclick ++;
            if(Rclick == 1)
            {
                last_time[1] = clock();
                canvas({-3,0}, 0, "Press R again to confirm suicide");
            }
            if(Rclick == 2)lose();
        }
        if(check_time(1))update_map = true, Rclick = 0,canvas({-2,0}, 0, "                                    ");
        if(press( k, 'u') && item[1]>0  )
        {
            if(mode[3] && key )
            {
                double minx = inf;
                for(rint i = 0; i<keys.size(); ++i)
                    if(minx > calc_dist(keys[i], p) )
                    {
                        minx = calc_dist(keys[i], p);
                        anchor = keys[i];
                    }
//              debug_out(str(chs.x) + " " + str(chs.y) + " " + str(shown_dir));
                last_time[2] = clock();
            }
            if(!mode[2] && path.size())
            {
                t.clear();
                for(rint i=0;i<path.size();++i)
                    if(!path[i].highlight)t.push_back( node( { i, calc_dist(p,path[i].ps) } ) );
                sort(t.begin(),t.end(),cmp);
                int l=t.size();
                for(rint i=0; i< min(5, l-1 ) ; ++i)
                {
                    path[t[i].idx].highlight=true;
                    mapx[ path[t[i].idx].ps . x ][ path[t[i].idx].ps . y ] = 3;
                }
            }
            if(!mode[2] || (mode[3] && key)) item[1] --, score += item_score[1],update_map = true;
        }
        if(press( k, 'i') && item[2]>0 && mode[1])
        {
            update_map = true;
            p = aim;
            item[2] --; score += item_score[2];
        }
        if(press(k, 'o') && item[3]>0 && mode[1])
        {
            update_map = true;
            for(rint i=0; i<=8 ; ++i)
            {
                int tx= aim.x+dir_get_dpx[i],ty= aim.y+dir_get_dpy[i];
                if(tx==p.x && ty==p.y && mode[4])lose();
                if(mode[4])
                    for(rint j=0; j<mob.size(); ++j)
                        if( pos({mob[j].x,mob[j].y}) == pos({tx,ty}) )
                            mob[j].last_time_dizzy=clock();
                if(mapx[tx][ty] == '#'  && (tx>0 && tx<=maph && ty<=mapw && ty>0)   )
                    mapx[ tx ][ ty ] = ' ';
            }
            item[3] --; score += item_score[3];
        }
    }
}
void data_update()
{
    run++; cnt++;
    int calc= -pow2(item[4])/4 + 4*item[4] ;
    vision2 = {max(vision2.x,calc), max(vision2.y,calc)};
    vision = {vision2.x+vision_init.x,vision2.y+vision_init.y};
    fps_count();
}
void fps_count()
{
    if(clock()-lasts>=1000)
    {
        fps=run/ ( (clock()-lasts)*1.0/1000);
        run=0;
        lasts=clock();
    }
}
void enter_game(bool custom)
{
    game_over = false; key = 0;
    path.clear(); wall.clear(); mob.clear(); keys.clear();
    system("cls");
    startTime=clock();
    mmt(mapx,' ');  mmt(map2,' '); mmt(item,0); mmt(vis,false);
    if(!custom)
    {
        p= { 1, 1 }; vision_init={ 15, 15 }; vision2 = {-999,-999};
        data_update();
        int ttx = vision.x>>1, tty= (vision.y>>1) ;
        canvas({ttx,tty},0, "世界生成中...");
        for(rint i=1; i<=item_len ; ++i) item[i] = mode_item_init[choose][i];

        maph = mode_init[choose][2]; mapw = mode_init[choose][1];
        maph = maph >> 1 << 1 | 1; mapw = mapw >> 1 << 1 | 1;
        generate_maze();  

        canvas({ttx,tty+8},0, "33%");

        for(rint i=1; i<=item_len ; ++i) 
        {
            if(i==1 && !mode[2])generate_item(i,mode_item[choose][i]);
            if(i!=1 && mode[1])generate_item(i,mode_item[choose][i]);
        }

        canvas({ttx,tty+8},0, "45%");

        bfs_get_way(p);
        if(mode[2]) generate_block(mode_init[choose][3]);

        canvas({ttx,tty+8},0, "60%");

        if(mode[3]) generate_key(mode_init[choose][4]);

        canvas({ttx,tty+8},0, "85%");

        if(mode[5]) generate_mob(mode_init[choose][5]);

        system("cls");
        canvas({ttx,tty},0, "done!");
    }
    else
    {
        load_map();
        vision2 = {-999,-999};
        bfs_get_way(p);
//debug_out("1");
//      dfs_get_way(p);
    }
    data_update();
    for(rint i=0; i<mob.size(); ++i)
        mob[i].last_time_dizzy = clock();

    cnt = 0; run = 0; score = 0; mob_speed = 12; shown_dir = 0; cam_dp={ 4, 20 };
    player_speed = 8;
//  save_map();
//debug_out("1");
//debug_out("Polynswin")
    while(!game_over)
    {
        update_map = false;
//      char k =getch();
//      if(k == 'a') enable ^= 1;
        if(clock()-lasts2<1000/ ( 60 + 0 ))continue;
        lasts2=clock();
        data_update();
        button_check();
//debug_out("2");
        if(game_over)break;
        if( cnt%player_speed==0) player_move();
        if( cnt%mob_speed == 0) mob_move();
        player_check();

        if(update_map) game_update();
    }
    enter_menu();
}
void print_menu()
{
    canvas( {1,1}, 0, "欢迎来到 多重迷宫 V1.5 ");
    canvas( {2,1}, 0, "   made by Polynswin ");
    canvas( {5,2}, 0, "按 Z 进入游戏 ");
    canvas( {7,2}, 0, "按 C 修改迷宫模式");
    canvas( {9,2}, 0, "按 Q 查看规则");
}
void enter_custom_choose()
{
    system("cls");
    cam_dp = {3,20};
    ifstream in("level_list.info");
    vector<string> name = {""};
    string x;
    while(in>>x)name.push_back(x);
    int len = name.size() - 1,cur = 1;
    while(1)
    {
        int curx = 0;
        for(rint i=1; i<=len; ++i)
            canvas({curx = curx + 2, 1}, 0, name[i]);

        for(rint i=1;i<=len;++i)
            if(cur == i)canvas({i*2,-1},0," ");
            else canvas({i*2,-1},0,">");
//      if(1<=cur && cur<=6)

        char k =getch();
        if(press( k, 'w'))cur = (cur-1+len-1)%len+1;
        if(press( k, 's'))cur = cur%len+1;
        if(press( k, 'o'))
        {
            if(cur==1) enter_game(false);
            if(cur==2) enter_custom_choose();
            if(cur==3) enter_editor();
            if(cur==4) enter_setting();
            if(cur==5) enter_rule();
            if(cur==6) enter_updates();
        }
    }

}
void enter_menu()
{
    system("cls");
    cam_dp = {3,20};
    int len = 6,cur = 1;
    while(1)
    {
        int curx=3;
        cam_dp = {3,20};
        canvas({curx,0},0,"多重迷宫 V1.8!!!"); curx += 1;
        canvas({curx,0},0,"made by Polynswin"); curx += 2;
        canvas({curx,0},0,"开始游戏"); curx += 2;
        canvas({curx,0},0,"自定义关卡"); curx += 2;
        canvas({curx,0},0,"关卡编辑器"); curx += 2;
        canvas({curx,0},0,"修改迷宫模式"); curx += 2;
        canvas({curx,0},0,"查看游戏介绍"); curx += 2;
        canvas({curx,0},0,"更新日志 "); curx += 3;
        canvas({curx,0},0,"按 W / S 键上下移动"); curx += 1;
        canvas({curx,0},0,"按 O 键确认"); curx += 1;
        for(rint i=1;i<=len;++i)
            canvas({i*2+4,-1},0," ");
//      if(1<=cur && cur<=6)
            canvas({cur*2+4,-1},0,">");
        char k =getch();
        if(press( k, 'w'))cur = (cur-1+len-1)%len+1;
        if(press( k, 's'))cur = cur%len+1;
        if(press( k, 'o'))
        {
            if(cur==1) enter_game(false);
            if(cur==2) enter_custom_choose();
            if(cur==3) enter_editor();
            if(cur==4) enter_setting();
            if(cur==5) enter_rule();
            if(cur==6) enter_updates();
        }
    }
}
void enter_setting()
{
    int cur = 1, len = 4;
    while(1) 
    {
        cam_dp = {3,20};
        system("cls");
        if(1<=cur && cur<=3)
            canvas({cur*2-1,0},0,">");
        string text[10]={"",
            "难度选择", "模式选择", "颜色设置(尚未开放)", "UI设置(尚未开放)",
            "按 W / S 键改位置", "按 O 键确认",  "按 Q 键退出并保存设置"

        };
        for(rint i=1;i<=len+3;i++)
        {
            int col=0;
            canvas({i*2-1,1},col,text[i]);
        }

        char k =getch();
        if(press( k, 'w'))cur = (cur-1+len-1)%len+1;
        if(press( k, 's'))cur = cur%len+1;
        if(press( k, 'o'))
        {
            if(cur == 1) enter_difficulty_setting();
            if(cur == 2)enter_mode_setting();
            if(cur == 3);
        }
        if(press( k, 'q'))enter_menu();
    }
}
void enter_mode_setting()
{
    system("cls");
    cam_dp = {3,20};
    int cur = 1, len = mode_name.size() - 1;
    while(1) 
    {
        system("cls");
        if(1<=cur && cur<=len)
            canvas({cur*2-1,0},0,">");
        for(rint i=1;i<=len;i++)
        {
            int col=0;
            if(mode[i])col=2;
            canvas({i*2-1,1},col,mode_name[i]);
        }
        canvas({ (len+1<<1) - 1, 1}, 0, "按 W / S 键改位置");
        canvas({ len+1 << 1, 1}, 0, "按 O 键确认");
        canvas({ len+1 << 1 | 1, 1}, 0, "按 Q 键退出并保存设置");
        char k =getch();
        if(press(k, 'w'))cur = (cur-1+len-1)%len+1;
        if(press(k, 's'))cur = cur%len+1;
        if(press(k, 'o'))
        {
            mode[cur] ^= 1;
            if(mode[2])mode[1]=1;
        }
        if(press(k, 'q'))enter_setting();
    }

}
string str(int x)
{
    if(!x) return "0";
    string res="",res2=".";
//  int tot = -99;
//  if(int(x) != x)
//  {
//      double cx = x;
//      while(cx && tot<2)
//      {
//          cx = cx - int(cx);
//          cx = cx * 10;
//          res2 += int(cx) + '0';  
//          tot++;
//      }
////        Setpos(0,-10);test(res2);
//  }
    int tx=x;
    while(tx)
    {
        res+=tx%10+'0';
        tx=tx/10;
    }
    for(int i=0;i< (res.size()>>1) ;i++)
    {
        char t=res[i];
        res[i]=res[res.size()-i-1];
        res[res.size()-i-1]=t;
    }
    if(res2==".")return res;
    else return res+res2;
}
void enter_updates()
{
    int curx=0,len=2;
    cam_dp = {3,10};
    system("cls");
//  canvas({curx,0},0," "); curx += ;
    canvas({curx,0},0,"V1.5更新"); curx += 2;
    canvas({curx,0},0,"更新 钥匙收集 模式"); curx += 2;
    canvas({curx,0},0,"V1.6更新"); curx += 2;
    canvas({curx,0},0,"修复了一堆显示bug"); curx += 1;
    canvas({curx,0},0,"优化了游戏算法,反正作者的机房电脑是能在地狱难度\\模式拉满\\视野拉满下也能跑满62fps"); curx += 1;
    canvas({curx,0},0,"引导之星增添新功能,在钥匙收集模式中,还能显示钥匙大致方位"); curx += 1;
    canvas({curx,0},0,"新增 怪物追击 模式"); curx += 1;
    canvas({curx,0},0,"更新 UI"); curx += 2;;
    canvas({curx,0},0,"V1.7&1.8更新"); curx += 2;
    canvas({curx,0},0,"新增 自定义关卡&关卡编辑器 模式"); curx += 1;
    canvas({curx,0},0,"按 Q 键退出");
    while(1)
    {
        char k =getch();
        if(press(k, 'q')) break;
    }
    system("cls");
}
void enter_rule_editor()
{
    system("cls");
    while(1)
    {
        int curx = 0;
        cam_dp = {3,20};
        canvas({curx,0},0,"编辑器上方有工具栏,按下相应数字键切换选中物品,按O键即可在预瞄点处摆放"); curx += 2;
        canvas({curx,0},0,"箭头上方为你的预瞄点,按WASD键进行上下左右移动"); curx += 2;
        canvas({curx,0},0,"如果要对地图进行设置,按下ESC进入菜单界面"); curx += 2;
        canvas({curx,0},0,"大部分界面都可以用ESC退出,同时大部分选项都可以按下O键(注意)确认"); curx += 2;
        canvas({curx,0},0,"编辑好地图后,别忘了在菜单界面保存地图,会导出至与游戏本体同级地址为maze.pm"); curx += 1;
        canvas({curx,0},0,"如果想加载地图,可在菜单界面选择加载地图确认,会读入文件maze.pm"); curx += 3;
        canvas({curx,0},0,"按 Q 键退出");
        char k =getch();
        if(press( k, 'q'))return;
    }
}
void enter_rule()
{
    int curx=0,cur=1,len=3;

    while(1)
    {
        curx=0;
        cam_dp = {3,20};
        system("cls");
        canvas({curx,0},0,"游戏目标为移动至迷宫位于右下角的终点(符号*)"); curx += 2;
        canvas({curx,0},0,"按方向键进行上下左右移动"); curx += 2;
        canvas({curx,0},0,"你拥有道具,需要按下相应的键位使用,使用即可得分"); curx += 2;
        canvas({curx,0},0,"当你遇到死局时,可双击 R 键紫砂"); curx += 3;
        canvas({curx,0},0,"查看 道具介绍"); curx += 1;
        canvas({curx,0},0,"查看 模式介绍"); curx += 1;
        canvas({curx,0},0,"查看 编辑器介绍"); curx += 2;
        canvas({curx,0},0,"按 W / S 键上下移动"); curx += 1;
        canvas({curx,0},0,"按 O 键确认"); curx += 1;
        canvas({curx,0},0,"按 Q 键退出");
        for(rint i=1;i<=len;++i)
            canvas({i+8,-1},0," ");
        canvas({cur+8,-1},0,">");
        char k =getch();
        if(press( k, 'w'))cur = (cur-1+len-1)%len+1;
        if(press( k, 's'))cur = cur%len+1;
        if(press( k, 'q'))enter_menu();
        if(press( k, 'o'))
        {
            if(cur==1)enter_rule_item();
            if(cur==2)enter_rule_mode();
            if(cur==3)enter_rule_editor();
        }
    }
}
void enter_rule_mode()
{
    system("cls");
    cam_dp = {3,15};
    int curx=0;
    canvas({curx,0},0,"特殊道具: 场上会多出特殊道具"); curx += 2;
    canvas({curx,0},0,"特殊道具2: 同上"); curx += 2;
    canvas({curx,0},0,"迷宫塌方:迷宫坍塌,场上会随机出现方块"); curx += 1;
    canvas({curx,0},0,"         (强制打开特殊道具)"); curx += 2;
    canvas({curx,0},0,"收集钥匙:要收集一定钥匙后才能通往终点"); curx += 2;
    canvas({curx,0},0,"爆炸伤害:炸弹会炸死范围内单位,包括你自己"); curx += 1;
    canvas({curx,0},0,"         (强制打开特殊道具)"); curx += 2;
    canvas({curx,0},0,"怪物追击:场上会存在一定的怪物,它们会随机游走,但当看到你时,它们会向你追击"); curx += 1;
    canvas({curx,0},0,"          但是你可以甩开它们,同时要利用地形卡好视野,同时地图上会出现安全点"); curx += 1;
    canvas({curx,0},0,"          相应的,地图的路径将不再单一,你拥有多种路径通往终点"); curx += 2;
    canvas({curx,0},0,"灯光不足:玩家出生时会携带灯源,随着时间流逝灯光会减弱,视野也会相应变小,"); curx += 1;
    canvas({curx,0},0,"          需要去地图上搜寻燃料补充灯光,视野也会相应变小,需要去地图上搜寻"); curx += 1;
    canvas({curx,0},0,"          燃料补充灯光"); curx += 2;
    canvas({curx,0},0,"双人对战:开启双人模式,玩家出生在地图对角线,需不断搜寻道具击败对方"); curx += 1;
    canvas({curx,0},0,"         (强制打开特殊道具 & 2)"); curx += 2;
    canvas({curx,0},0,"按 Q 键退出");

    while(1)
    {
        char k =getch();
        if(press( k, 'q'))break;
    }
}
void enter_rule_item()
{
    system("cls");
    cam_dp = {3,15};
    int curx=0;
    canvas({curx,0},0,"道具1: 引导之星(guide)  U 键"); curx += 1;
    canvas({curx,0},0,"       使用后可以显示通往终点的道路,但只能显示距离你最近的5格"); curx += 1;
    canvas({curx,0},0,"       (迷宫塌方中不可用)"); curx += 2;
    canvas({curx,0},0,"接下来的为特殊道具,只有打开特殊模式才能使用"); curx += 2;
    canvas({curx,0},0,"道具2:闪现(flash) I 键"); curx += 1;
    canvas({curx,0},0,"       使用后可以闪现至预瞄点"); curx += 2;
    canvas({curx,0},0,"道具3:炸弹(bomb) O 键"); curx += 1;
    canvas({curx,0},0,"       使用后可以炸掉预瞄点3*3范围内的墙壁(不可炸掉边界,别想着偷鸡)"); curx += 2;
    canvas({curx,0},0,"道具4:探远星(vision) \\"); curx += 1;
    canvas({curx,0},0,"       收集之后可以增加视野,但存在上限,非线性增长"); curx += 2;
    canvas({curx,0},0,"按 Q 键退出");

    while(1)
    {
        char k =getch();
        if(press( k, 'q'))break;
    }
}
void enter_difficulty_setting()
{
    system("cls");
    cam_dp = {3,20};
    int cur = 1, len = 5;
    while(1) 
    {
        system("cls");
        if(1<=cur && cur<=5)
            canvas({cur*2-1,0},0,">");
        vector<string> text={"",
            "迷宫:简单难度",  "迷宫:正常难度",  "迷宫:困难难度",
            "迷宫:地狱难度",  "迷宫:自定义模式(尚未开放)",       "按 W / S 键改位置",
            "按 O 键确认",  "按 Q 键退出并保存设置"

        };
        for(rint i=1;i<=len+3;i++)
        {
            int col=0;
            if(choose==i)col=2;
            canvas({i*2-1,1},col,text[i]);
        }

        char k =getch();
        if(press( k, 'w'))cur = (cur-1+len-1)%len+1;
        if(press( k, 's'))cur = cur%len+1;
        if(press( k, 'o'))
        {
            if(1<=cur && cur<=5)
            {
                choose = cur;
                if(cur==5)
                {
                    system("cls");
                    canvas({1,1},0,"暂未开放 ");
                    choose = 4;
//                  canvas({-1,1},0,"尽量不要进行非合法/常规输入,否则会出bug ");
//                  canvas({1,1},0,"输入迷宫宽度: "); cin>>mode[5][1];
//                  canvas({3,1},0,"输入迷宫长度: "); cin>>mode[5][2];
//                  canvas({5,1},0,"输入迷宫引导之星数量: "); cin>>mode_item[5][1];
//                  canvas({7,1},0,"输入完毕 ");
                    Sleep(2000);
                }
            }
        }
        if(press( k, 'q'))enter_setting();
    }
}
void lose()
{
    game_over = true;
    ending_of_game();
    system("cls");
    cam_dp= {3,20};
    string s=str(score);
    int sx= vision.x>>1, sy= vision.y>>1;
    Setpos( sx, sy ); Color(0); SlowDisplay(100,"You lost!"); 
    Setpos( sx +1 , sy ); Color(0); SlowDisplay(100,"used time:"+str( (clock()-startTime)/1000 ) + " score:"+str(score)); 
    Setpos( sx +2 , sy ); system("pause");
}
void win()
{
    game_over = true;
    ending_of_game();
    system("cls");
    string s=str(score);
    cam_dp= {3,20};
    int sx= vision.x>>1, sy= vision.y>>1;
    Setpos( sx, sy ); Color(0); SlowDisplay(100,"You won!"); 
    Setpos( sx +1 , sy ); Color(0); SlowDisplay(100,"used time:"+str( (clock()-startTime)/1000 ) + " score:"+str(score)); 
    Setpos( sx +2 , sy ); system("pause");
}
void ending_of_game()
{
    paint();
    game_update();
    for(int i=1;i<=3;i++)
    {
        Setpos(p.x-cam.x+1,p.y-cam.y+1); Color(4); cout<<"●";
        Sleep(500);
        Setpos(p.x-cam.x+1,p.y-cam.y+1); Color(3); cout<<"●";
        Sleep(500);
    }
    for(int i=max(vision.y,vision.x);i>=-vision.y-vision.x+2; --i)
    {
        for(int j=0;vision.x-j>=1&&i+j<=vision.y; ++j)
            if(i+j>=1){Setpos(vision.x-j,i+j); Color(0); cout<<"  ";}
        Sleep(50);
    }

}


void HideCursor(){CONSOLE_CURSOR_INFO cursor_info = {1,0};SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);/*Po*/}
void showCursor()
{
    HANDLE h_GAME = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_CURSOR_INFO cursor_info;
    GetConsoleCursorInfo(h_GAME,&cursor_info);
    cursor_info.bVisible = true;
    SetConsoleCursorInfo(h_GAME,&cursor_info);
} 
void Setpos(int x,int y){RealSetpos(x+cam_dp.x,y+cam_dp.y);}
void RealSetpos(int x,int y){COORD pos;pos.X=y*2,pos.Y=x;SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos);}
void SlowDisplay(int x,string p)
{
    for(int i=0;i<p.size();i++)
    {
        cout<<p[i];
        if(kbhit())x = 0;
        Sleep(x);
    }
}
int sprand(int l,int r){return rand()%(r-l+1)+l;}
void Color(int a)
{
    if(a==0) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE);
    if(a==1) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_GREEN|FOREGROUND_BLUE);
    if(a==2) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_GREEN);
    if(a==3) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED|FOREGROUND_BLUE);
    if(a==4) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED);
    if(a==5) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED|FOREGROUND_GREEN);
    if(a==7) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_GREEN);
    if(a==8) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED|FOREGROUND_GREEN|BACKGROUND_RED);
}

inline void read(int &x)
{
    int f=1;x=0;char ch=getchar();
    while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
    x=x*f;
}
inline void ffout(int x)
{
    if(x<0){x=-x; putchar('-'); }
    short sta[63],top=0;
    do{ sta[top++]=x%10; x/=10; }while(x);
    while(top) putchar(sta[--top]+'0');
}
inline void ffout(int x,char b)
{
    if(x<0){x=-x; putchar('-'); }
    short sta[63],top=0;
    do{ sta[top++]=x%10; x/=10; }while(x);
    while(top) putchar(sta[--top]+'0');
    putchar(b);
}