创意棋类游戏

· · 个人记录

//转自:https://www.luogu.com.cn/paste/kjqt4pja
//作者:https://www.luogu.com.cn/user/85994
/*
All right!
*/
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#include<windows.h>
#include<conio.h>
using namespace std;

#define maxn 10
#define GREY 8*17
#define WHITE 255
#define BLACK 0
#define YELLOW 14*17

#define accept_ 1.1

#define space 1
#define black 2
#define white 3
#define side 0

#define MaxCal 300000000
#define relaxTime 12

#define out_of_board -1290687
#define notSet -128370

#define RIGHT 10
#define WRONG -10

#define RESET_TIMES 5 

const int fx_1[4]={0,0,1,-1};
const int fx_2[4]={1,-1,0,0};

int D=0;
int calNum=0;//the number of calculation in order to relax the CP
int warn=0,turn=0;

void color(int a)
{
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),a);
}

string num_str(int n)
{
    int m=n;
    char s[20];
    char ss[20];
    int i=0,j=0;
    if (n<0)// 处理负数
        m=-m,j=1,ss[0]='-';
    while(m>0)
        s[i++]=m%10+'0',m/=10;
    s[i]='\0';
    --i;
    while (i >= 0)
    {
     ss[j++]=s[i--];
    }    
    ss[j]='\0';    
    return ss;
}

void HideCursor(void)
{
    HANDLE handle=GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_CURSOR_INFO CursorInfo;
    GetConsoleCursorInfo(handle,&CursorInfo);//获取控制台光标信息
    CursorInfo.bVisible=false; //隐藏控制台光标
    SetConsoleCursorInfo(handle,&CursorInfo);//设置控制台光标状态
}

void SetXY(int x, int y) {
    COORD pos={x,y};
    HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);// 获取标准输出设备句柄
    SetConsoleCursorPosition(hOut,pos);//两个参数分别是指定哪个窗体,具体位置
}

inline double drand(void)
{
    double d=1.0,ans=0.0;
    for(int i=0;i<15;i++)
    {
        d*=0.5;
        if(rand()%2) ans+=d;
    }
    return ans;
}

inline bool gl(double a)
{
    if(a>=drand()) return true;
    else return false;
}

inline char* str_ch(string str)
{
    char* strc=new char[strlen(str.c_str())+1];
    strcpy(strc,str.c_str());
    return strc;
}

void Game(void);

class MAP
{
    public:
        int d[maxn][maxn];
        bool is_white;
        int White,Black;
        void Set(void)
        {
            is_white=true,White=0,Black=0;
            for(int i=0;i<maxn;i++)
                for(int j=0;j<maxn;j++)
                    d[i][j]=space;
            for(int i=0;i<maxn;i++)
                d[i][0]=side,d[i][maxn-1]=side,d[maxn-1][i]=side,d[0][i]=side;
        }//set a board with nothing
        void draw_(void)
        {
            for(int i=0;i<maxn;i++)
            {
                for(int j=0;j<maxn;j++)
                {
                    color(15);
                    if(d[i][j]==space)
                    {
                        SetXY(i+1,j+1),color(GREY),cout<<' ';
                        continue;
                    }
                    if(d[i][j]==white) 
                    {
                        SetXY(i+1,j+1),color(WHITE),cout<<' ';
                        continue;
                    }
                    if(d[i][j]==black)
                    {
                        SetXY(i+1,j+1),color(BLACK),cout<<' ';
                        continue;
                    }
                    if(d[i][j]==side)
                    {
                        SetXY(i+1,j+1),color(YELLOW),cout<<' ';
                        continue;
                    }
                }
                color(15),cout<<endl;
            }
        }//just draw a MAP
        void count_(void)
        {
            White=0,Black=0;
            for(int i=1;i<maxn-1;i++)
                for(int j=1;j<maxn-1;j++)
                    if(d[i][j]==white) ++White;
                    else if(d[i][j]==black) ++Black;
        }//count the MAP,must do this after you change it
        void turn(int a,int b)
        {
            if(d[a][b]==white) d[a][b]=black;
            else d[a][b]=white;
        }//turn a piece
        int Change(int a,int b)
        {
            if(a>=maxn-1||a<1||b>=maxn-1||b<1) return WRONG;
            if(d[a][b]!=space) return WRONG;
            if(is_white) d[a][b]=white;
            else d[a][b]=black;
            is_white=!is_white;
            bool t[4]={1,1,1,1};
            for(int i=1;i<maxn;i++)
            {
                for(int j=0;j<4;j++)
                    if(t[j])
                        if(d[a+fx_1[j]*i][b+fx_2[j]*i]!=space&&d[a+fx_1[j]*i][b+fx_2[j]*i]!=side) turn(a+fx_1[j]*i,b+fx_2[j]*i);
                        else t[j]=false;
            }
            return RIGHT;
        }//lay at (a,b)
        void from(MAP map_)
        {
            for(int i=0;i<maxn;i++)
                for(int j=0;j<maxn;j++)
                    d[i][j]=map_.d[i][j];
        }//copy a MAP
        int Space_() {return (maxn-2)*(maxn-2)-White-Black;}//the space number
};

