botzone snake代码思路整理

现状:

目前天梯到了20/343,估计上限是15名左右。

PS:

1、代码量在600-800行左右,为什么是“左右”,因为一开始都是用STL写的,用了queue和各种vector,毕竟限时都是一秒,为了增大运算次数。测试之后,一秒内计算次数在10万次上下。
2、思路:蒙特卡洛树套价值评估。
3、关于价值评估:
每一个点的价值根据周围的情况不同要有不同的估值,根据上下左右四个点的状态(是否可行走)。分别估值为

switch(vis_sum){
                    case 1:weight[which][x][y]=1.0;break;
                    case 2:weight[which][x][y]=1.2;break;
                    case 3:weight[which][x][y]=1.6;break;
                    case 4:weight[which][x][y]=2.0;break;
                }

1)价值评估过程用bfs,根据最短路是否可达,判定某地图位置是否可达,并且计算最短距离。距离更近的snake占据该点,并且在计算价值时加上上述规定的此点价值。
2)价值评估过程,首先将所有蛇的身体转化为在固定时间之后会消失的动态障碍物。详细见函数to_obtacle()
3)价值评估某一点值的确定,目前用的是1-2之间的勾股数,还有一个单位1。这个很难确定到底怎么最好,但是肯定跟几何是有关系的,数学直觉用了勾股数,看起来效果还不错,但是怎么解释我也不会(so良好的算法是无法解释的…)。
4)多种未采用的价值评估的想法,可以加上一个平方根倒数(用Fast Inverse Square Root可降低复杂度,保证算力),a,b是我方和对方的价值评估总和, a a b l e a_{able} aable b a b l e b_{able} bable分别是双发可到达的地图上格点数目。比如:
( a − b + c 1 a 1 ∗ m ∗ n − ∣ a − b ∣ ) ( a + b + c 2 a 2 ∗ m ∗ n − ∣ a − b ∣ ) \frac{(a-b+ \frac{c_1}{\sqrt{a_1*m*n-|a-b|}} )}{(a+b+ \frac{c_2}{\sqrt{a_2*m*n-|a-b|}} )} (a+b+a2mnab c2)(ab+a1mnab c1)根据真分数性质还有很多常识,各位请自行理解到底为啥这么干。
5)或者,加一个修正,即不仅仅按照某点的占据来看,还要看整个地图中,到底有多少点可以走(plus可达性)。
0.9 ∗ ( a − b ) a + b + 0.1 ∗ ( a a b l e − b a b l e ) a a b l e + b a b l e 0.9*\frac{(a-b)}{a+b}+0.1*\frac{(a_{able}-b_{able})}{a_{able}+b_{able}} 0.9a+b(ab)+0.1aable+bable(aablebable)

关于

1、毕竟是小组作业,可以认为,命名乱的地方,写的不简洁的地方都不是我写的,但是你也可以认为都是我写的(95++%嗯哼?)。
2、缺点:很明显的地方是,仅仅根据最短路就判断这个点是不是可以到达局限性太大了,虽然MCTS后续可以给你修正好一些,但是毕竟误差就是误差。
3、因为snake是同时决策的游戏,(贪吃蛇大作战的那种?)就所以我把它分成两层不符合逻辑,并且会造成十分复杂的数据结构,造成不太好扩展代码。
4、参数没法证明是收敛的,波动较大,继承对局之后可能出现不同的胜负情况。这可能是因为用了随机洗牌函数rand_shuffle,但是在计算了10万次之后参数仍不收敛确实是漏洞,参数没有调整好造成的抖振现象吧。
5、遗憾:有一些想法最后没加上去,因为没有思路该怎么加。比如,保证考虑了所有因素的话,一个点周围不仅仅有障碍物、蛇的身体,还应该区分蛇的身体到底是哪一方的,以及对应应该有不同的更复杂的估值。