string name;

void rule(void)
{
    system("cls");
    color(10);
    printf("In the rolling chess,if you put a piece at everywhere in a ");
    puts("chess board which is 8*8,it will turn all the pieces on the same line with it and next to it into a different color.");
    puts("White first,and then is black's turn.Finally,who has more pieces of his own color will win.");
    puts("You can play with your friend at a CP ,play with the CP or even just watching CPs' play.");
    puts("'W','A','S','D' to move a piece and ' ' to lay it");
    puts("When you are using Adviser,'q' to get the advice and 'l' to know your now point");
    puts("To avoid copying and peace,black give white a piece."); 
    color(15),puts("MADE BY efX!");
    printf("Now the AI is right,never do foolish things\n");
    system("pause");
    Game();
}

#define MIX 2 
#define RATE 1
#define POINT 0

class MCTS
{
    private:
        double judge(MAP mp)
        {
            if(mp.Space_()<=7)
                if(mp.White>mp.Black)
                    return 1.0;
                else return -1.0;
            return (double)(mp.White>mp.Black)*0.125+(mp.White>mp.Black?1.0:-1.0);
        }
    public:
        double now_point;
        int work_depth;
        int workNum;//how many borads
        int advX,advY;//advise to go
        int type;
        bool is_white;
        /*double randSearch(MAP mp,int restDepth)
        {
            mp.count_();
            if(restDepth==0||mp.Space_()<=1) return judge(mp);
            int place[(maxn-2)*(maxn-2)][2],q=0,r=0;
            for(int i=1;i<maxn-1;i++)
                for(int j=1;j<maxn-1;j++)
                    if(mp.d[i][j]==space)
                        place[q][0]=i,place[q][1]=j,++q;
            r=rand()%q;
            mp.Change(place[r][0],place[r][1]);
            return randSearch(mp,restDepth-1);
        }
        void MIX_WORK(MAP mp)
        {
            mp.count_();
            if(mp.Space_()%2) mp.is_white=true;
            else mp.is_white=false;
            int point[(maxn-2)*(maxn-2)][3];
            double count_point[(maxn-2)*(maxn-2)];
            memset(count_point,0,sizeof(count_point));
            int q=0,r=0;
            //0.X;1.Y;2.count times
            double realPoint[(maxn-2)*(maxn-2)],nowBest;
            for(int i=0;i<(maxn-2)*(maxn-2);i++)
                realPoint[i]=0.0;
            for(int i=0;i<(maxn-2)*(maxn-2);i++)
                for(int j=0;j<3;j++)
                    point[i][j]=0;//first set
            for(int i=1;i<maxn-1;i++)
                for(int j=1;j<maxn-1;j++)
                    if(mp.d[i][j]==space)
                        point[q][0]=i,point[q][1]=j,++q;
            for(int i=0;i<workNum;i++)
            {
                r=rand()%q;
                mp.Change(point[r][0],point[r][1]);
                count_point[r]+=randSearch(mp,work_depth),++point[r][2];
                mp.Change(point[r][0],point[r][1]);
                mp.d[point[r][0]][point[r][1]]=space;
            }//search the point
            for(int i=0;i<q;++i)
                realPoint[i]=count_point[i]/(double)(point[i][2]);
                //get the mean
            nowBest=realPoint[0],r=0;
            if(mp.is_white)
                for(int i=1;i<q;++i)
                    if(realPoint[i]>nowBest)
                        r=i,nowBest=realPoint[i];
            else for(int i=1;i<q;++i)
                    if(realPoint[i]<nowBest)
                        r=i,nowBest=realPoint[i];
            advX=point[r][0],advY=point[r][1];
            now_point=realPoint[r];
            return;
        }//maybe finish*/
        int RandSearch(MAP mp,int restDepth)
        {
            mp.count_();
            if(restDepth==0||mp.Space_()<=1)
            {
                if(type==POINT)
                    return (mp.White-mp.Black);
                if(type==RATE)
                    if(mp.White>mp.Black)
                        return 1;
                    else return 0;
                if(type==MIX)
                {
                    if(is_white)
                        if(mp.White>mp.Black)
                            return (((mp.White-mp.Black)+1)>>1);
                        else return ((mp.White-mp.Black)>>1)-1;
                    else
                        if(mp.White>mp.Black)
                            return ((mp.White-mp.Black)>>1)+1;
                        else return (((mp.White-mp.Black)-1)>>1);
                }
            }
            int place[(maxn-2)*(maxn-2)][2],q=0,r=0;
            for(int i=1;i<maxn-1;i++)
                for(int j=1;j<maxn-1;j++)
                    if(mp.d[i][j]==space)
                        place[q][0]=i,place[q][1]=j,++q;
            r=rand()%q;
            mp.Change(place[r][0],place[r][1]);
            return RandSearch(mp,restDepth-1);
        }
        void Work(MAP mp)
        {
            mp.count_();
            if(mp.Space_()%2) mp.is_white=true,is_white=true;
            else mp.is_white=false,is_white=false;
            int point[(maxn-2)*(maxn-2)][4];
            int q=0,r=0;
            //0.X;1.Y;2.point;3.count times
            double realPoint[(maxn-2)*(maxn-2)],nowBest;
            for(int i=0;i<(maxn-2)*(maxn-2);i++)
                realPoint[i]=0.0;
            for(int i=0;i<(maxn-2)*(maxn-2);i++)
                for(int j=0;j<4;j++)
                    point[i][j]=0;//first set
            for(int i=1;i<maxn-1;i++)
                for(int j=1;j<maxn-1;j++)
                    if(mp.d[i][j]==space)
                        point[q][0]=i,point[q][1]=j,++q;
            for(int i=0;i<workNum;i++)
            {
                r=rand()%q;
                mp.Change(point[r][0],point[r][1]);
                point[r][2]+=RandSearch(mp,work_depth),++point[r][3];
                mp.Change(point[r][0],point[r][1]);
                mp.d[point[r][0]][point[r][1]]=space;
            }//search the point
            for(int i=0;i<q;++i)
                realPoint[i]=(double)(point[i][2])/(double)(point[i][3]);
                //get the mean
            nowBest=realPoint[0],r=0;
            if(mp.is_white)
                for(int i=1;i<q;++i)
                    if(realPoint[i]>nowBest)
                        r=i,nowBest=realPoint[i];
            else for(int i=1;i<q;++i)
                    if(realPoint[i]<nowBest)
                        r=i,nowBest=realPoint[i];
            advX=point[r][0],advY=point[r][1];
            now_point=realPoint[r];
            return;
        }
};

int type=0,st=0;

void Adviser(MAP &mp,MCTS mct,ofstream &fout)
{
    system("cls");
    printf("1.with POINT\n2.with RATE\n3.with MIX");
    char ch=getch();
    if(ch=='1') mct.type=POINT;
    else if(ch=='2') mct.type=RATE;
         else mct.type=MIX;
    system("cls");
    for(int i=st;i<(maxn-2)*(maxn-2)-1;i++)
    {
        char ch='\0';
        int X=(maxn-2)/2,Y=(maxn-2)/2;
        SetXY((maxn)/2-2,0),printf("turn %d",i+1);

        double P[(maxn-2)*(maxn-2)],best;
        int allow[(maxn-2)*(maxn-2)][2]={0},ac=0;
        int p[(maxn-2)*(maxn-2)][2];
        int q=0;
        for(int t=1;t<maxn-1;++t)
            for(int j=1;j<maxn-1;++j)
                if(mp.d[t][j]==space)
                    p[q][0]=t,p[q][1]=j,++q;//every tile's point 
        while(ch!=' ')
        {
            memset(allow,0,sizeof(allow));
            for(int j=0;j<(maxn-2)*(maxn-2);j++) P[j]=0.0;

            mp.draw_();
            color(15),SetXY(X+1,Y+1);
            if(mp.d[X][Y]==space)
                if(!mp.is_white) color(BLACK+10),putchar('X');
                else color(BLACK-7),putchar('X');
            else color(14),putchar('O');
            ch=getch();
            if(ch==' '&&mp.d[X][Y]!=space) ch='\0';
            if(ch=='w'||ch=='W') {Y=((Y-1>0)?Y-1:maxn-2);continue;}
            if(ch=='s'||ch=='S') {Y=((Y+1<maxn-1)?Y+1:1);continue;}
            if(ch=='a'||ch=='A') {X=((X-1>0)?X-1:maxn-2);continue;}
            if(ch=='d'||ch=='D') {X=((X+1<maxn-1)?X+1:1);continue;}
            if(ch=='q'||ch=='Q')
            {
                MAP m;
                m.from(mp);
                m.count_();
                int work_depth=mct.work_depth;
                //mct.work_depth/=m.Space_();

                ac=0; 

                for(int t=0;t<q;t++)
                {
                    m.Change(p[t][0],p[t][1]);
                    if(i%2) m.d[p[t][0]][p[t][1]]=black;
                    else m.d[p[t][0]][p[t][1]]=white;
                    mct.Work(m);
                    //color(15);
                    //SetXY(0,maxn+6);
                    m.Change(p[t][0],p[t][1]);
                    m.d[p[t][0]][p[t][1]]=space;
                    //P[t]*=0.999;//slowly forget
                    P[t]+=mct.now_point;
                }
                best=P[0],X=p[0][0],Y=p[0][1];
                for(int t=1;t<q;t++)
                {
                    if(i%2&&P[t]<best)
                    {
                        X=p[t][0],Y=p[t][1],best=P[t];
                        continue;
                    }
                    if(i%2==0&&P[t]>best)
                    {
                        X=p[t][0],Y=p[t][1],best=P[t];
                        continue;
                    }
                    if(i%2&&P[t]*accept_<best)
                    {
                        allow[ac][0]=p[t][0],allow[ac][1]=p[t][1],ac++;
                        continue;
                    }
                    if(i%2==0&&P[t]>best*accept_)
                    {
                        allow[ac][0]=p[t][0],allow[ac][1]=p[t][1],ac++;
                        continue;
                    }
                }
                mct.work_depth=work_depth;
                mp.draw_();
                color(15);
                SetXY(X+1,Y+1),color(13*17),putchar(' ');
                for(int j=0;j<ac;j++)
                {
                    color(15),SetXY(allow[j][0]+1,allow[j][1]+1);
                    color(10*17),putchar(' ');
                }
                getch();
                //mct.Work(mp);
                //SetXY(mct.advX+1,mct.advY+1),color(12*17),putchar(' '),getch();
            }
            if((ch=='l'||ch=='L')&&mp.d[X][Y]==space)
            {
                if(i%2) mp.d[X][Y]=black;
                else mp.d[X][Y]=white;
                mp.Change(X,Y);
                mct.Work(mp);
                color(15);
                SetXY(0,maxn+6);
                printf("this move's point:                   ");
                SetXY(18,maxn+6),printf("%0.3f",mct.now_point);
                mp.Change(X,Y),mp.d[X][Y]=space;
            //  system("pause");
            }
        }
        mp.Change(X,Y);
        if(i%2) mp.d[X][Y]=black;
        else mp.d[X][Y]=white;
        color(15);
        mct.Work(mp);
        if(mct.type==POINT)
            SetXY(0,maxn+1),printf("now point:                   ");
        else SetXY(0,maxn+1),printf("now rate :                   ");
        SetXY(10,maxn+1),printf("%0.3f",mct.now_point);
        mp.count_();
        SetXY(2,maxn+7),printf("White:  ");
        SetXY(2,maxn+8),printf("Black:  ");
        SetXY(8,maxn+7),printf("%d",mp.White);
        SetXY(8,maxn+8),printf("%d",mp.Black);
        fout<<X<<' '<<Y<<endl;
        SetXY(maxn/2-3,maxn+3),printf("X,Y:%d,%d",X,Y);
    //  mp=next_(mp,dos);
    }
    /*if(mp.White-mp.Black>0) printf("The White win %d pieces!\n",mp.White-mp.Black);
    else if(mp.White-mp.Black<0) printf("The Black win %d pieces!\n",mp.Black-mp.White);
         else cout<<"Nobody win!\n";
    system("pause");*/ 
}