价值评估关键代码:

    int que[200];
    int dis_vis[2][17][17];
    double weight[2][17][17];
    void to_obstacle(){
        int k_temp=k;
        int xx,yy;
        int p=st0myfront();
        //tmp_board_for_us[p>>4][p&0x0f]=11+k+(k-1)/2;//头消失的时间
        for(int i=snaketmptail0;i<=snaketmphead0;i++){
            while(k<=9||((k>9)&&((k-9)%3==0))) k++;
            p=snake0[i];
            xx=p>>4,yy=p&0x0f;
            tmp_board_for_us[xx][yy]=k++;
        }
        k=k_temp;
        p=st1myfront();
        //tmp_board_for_op[p>>4][p&0x0f]=11+k+(k-1)/2;//头消失的时间
        for(int i=snaketmptail1;i<=snaketmphead1;i++){
            while(k<=9||((k>9)&&((k-9)%3==0))) k++;
            p=snake1[i];
            xx=p>>4,yy=p&0x0f;
            tmp_board_for_op[xx][yy]=k++;
        }
        return ;
    }
    void bfs(int which,int round)
    {
        int hh = 0;
        int tt = 0;

        int p;

        if(which)
        p=st1myfront();
        else
        p=st0myfront();

        que[tt++]=p;
        dis_vis[which][p>>4][p&0x0f]=0;//距离

        while(tt!=hh)
        {
            int cur = que[hh++];
            int x = cur>>4;
            int y = cur&0x0f;
            int vis_sum=0;
            for(int i=0; i<4; i++)
            {
                int xx = x+dx[i];
                int yy = y+dy[i];
                if(!inboard(xx,yy)) continue;
                if(dis_vis[which][xx][yy]!=INF){
                    vis_sum++;
                    continue;
                }
                if(!board[xx][yy]){//在界内则试一试
                    int barrier=tmp_board_for_us[xx][yy]>tmp_board_for_op[xx][yy]?tmp_board_for_us[xx][yy]:tmp_board_for_op[xx][yy];
                    int temp_round=round+dis_vis[which][xx][yy];//能到达则试一试
                    if(temp_round>=barrier)
                    {
                        vis_sum++;//联通数目加一
                        que[tt++] = (xx<<4)+yy;//未访问过则加入
                        dis_vis[which][xx][yy] = dis_vis[which][x][y] + 1;
                    }//最多多访问三次
                }
                switch(vis_sum){
                    case 1:weight[which][x][y]=1.0;break;
                    case 2:weight[which][x][y]=1.2;break;
                    case 3:weight[which][x][y]=1.6;break;
                    case 4:weight[which][x][y]=2.0;break;
                }
            }
        }
        return ;
    }
    double simulate_dis_fight()
    {
        for(int k=0; k<2; k++)
        {
            for(int i=1; i<=n; i++)
            {
                for(int j=1; j<=m; j++)
                {
                    dis_vis[k][i][j]=INF;
                }
            }
        }
        //outboard();
        int k_temp=k;
        to_obstacle();
        k=k_temp;
        bfs(0,k_temp);
        bfs(1,k_temp);

        double me=0;
        double op=0;
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=m; j++)
            {
                if(dis_vis[0][i][j]==INF&&dis_vis[1][i][j]==INF)continue;
                if(dis_vis[0][i][j]<dis_vis[1][i][j])
                {
                    me+=weight[0][i][j];
                }
                if(dis_vis[0][i][j]>dis_vis[1][i][j])
                {
                    op+=weight[1][i][j];
                }
            }
        }
        if(op-me==0) return 0.0;
        return (op-me)/(op+me);
    }

完整代码:

#pragma GCC optimize("O2")
#pragma GCC optimize("O3")
#pragma GCC optimize("Ofast,no-stack-protector")
#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
#include"jsoncpp/json.h"
using namespace std;//框架已经有了
const int MAX_NUM=1e6;
const int INF=1e9;
const int dx[4]= {-1, 0, 1, 0};
const int dy[4]= { 0, 1, 0,-1};
int tmp_board_for_us[17][17];//从某一个位置开始,向下走的时候,进行随机模拟
int tmp_board_for_op[17][17];//从某一个位置开始,向下走的时候,进行随机模拟
int count_num=0;
struct point
{
    int x,y;
    point(int _x,int _y)
    {
        x=_x;
        y=_y;
    }
};
list<point> snake[2],snake_temp[2]; // 0表示自己的蛇,1表示对方的蛇
int snake0[400];
int snake1[400];
int snaketmp0[400];
int snaketmp1[400];
int snakehead0=-1;
int snaketail0=0;
int snakehead1=-1;
int snaketail1=0;
int snaketmphead0=-1;
int snaketmptail0=0;
int snaketmphead1=-1;
int snaketmptail1=0;
int board[17][17];
int k;//回合数
int n,m;
inline vector<int> try_dir(int which);
void outboard();
void outputSnakeBody();
inline int s1myfront() //返回头坐标
{
return snake1[snakehead1];
}
inline int s0myfront() //返回头坐标
{
return snake0[snakehead0];
}
inline int st1myfront() //返回头坐标
{
return snaketmp1[snaketmphead1];
}
inline int st0myfront() //返回头坐标
{
return snaketmp0[snaketmphead0];
}
inline int st0myback() //返回尾坐标
{
return snaketmp0[snaketmptail0];
}
inline int st1myback() //返回尾坐标
{
return snaketmp1[snaketmptail1];
}
inline void st1mypushfront(int loc){
snaketmphead1++;
snaketmp1[snaketmphead1]=loc;
}
inline void st0mypushfront(int loc){
snaketmphead0++;
snaketmp0[snaketmphead0]=loc;
}
class IO
{
public:
    inline void readJson() //读取输入
    {
        memset(board,0,sizeof(board));
        string str;//高度
        string temp;//宽度
        while(getline(cin,temp))
            str+=temp;

        Json::Reader reader;
        Json::Value input;
        reader.parse(str,input);

        n=input["requests"][(Json::Value::UInt) 0]["height"].asInt();  //棋盘高度
        m=input["requests"][(Json::Value::UInt) 0]["width"].asInt();   //棋盘宽度
        int x=input["requests"][(Json::Value::UInt) 0]["x"].asInt();  //读蛇初始化的信息
        if (x==1)
        {
            snake[0].push_front(point(1,1));
            snake[1].push_front(point(n,m));
        }
        else
        {
            snake[1].push_front(point(1,1));
            snake[0].push_front(point(n,m));
        }

        //处理地图中的障碍物
        int obsCount=input["requests"][(Json::Value::UInt) 0]["obstacle"].size();
        for (int i=0; i<obsCount; i++)
        {
            int ox=input["requests"][(Json::Value::UInt) 0]["obstacle"][(Json::Value::UInt) i]["x"].asInt();
            int oy=input["requests"][(Json::Value::UInt) 0]["obstacle"][(Json::Value::UInt) i]["y"].asInt();
            board[ox][oy]=1;
        }

        //蛇从出生点成长到当前局面状态
        total=input["responses"].size();
        int dire;
        for (int i=0; i<total; i++)
        {
            dire=input["responses"][i]["direction"].asInt();
            move(0,dire,i);

            dire=input["requests"][i+1]["direction"].asInt();
            move(1,dire,i);
        }//
        snake_init();
    }


    void inline snake_init()
    { ///snake数组初始化 头指针初始化

    for(list<point>::iterator iter=--snake[0].end(); iter!=--snake[0].begin(); --iter)
    {
    snakehead0++;
    snake0[snakehead0]=((iter->x)<<4)+iter->y;
    }

    for(list<point>::iterator iter=--snake[1].end(); iter!=--snake[1].begin(); --iter)
    {
    snakehead1++;
    snake1[snakehead1]=(iter->x<<4)+iter->y;
    }

    }

    void move(int id,int dire,int num)  //编号为id的蛇朝向dire方向移动一步
    {
        point p=*(snake[id].begin());
        int x=p.x+dx[dire];
        int y=p.y+dy[dire];

        snake[id].push_front(point(x,y));//头插入法
        if (!whetherGrow(num))
            deleteEnd(id);
    }
    bool whetherGrow(int num)  //本回合是否生长, 生长从0回合开始 生长则不删除尾巴
    {
        if (num<=9) return true;
        if ((num-9)%3==0) return true;
        return false;
    }