void Fight(MAP &mp,MCTS mct,ofstream &fout)
{
    bool point_print=0;
    printf("1.with POINT\n2.with RATE\n");
    char ch=getch();
    if(ch=='1') mct.type=POINT;
    else if(ch=='2') mct.type=RATE;
         else mct.type=MIX;
    system("cls");
    printf("1.White  2.Black(you are):");
    cin>>D;
    system("cls");
    printf("Would AI print the point out(Y or N)");
    ch=getch();
    if(ch=='y'||ch=='Y') point_print=1;
    system("cls"); 
    for(int i=st;i<(maxn-2)*(maxn-2)-1;i++)
    {
        char ch='\0';
        int X=(maxn-2)/2,Y=(maxn-2)/2;
        SetXY((maxn)/2-2,0),printf("turn %d",i+1),mp.draw_();
        if((D==1&&i%2==0)||(D!=1&&i%2))
        {
            SetXY((maxn)/2-2,0),printf("turn %d",i+1);
            while(ch!=' ')
            {
                mp.draw_();
                color(15),SetXY(X+1,Y+1);
                if(mp.d[X][Y]==space)
                    if(!mp.is_white) color(BLACK+10),putchar('X');
                    else color(BLACK-7),putchar('X');
                else color(14),putchar('O');
                ch=getch();
                if(ch==' '&&mp.d[X][Y]!=space) ch='\0';
                if(ch=='w'||ch=='W') Y=((Y-1>0)?Y-1:maxn-2);
                if(ch=='s'||ch=='S') Y=((Y+1<maxn-1)?Y+1:1);
                if(ch=='a'||ch=='A') X=((X-1>0)?X-1:maxn-2);
                if(ch=='d'||ch=='D') X=((X+1<maxn-1)?X+1:1);
            }
        }
        else
        {
            MAP m;
            m.from(mp);
            int work_depth=mct.work_depth;
            int workNum=mct.workNum;
            //mct.work_depth/=mp.Space_(),mct.work_depth+=rand()%60;
            double P[(maxn-2)*(maxn-2)],best,p_=0.0;
            int p[(maxn-2)*(maxn-2)][2];
            int q=0;
            for(int t=1;t<maxn-1;++t)
                for(int j=1;j<maxn-1;++j)
                    if(mp.d[t][j]==space)
                        p[q][0]=t,p[q][1]=j,++q;
            mct.work_depth>>=RESET_TIMES;
            for(int t=0;t<q;t++)
            {
                m.Change(p[t][0],p[t][1]);
                if(i%2) m.d[p[t][0]][p[t][1]]=black;
                else m.d[p[t][0]][p[t][1]]=white;
                mct.Work(m);
                //color(15);
                //SetXY(0,maxn+6);
                m.Change(p[t][0],p[t][1]);
                m.d[p[t][0]][p[t][1]]=space;
                P[t]+=mct.now_point;
                p_+=P[t];
            }
            p_/=(double)q;
            for(int T=0;T<RESET_TIMES;T++)
            {
                mct.work_depth<<=1;
                for(int t=0;t<q;t++)
                    if(P[t]>=p_)
                    {
                        m.Change(p[t][0],p[t][1]);
                        if(i%2) m.d[p[t][0]][p[t][1]]=black;
                        else m.d[p[t][0]][p[t][1]]=white;
                        mct.Work(m);
                        //color(15);
                        //SetXY(0,maxn+6);
                        m.Change(p[t][0],p[t][1]);
                        m.d[p[t][0]][p[t][1]]=space;
                        P[t]+=mct.now_point;
                    }
                p_=0.0;for(int t=0;t<q;t++) p_+=P[t];p_/=(double)q;
            }
            best=P[0],X=p[0][0],Y=p[0][1];
            for(int t=1;t<q;t++)
            {
                if(i%2&&P[t]<best)
                    X=p[t][0],Y=p[t][1],best=P[t];
                if(i%2==0&&P[t]>best)
                    X=p[t][0],Y=p[t][1],best=P[t];
            }
            mct.workNum=workNum;
            mct.work_depth=work_depth;
            mct.workNum+=256;
        }
        if(i%10==0) /*mct.work_depth++,*/mct.workNum+=256;
        if(i==40) ++mct.work_depth;
        mp.Change(X,Y);
        if(i%2) mp.d[X][Y]=black;
        else mp.d[X][Y]=white;
        mp.draw_();
        mp.count_();
        color(15);
        if(point_print)
        {
            if(mct.type==POINT)
                SetXY(0,maxn+1),printf("now point:                   ");
            else SetXY(0,maxn+1),printf("now rate :                   ");
            SetXY(10,maxn+1),printf("%0.3f",mct.now_point);
        }
        SetXY(2,maxn+7),printf("White:  "),SetXY(2,maxn+8),printf("Black:  ");
        SetXY(8,maxn+7),printf("%d",mp.White),SetXY(8,maxn+8),printf("%d",mp.Black);
        SetXY(maxn/2-3,maxn+3),printf("X,Y:%d,%d",X,Y);
        fout<<X<<' '<<Y<<endl;
    }
    /*if(mp.White-mp.Black>0) printf("The White win %d pieces!\n",mp.White-mp.Black);
    else if(mp.White-mp.Black<0) printf("The Black win %d pieces!\n",mp.Black-mp.White);
         else cout<<"Nobody win!\n";
    system("pause");*/ 
}