    void deleteEnd(int id) //删去尾巴
    {
        snake[id].pop_back();
    }
    inline void writeJson(int dir)
    {
        Json::Value ret;
        ret["response"]["direction"]=dir;//
        ret["debug"]["count_num"]=count_num;
        int start=clock();
        ret["debug"]["time"]=start;
        Json::FastWriter writer;
        cout<<writer.write(ret)<<endl;
        return;
    }
    int total;//回合数
};
class rand_maker
{
public:
    inline int rand_int(int l,int r){
        return rand()%(r-l+1)+l;
    }
    inline void rand_shuffle(vector<int>::iterator starting,vector<int>::iterator ending)// ending 指向最后元素后一位?
    {
        int num=ending-starting;
        for(int i=num-1; i>=1; i--)
        {
            int j=rand_int(0,i-1);
            swap(*(starting+i),*(starting+j));
        }
        return;
    }
};
IO io;
rand_maker r1;
class MCTS
{
private:
    int total;//回合数
public:
    //我方对方棋盘
    int board_for_us[17][17];//保存输入的我方位置信息
    int board_for_op[17][17];//保存输入的对方位置信息
    inline bool inboard(int x,int y) //inboard return true else return false
    {
        return x>=1 && x<=n && y>=1 && y<=m;
    }
    inline void init() //board_for_us board_for_op 1表示障碍物 2表示有蛇
    {
        root=0;
        next_using=1;
        ///
        total=io.total;
        k=total;

        ///board_for_us初始化
        for(int i=snaketail0;i<=snakehead0;i++)
        {
        board_for_us[snake0[i]>>4][snake0[i]&0x0f]=2;
        }
        for(int i=snaketail1;i<=snakehead1;i++)
        {
        board_for_op[snake1[i]>>4][snake1[i]&0x0f]=2;
        }
        snakeNode[0].which=1;    ///把这个头通过list初始化
        snakeNode[0].fa=-1;


        snakeNode[root].head0=s0myfront();//头
        snakeNode[root].head1=s1myfront();//头

        ///snaketmp初始化
        for(int i=snaketail0;i<=snakehead0;i++)
        {
        snaketmphead0++;
        snaketmp0[snaketmphead0]=snake0[i];
        }
        for(int i=snaketail1;i<=snakehead1;i++)
        {
        snaketmphead1++;
        snaketmp1[snaketmphead1]=snake1[i];
        }

        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=m; j++)
            {
                tmp_board_for_us[i][j]=board_for_us[i][j];
                tmp_board_for_op[i][j]=board_for_op[i][j];
            }
        }
//        outboard();
//        outputSnakeBody();
        snakeNode[root].init_data();
    }
    ///
    int que[200];
    int dis_vis[2][17][17];
    double weight[2][17][17];
    void to_obstacle(){
        int k_temp=k;
        int xx,yy;
        int p=st0myfront();
        //tmp_board_for_us[p>>4][p&0x0f]=11+k+(k-1)/2;//头消失的时间
        for(int i=snaketmptail0;i<=snaketmphead0;i++){
            while(k<=9||((k>9)&&((k-9)%3==0))) k++;
            p=snake0[i];
            xx=p>>4,yy=p&0x0f;
            tmp_board_for_us[xx][yy]=k++;
        }
        k=k_temp;
        p=st1myfront();
        //tmp_board_for_op[p>>4][p&0x0f]=11+k+(k-1)/2;//头消失的时间
        for(int i=snaketmptail1;i<=snaketmphead1;i++){
            while(k<=9||((k>9)&&((k-9)%3==0))) k++;
            p=snake1[i];
            xx=p>>4,yy=p&0x0f;
            tmp_board_for_op[xx][yy]=k++;
        }
        return ;
    }
    void bfs(int which,int round)
    {
        int hh = 0;
        int tt = 0;

        int p;

        if(which)
        p=st1myfront();
        else
        p=st0myfront();

        que[tt++]=p;
        dis_vis[which][p>>4][p&0x0f]=0;//距离

        while(tt!=hh)
        {
            int cur = que[hh++];
            int x = cur>>4;
            int y = cur&0x0f;
            int vis_sum=0;
            for(int i=0; i<4; i++)
            {
                int xx = x+dx[i];
                int yy = y+dy[i];
                if(!inboard(xx,yy)) continue;
                if(dis_vis[which][xx][yy]!=INF){
                    vis_sum++;
                    continue;
                }
                if(!board[xx][yy]){//在界内则试一试
                    int barrier=tmp_board_for_us[xx][yy]>tmp_board_for_op[xx][yy]?tmp_board_for_us[xx][yy]:tmp_board_for_op[xx][yy];
                    int temp_round=round+dis_vis[which][xx][yy];//能到达则试一试
                    if(temp_round>=barrier)
                    {
                        vis_sum++;//联通数目加一
                        que[tt++] = (xx<<4)+yy;//未访问过则加入
                        dis_vis[which][xx][yy] = dis_vis[which][x][y] + 1;
                    }//最多多访问三次
                }
                switch(vis_sum){
                    case 1:weight[which][x][y]=1.0;break;
                    case 2:weight[which][x][y]=1.2;break;
                    case 3:weight[which][x][y]=1.6;break;
                    case 4:weight[which][x][y]=2.0;break;
                }
            }
        }
        return ;
    }
    double simulate_dis_fight()
    {
        for(int k=0; k<2; k++)
        {
            for(int i=1; i<=n; i++)
            {
                for(int j=1; j<=m; j++)
                {
                    dis_vis[k][i][j]=INF;
                }
            }
        }
        //outboard();
        int k_temp=k;
        to_obstacle();
        k=k_temp;
        bfs(0,k_temp);
        bfs(1,k_temp);

        double me=0;
        double op=0;
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=m; j++)
            {
                if(dis_vis[0][i][j]==INF&&dis_vis[1][i][j]==INF)continue;
                if(dis_vis[0][i][j]<dis_vis[1][i][j])
                {
                    me+=weight[0][i][j];
                }
                if(dis_vis[0][i][j]>dis_vis[1][i][j])
                {
                    op+=weight[1][i][j];
                }
            }
        }
        if(op-me==0) return 0.0;
        return (op-me)/(op+me);
    }
    inline void modify_board(int node,int k) //修改盘面
    {
        if(tail_to_move(k))
        {
            int p=st1myback();
            tmp_board_for_op[p>>4][p&0x0f]=0;
            snaketmptail1++;

            p=st0myback();
            tmp_board_for_us[p>>4][p&0x0f]=0;
            snaketmptail0++;
        }

        int x=snakeNode[node].head1>>4;
        int y=snakeNode[node].head1&0x0f;

        tmp_board_for_op[x][y]|=2;
        st1mypushfront((x<<4)+y);


        int fa=snakeNode[node].fa;
        x=snakeNode[fa].head0>>4;
        y=snakeNode[fa].head0&0x0f;

        tmp_board_for_us[x][y]|=2;
        st0mypushfront((x<<4)+y);
        return ;
    }
    inline bool tail_to_move(int num) //尾巴是否移动,回合数从0开始
    {
        if (num<=9) return false;
        if ((num-9)%3==0) return false;
        return true;
    }
    inline int return_ans() //返回答案
    {
        int endClock=int(0.99*double(CLOCKS_PER_SEC));
        while(clock()<endClock)
        {
            UCT(root);
        }
        count_num=next_using;
        int ans=best_score_child(root,0);
        return snakeNode[ans].dir;
    }//