void Watch(MAP &mp,MCTS mct,ofstream &fout)
{
    system("cls");
    int KIND[2];
    char ch='0';
    printf("1.AI_White is POINT\n2.AI_White is RATE\n3.AI_White is MIX\n");
    ch=getch();
    if(ch=='1') KIND[0]=POINT;
    else if(ch=='2') KIND[0]=RATE;
         else KIND[0]=MIX;
    system("cls");
    printf("1.AI_Black is POINT\n2.AI_Black is RATE\n3.AI_Black is MIX\n");
    ch=getch();
    if(ch=='1') KIND[1]=POINT;
    else if(ch=='2') KIND[1]=RATE;
         else KIND[1]=MIX;
    system("cls");
    mp.count_();
    int moved[maxn-2][maxn-2];
    memset(moved,0,sizeof(moved));
    for(int i=st;i<(maxn-2)*(maxn-2)-1;i++)
    {
        mct.type=KIND[i%2];
        SetXY((maxn)/2-2,0),printf("turn %d",i+1);
        SetXY((maxn)/2-3,maxn+2),printf("space   ");
        SetXY((maxn)/2+3,maxn+2),printf("%d",mp.Space_());
        mp.draw_();
        char ch='\0';
        int X=(maxn-2)/2,Y=(maxn-2)/2;
        int work_depth=mct.work_depth;
        //if(i%2) mct.work_depth/=mp.Space_(),mct.work_depth+=rand()%60;
        double P[(maxn-2)*(maxn-2)],best;
        double countNum=0.0;
        int p[(maxn-2)*(maxn-2)][2];
        int q=0,r;
        for(int t=1;t<maxn-1;t++)
            for(int j=1;j<maxn-1;j++)
            {
                if(moved[t-1][j-1]==0)
                    p[q][0]=t,p[q][1]=j,q++;
            }
        for(int t=0;t<q;t++) P[t]=0.0;
        for(int t=0;t<q;t++)
            if(mp.d[p[t][0]][p[t][1]]!=space)
            {
                for(int j=t+1;j<q;j++)
                    p[j-1][0]=p[j][0],p[j-1][1]=p[j][1];
                --q;
            }
        MAP m;
        m.from(mp);
        if(type==2)
        {
            double p_=0.0;
            m.draw_();
            countNum+=1.0;
            mct.work_depth>>=RESET_TIMES;
            for(int t=0;t<q;t++)
            {
                m.Change(p[t][0],p[t][1]);
                if(i%2) m.d[p[t][0]][p[t][1]]=black;
                else m.d[p[t][0]][p[t][1]]=white;
                mct.Work(m);
                //color(15);
                //SetXY(0,maxn+6);
                m.Change(p[t][0],p[t][1]);
                m.d[p[t][0]][p[t][1]]=space;
                P[t]+=mct.now_point;
                p_+=P[t];
            }
            p_/=(double)q;
            for(int T=0;T<RESET_TIMES;T++)
            {
                mct.work_depth<<=1;
                for(int t=0;t<q;t++)
                    if(P[t]>=p_)
                    {
                        m.Change(p[t][0],p[t][1]);
                        if(i%2) m.d[p[t][0]][p[t][1]]=black;
                        else m.d[p[t][0]][p[t][1]]=white;
                        mct.Work(m);
                        //color(15);
                        //SetXY(0,maxn+6);
                        m.Change(p[t][0],p[t][1]);
                        m.d[p[t][0]][p[t][1]]=space;
                        P[t]+=mct.now_point;
                    }
                p_=0.0;for(int t=0;t<q;t++) p_+=P[t];p_/=(double)q;
            }
            //TRUE_WORK:;
            best=P[0],X=p[0][0],Y=p[0][1];
            for(int t=1;t<q;t++)
            {
                if(i%2&&P[t]<best)
                    r=t,X=p[t][0],Y=p[t][1],best=P[t]/countNum;
                if(i%2==0&&P[t]>best)
                    r=t,X=p[t][0],Y=p[t][1],best=P[t]/countNum;
            }
            mct.work_depth=work_depth;
            color(15);
            if(mct.type==POINT)
                SetXY(0,maxn+1),printf("now point:                   ");
            else if(mct.type==RATE)
                SetXY(0,maxn+1),printf("now rate :                   ");
                else 
                SetXY(0,maxn+1),printf("mix rate :                   ");
            SetXY(10,maxn+1),printf("%0.3f",best);
            Sleep(500+rand()%300);
        }
        else
            while(ch!=' ')
            {
                m.draw_();
                if(ch=='g')
                {
                    color(10*17);
                    for(int t=0;t<q;t++)
                        SetXY(p[t][0]+1,p[t][1]+1),putchar(' ');
                    ch=getch(),color(15);
                    continue;
                }
                countNum+=1.0;
                double p_=0.0;
                mct.work_depth>>=RESET_TIMES;
                for(int t=0;t<q;t++)
                {
                    m.Change(p[t][0],p[t][1]);
                    if(i%2) m.d[p[t][0]][p[t][1]]=black;
                    else m.d[p[t][0]][p[t][1]]=white;
                    mct.Work(m);
                    //color(15);
                    //SetXY(0,maxn+6);
                    m.Change(p[t][0],p[t][1]);
                    m.d[p[t][0]][p[t][1]]=space;
                    P[t]+=mct.now_point;
                    p_+=P[t];
                }
                p_/=(double)q;
                for(int T=0;T<RESET_TIMES;T++)
                {
                    mct.work_depth<<=1;
                    for(int t=0;t<q;t++)
                        if(P[t]>=p_)
                        {
                            m.Change(p[t][0],p[t][1]);
                            if(i%2) m.d[p[t][0]][p[t][1]]=black;
                            else m.d[p[t][0]][p[t][1]]=white;
                            mct.Work(m);
                            //color(15);
                            //SetXY(0,maxn+6);
                            m.Change(p[t][0],p[t][1]);
                            m.d[p[t][0]][p[t][1]]=space;
                            P[t]+=mct.now_point;
                        }
                    p_=0.0;for(int t=0;t<q;t++) p_+=P[t];p_/=(double)q;
                }
                //TRUE_WORK:;
                best=P[0],X=p[0][0],Y=p[0][1];
                for(int t=1;t<q;t++)
                {
                    if(i%2&&P[t]<best)
                        r=t,X=p[t][0],Y=p[t][1],best=P[t]/countNum;
                    if(i%2==0&&P[t]>best)
                        r=t,X=p[t][0],Y=p[t][1],best=P[t]/countNum;
                }
                mct.work_depth=work_depth;
                color(15);
                SetXY(0,maxn+1),printf("now point:                   ");
                SetXY(10,maxn+1),printf("%0.3f",best);
                ch=getch();
            }
        SetXY(maxn/2-3,maxn+3),printf("X,Y:%d,%d",X,Y);
        if(mp.d[X][Y]!=space)
            SetXY(maxn/2-4,maxn+4),printf("not space!");
        moved[X-1][Y-1]=1;
        mp.Change(X,Y);
        if(i%2) mp.d[X][Y]=black;
        else mp.d[X][Y]=white;
        mp.count_();
        SetXY(2,maxn+7),printf("White:  ");
        SetXY(2,maxn+8),printf("Black:  ");
        SetXY(8,maxn+7),printf("%d",mp.White);
        SetXY(8,maxn+8),printf("%d",mp.Black);
        fout<<X<<' '<<Y<<endl;
    }
}