private:
    class treeNode
    {
    public://进行先我后对方的顺序
        int head0;//我方头的位置所在
        int head1;//对方头的位置所在
        int which;//0代表是我方,1代表是对方
        int fa;//父节点

        int intchild[4];//孩子节点
        int intvachild[4];//备选节点
        int child_p;
        int vachild_p;

        int maxChildNum;//最多合法孩子数目(对下一节点
        int dir;

        double score;//总得分
        int total;//模拟次数

        inline void init_data()
        {
            child_p=-1;
            vachild_p=-1;

            vector<int> temp=try_dir((which+1)&1);//对子节点进行拓展

            r1.rand_shuffle(temp.begin(),temp.end());

            for(vector<int>::iterator it=temp.begin(); it!=temp.end(); it++)
            {
            vachild_p++;
            intvachild[vachild_p]=(*it);  //孩子都放到里面
            }
            maxChildNum=vachild_p+1;
        }
    };
    treeNode snakeNode[MAX_NUM+5];//整个博弈树
    int next_using;//下一个能用的空闲的点的坐标
    int root=0;
    inline bool myempty(int node){
    if(snakeNode[node].vachild_p<0)
    return true;
    else
    return false;
    }
    inline bool isEnd(int node)
    {
        return snakeNode[node].maxChildNum==0;   //结束则返回1,否则返回0
    }
    inline bool couldExpand(int node)
    {
        return !myempty(node); //空则不能扩展,否则可以拓展则返回1
    }
    inline int expand(int node) //对node节点进行扩展
    {
        //选child第一个元素作为扩展节点 扩展之前已经随机打乱过了
        int dir=snakeNode[node].intvachild[snakeNode[node].vachild_p];
        snakeNode[node].vachild_p--;//从有效孩子中删除
        return newNode(node,dir);//返回新的节点
    }
    inline int newNode(int fa,int dir) //创建新的节点
    {
        int N=next_using++;
        snakeNode[N].fa=fa;
        snakeNode[N].dir=dir;
        snakeNode[N].which=(snakeNode[fa].which+1)&1;
        snakeNode[N].total=0;
        snakeNode[N].score=0;
        if(snakeNode[N].which==0) snakeNode[N].init_data();
        int side=snakeNode[N].which;
        if(side)
        {
            int xx=(snakeNode[fa].head1>>4)+dx[dir],yy=(snakeNode[fa].head1&0x0f)+dy[dir];
            snakeNode[N].head1=(xx<<4)+yy;//两个头都要修改
            snakeNode[N].head0=snakeNode[fa].head0;
        }else{
            int xx=(snakeNode[fa].head0>>4)+dx[dir],yy=(snakeNode[fa].head0&0x0f)+dy[dir];
            snakeNode[N].head0=(xx<<4)+yy;//两个头都要修改
            snakeNode[N].head1=snakeNode[fa].head1;
        }

        snakeNode[fa].child_p++;
        snakeNode[fa].intchild[snakeNode[fa].child_p]=N;

        return N;
    }
    //下述两个函数只需要判断最新走的那一步是否是冲突的,即只需要判断head
    inline bool if_we_die(int xx,int yy)//我方是否死亡
    {//只需要判断头的位置
        if(!board[xx][yy]&&!tmp_board_for_op[xx][yy]) return false;
        return true;
    }
    inline bool if_op_die(int xx,int yy)
    {//只需要判断头的位置
        if(!board[xx][yy]&&!tmp_board_for_us[xx][yy]) return false;
        return true;
    } //对方是否死亡
    inline bool if_continue(int node)
    {
        int xx=snakeNode[node].head0>>4;
        int yy=snakeNode[node].head0&0x0f;

        int flag_for_me=if_we_die(xx,yy);

        xx=snakeNode[node].head1>>4;
        yy=snakeNode[node].head1&0x0f;
        int flag_for_op=if_op_die(xx,yy);

        if(flag_for_me||flag_for_op) return false;
        else return true;
    }
    inline int calcScore(int node)
    {
        //返回对方得分
        int fa=snakeNode[node].fa;
        int xx=snakeNode[fa].head0>>4;
        int yy=snakeNode[fa].head0&0x0f;

        int flag_for_me=if_we_die(xx,yy);

        xx=snakeNode[node].head1>>4;
        yy=snakeNode[node].head1&0x0f;
        int flag_for_op=if_op_die(xx,yy);
        if(flag_for_me&&flag_for_op) return 0;//同归于尽
        if(flag_for_me) return 1;//我死了,对方获胜
        else return -1;//对方死了,我获胜
    }//计算当前局面的评分
    inline int best_score_child(int node ,int c) //返回评分值最高的孩子节点的下标
    {
        double mini=-1e9;
        int pos=0;
        for(int i=0;i<=snakeNode[node].child_p;i++) //遍历所有孩子找最满意的孩子
        {

            int tmp=snakeNode[node].intchild[i];//孩子节点
            double ucb=calcUcb(tmp,c);
            if(ucb>mini)
            {
                mini=ucb;
                pos=tmp;
            }
        }
        return pos;//将孩子的数组下标返回去
    }
    inline double calcUcb(int node,int c)
    {
        treeNode t=snakeNode[node],fa=snakeNode[snakeNode[node].fa];//子节点,父节点
        return (double)t.score/t.total*0.5+sqrt(c*log(fa.total)/t.total);//计算参数
    }
    inline void UCT(int node)
    {
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=m; j++)
            {
                tmp_board_for_us[i][j]=board_for_us[i][j];
                tmp_board_for_op[i][j]=board_for_op[i][j];
            }
        }

        snaketmphead0=snakehead0;
        snaketmptail0=snaketail0;
        snaketmphead1=snakehead1;
        snaketmptail1=snaketail1;

        k=total;//回合数
        while(isEnd(node)==0)
        {
            if(couldExpand(node))
            {
                node=expand(node);//向下扩展节点
                if(snakeNode[node].which==1)
                {
                    modify_board(node,k);
                    k++;
                    if(snakeNode[node].maxChildNum==0)
                        snakeNode[node].init_data();
                    if(if_continue(node)==0) snakeNode[node].maxChildNum=0;//如果分出了胜负,则不能继续拓展
                    break;//扩展到对方节点,则退出
                }
                if(couldExpand(node)){
                    node=expand(node);//否则要再模拟一次,到达对方节点退出
                    modify_board(node,k);
                    k++;
                    if(snakeNode[node].maxChildNum==0)
                        snakeNode[node].init_data();
                    if(if_continue(node)==0) snakeNode[node].maxChildNum=0;//如果分出了胜负,则不能继续拓展
                    break;
                }
                break;
            }
            node=best_score_child(node,1.8);//走最好的孩子
            if(snakeNode[node].which==1){
                modify_board(node,k);
                k++;
                if(snakeNode[node].maxChildNum==0)
                    snakeNode[node].init_data();
            }
        }
        double value=0;
        if(snakeNode[node].which==0){
            value=1;
        }
        else if(isEnd(node)){//当前颜色是对方,并且我方已经无路可走
            if(if_continue(node)==0){
                value=calcScore(node);//已经分出了胜负,前方已经强行赋值为0
            }
            else{
                int num_op=try_dir(1).size();//这种情况是说,当前我方已经无路可走,则计算一下对方可以走多少,则当前的局数目应当加1
                if(num_op==0) value=0;//若对方也无路可走,则平局
                else value=1;//否则对方获胜
            }
        }
        else
            value=simulate_dis_fight();
        while(node>=0)//从尾巴向上
        {
            snakeNode[node].total++;
            snakeNode[node].score+=value;
            value=-value;
            node=snakeNode[node].fa;//对方要获得相反的损失
        }
        return;
    }
};
MCTS mcts;
inline vector<int> try_dir(int which)
{
    int p;
    if(which)
    p=st1myfront();
    else
    p=st0myfront();

    int x=p>>4;
    int y=p&0x0f;

    vector<int> ans;
    for(int i=0; i<4; i++)
    {
        int xx=x+dx[i],yy=y+dy[i];
        if(xx>=1 && xx<=n && yy>=1 && yy<=m)
        {
            int tail=st0myback();
            if(tail==(xx<<4)+yy)
                if(!(k<=9||(k-9)%3==0))//修改了 加了取反
                {
                    ans.push_back(i);
                    continue;
                }
            tail=st1myback();
            if(tail==(xx<<4)+yy)
                if(!(k<=9||(k-9)%3==0))//修改了 加了取反
                {
                    ans.push_back(i);
                    continue;
                }
            if(!board[xx][yy]&&!tmp_board_for_op[xx][yy]&&!tmp_board_for_us[xx][yy])
            {
                ans.push_back(i);
            }
        }
    }
    return ans;
}
void outputSnakeBody()    //调试语句
{
    for(int id=0;id<2;id++){
        cout<<"snake_temp No."<<id<<endl;
        for (list<point>::iterator iter=snake_temp[id].begin();iter!=snake_temp[id].end();++iter)
		cout<<iter->x<<" "<<iter->y<<endl;
        cout<<endl;
    }

}
void outboard()
{

    printf("this is board_for_us\n");
    for(int j=1; j<=m; j++)
    {
        for(int i=1; i<=n;i++)
            printf("%d ",tmp_board_for_us[i][j]);
        cout<<endl;
    }
    cout<<endl<<endl;
    printf("this is board_for_op\n");
    for(int j=1; j<=m; j++)
    {
        for(int i=1; i<=n; i++)
            printf("%d ",tmp_board_for_op[i][j]);
        cout<<endl;
    }
    cout<<endl<<endl;
}
int main()
{
    //freopen("in.txt", "r", stdin);
    srand(time(0));
    io.readJson();
    mcts.init();
    int dir=mcts.return_ans();
    io.writeJson(dir);
    return 0;
}

最后

对于计算机博弈有了更深刻的理解吧,可惜在至今没有好好探索过博弈树,并且想好好学学α-β剪枝和PVS还有渴望搜索。 而且你好好跟别人交流的话,完全无私的话,更容易收获更多,反正我是这么想的。

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值