void MCTS_(void)
{
    st=0,type=0;
    ofstream fout("last.ini");
    printf("1.Read\n2.Self-work(don't need to push ' ',only if you choose Watch)\n3.Common\n");
    cin>>type;
    MAP mp;
    mp.Set();
    if(type==1)
    {
        printf("Put in the name:");
        cin>>name;
        ifstream fin(str_ch(name));
        if(fin.is_open())
        {
            int x=0,y=0;
            mp.is_white=true;
            while(true)
            {
                fin>>x;
                if(x==EOF) break;
                fin>>y;
                if(y==EOF) break;
                mp.Change(x,y),++st;
            }
        }
        else cout<<"打开失败!\n";
    }
    MCTS mct;
    mct.type=POINT;
    system("cls");
    HideCursor();
    printf("Put in work depth(can reach 6!):"),cin>>D;
    if(D<2) D=2;
    mct.work_depth=D;
    printf("Put in work borads num(1 means 1 kilo):"),cin>>D;
    if(D<1) D=1;
    mct.workNum=D*1024;
    printf("1.Adviser  2.Fight  3.Watch\n"),cin>>D;
    if(D==1) Adviser(mp,mct,fout);
    if(D==2) Fight(mp,mct,fout);
    if(D==3) Watch(mp,mct,fout);
    mp.count_(),mp.draw_();
    SetXY(0,maxn+5);
    if(mp.White-mp.Black>0) printf("The White win %d pieces!\n",mp.White-mp.Black);
    else if(mp.White-mp.Black<0) printf("The Black win %d pieces!\n",mp.Black-mp.White);
         else cout<<"Nobody win!\n";
    system("pause"),SetXY(0,maxn+6),printf("                         \n");
    Game(); 
}

void AI_test(void)
{
    system("cls");
    MAP mp;
    MCTS mct;

    printf("Put in work depth(can reach 15!):"),cin>>D;
    if(D<2) D=2;
    mct.work_depth=D;//mct[1].work_depth=mct[0].work_depth;
    printf("Put in work borads num(1 means 1 kilo):"),cin>>D;
    if(D<1) D=1;
    mct.workNum=D*1024;//ct[1].workNum=mct[0].workNum;
    //mct.type=POINT,mct[1].type=RATE;

    int winner=0,win_num[2]={0},N=0;
    int now_color[2];
    int whiteWinNum=0;
    int moves[(maxn-2)*(maxn-2)][2]={0};
    string savingName;
    printf("How many times AIs will play:"),cin>>N;
    //N=min(1000,max(1,N));
    printf("Saving name:"),cin>>savingName;

    int fst,sec;
    printf("Which AI plays(input twice):\n1.POINT\n2.RATE\n3.MIX\n");
    char ch=getch();
    if(ch=='1') fst=POINT;
    else if(ch=='2') fst=RATE;
    else fst=MIX;
    ch=getch();
    if(ch=='1') sec=POINT;
    else if(ch=='2') sec=RATE;
    else sec=MIX;
    for(int i=1;i<=N;i++)
    {
        ofstream fout(str_ch("Record\\"+savingName+"_"+num_str(i)+".ini"));
        mp.Set();
        //now_color[0]=black,now_color[1]=white;
        //if(rand()%2) swap(now_color[0],now_color[1]);
        //system("cls");
        int KIND[2];
        //printf("1.AI_White is POINT\n2.AI_White is RATE\n");
        if(rand()%2) KIND[0]=fst;
        else KIND[0]=sec; 
        system("cls");
        //printf("1.AI_Black is POINT\n2.AI_Black is RATE\n");
        if(KIND[0]==sec) KIND[1]=fst;
        else KIND[1]=sec; 
        //system("cls");
        mp.count_();
        int moved[maxn-2][maxn-2];
        memset(moved,0,sizeof(moved));
        for(int i=st;i<(maxn-2)*(maxn-2)-1;i++)
        {
            mct.type=KIND[i%2];
            //SetXY((maxn)/2-2,0),printf("turn %d",i+1);
            SetXY(0,0),printf("Turn up or enjoy AI's play!");
            SetXY((maxn)/2-3,maxn+2),printf("space   ");
            SetXY((maxn)/2+3,maxn+2),printf("%d",mp.Space_());
            mp.draw_();
            char ch='\0';
            int X=(maxn-2)/2,Y=(maxn-2)/2;
            int work_depth=mct.work_depth;
            mct.work_depth/=mp.Space_();mct.work_depth+=rand()%60;
            double P[(maxn-2)*(maxn-2)],best;
            double countNum=0.0;
            int p[(maxn-2)*(maxn-2)][2];
            int q=0,r;
            for(int t=1;t<maxn-1;t++)
                for(int j=1;j<maxn-1;j++)
                {
                    if(moved[t-1][j-1]==0)
                        p[q][0]=t,p[q][1]=j,q++;
                }
            for(int t=0;t<q;t++) P[t]=0.0;
            for(int t=0;t<q;t++)
                if(mp.d[p[t][0]][p[t][1]]!=space)
                {
                    for(int j=t+1;j<q;j++)
                        p[j-1][0]=p[j][0],p[j-1][1]=p[j][1];
                    --q;
                }
            MAP m;
            m.from(mp);
            if(1)
            {
                m.draw_();
                countNum+=1.0;
                double p_=0.0;
                mct.work_depth>>=RESET_TIMES;
                for(int t=0;t<q;t++)
                {
                    m.Change(p[t][0],p[t][1]);
                    if(i%2) m.d[p[t][0]][p[t][1]]=black;
                    else m.d[p[t][0]][p[t][1]]=white;
                    mct.Work(m);
                    //color(15);
                    //SetXY(0,maxn+6);
                    m.Change(p[t][0],p[t][1]);
                    m.d[p[t][0]][p[t][1]]=space;
                    P[t]+=mct.now_point;
                    p_+=P[t];
                }
                p_/=(double)q;
                for(int T=0;T<RESET_TIMES;T++)
                {
                    mct.work_depth<<=1;
                    for(int t=0;t<q;t++)
                        if(P[t]>=p_)
                        {
                            m.Change(p[t][0],p[t][1]);
                            if(i%2) m.d[p[t][0]][p[t][1]]=black;
                            else m.d[p[t][0]][p[t][1]]=white;
                            mct.Work(m);
                            //color(15);
                            //SetXY(0,maxn+6);
                            m.Change(p[t][0],p[t][1]);
                            m.d[p[t][0]][p[t][1]]=space;
                            P[t]+=mct.now_point;
                        }
                    p_=0.0;for(int t=0;t<q;t++) p_+=P[t];p_/=(double)q;
                }
                //TRUE_WORK:;
                best=P[0],X=p[0][0],Y=p[0][1];
                for(int t=1;t<q;t++)
                {
                    if(i%2&&P[t]<best)
                        r=t,X=p[t][0],Y=p[t][1],best=P[t]/countNum;
                    if(i%2==0&&P[t]>best)
                        r=t,X=p[t][0],Y=p[t][1],best=P[t]/countNum;
                }
                mct.work_depth=work_depth;
                color(15);
                if(mct.type==POINT)
                    SetXY(0,maxn+1),printf("now point:                ");
                else if(mct.type==RATE)
                    SetXY(0,maxn+1),printf("now rate:                ");
                else SetXY(0,maxn+1),printf("mix rate:                ");
                SetXY(10,maxn+1),printf("%0.3f",best);
                Sleep(1000+rand()%500);
            }
            SetXY(maxn/2-3,maxn+3),printf("X,Y:%d,%d",X,Y);
            if(mp.d[X][Y]!=space)
                SetXY(maxn/2-4,maxn+4),printf("not space!");
            moved[X-1][Y-1]=1;
            mp.Change(X,Y);
            if(i%2) mp.d[X][Y]=black;
            else mp.d[X][Y]=white;
            mp.count_();
            SetXY(2,maxn+7),printf("White:  ");
            SetXY(2,maxn+8),printf("Black:  ");
            SetXY(8,maxn+7),printf("%d",mp.White);
            SetXY(8,maxn+8),printf("%d",mp.Black);
            fout<<X<<' '<<Y<<endl;
        }
        mp.count_();
        if(mp.White>mp.Black)
            if(KIND[0]==fst) winner=0;
            else winner=1;
        else if(KIND[0]==fst) winner=1;
             else winner=0;
        win_num[winner]++;
        Sleep(50);
        if(mp.White>mp.Black) fout<<"White win "<<mp.White-mp.Black<<endl,++whiteWinNum;
        else fout<<"Black win "<<mp.Black-mp.White<<endl;
        /*for(int t=0;t<(maxn-2)*(maxn-2)-1;t++)
            fout<<moves[t][0]<<' '<<moves[t][1]<<endl;*/
        Sleep(50);
    }

    system("cls");
    if(fst==POINT) printf("POINT win:%d\n",win_num[0]);
    else if(fst==RATE) printf("RATE win:%d\n",win_num[0]);
    else printf("MIX win:%d\n",win_num[0]);
    if(sec==POINT) printf("POINT win:%d\n",win_num[1]);
    else if(sec==RATE) printf("RATE win:%d\n",win_num[1]);
    else printf("MIX win:%d\n",win_num[1]);
    printf("White win:%d\nBlack win:%d\n",whiteWinNum,N-whiteWinNum);
    system("pause");
}

void Game(void)
{
    color(15),system("cls"),srand(time(0));
    printf("1.Exit\n");
    color(12),printf("2.New game\n"),color(15);
    printf("3.AI test\n"); 
    cin>>D;
    if(D==1) exit(0);
    if(D==2) MCTS_();
    if(D==3) AI_test();
    Game();
}

int main(void)
{
    //for(int i=0;i<=15;i++) color(15),cout<<i,color(17*i),cout<<' '<<endl;
    MAP m;
    m.Set(),m.d[2][2]=white,m.d[3][3]=black,m.draw_();
    HideCursor();
    cout<<"1.Rule\n2.Play\n";
    cin>>D;
    if(D==1) rule();
    if(D==2) Game();
}