2021编码大赛

这是一个双方pk的挖矿游戏。

地图上有一些矿和障碍物,双方从各自基地派出一些机器人去挖矿,按照挖矿数量算得分。
区域平面划分成若干个最小的正方形单元格:
机器人由牵引车和拖车组成,牵引车和拖车各独占一个单元格,即机器人独占两个连续单元格。
矿占用一个单元格,但一个单元格内可能有多个矿。
石块独占一个单元格。
每个机器人每回合接收一条指令,可以接收的指令有:出基地、移动、拿矿,其中移动和拿矿需要提供方向(前面、左边、右边)

第一版代码:

#include "player.h"
#include "cal.h"
#include "json.hpp"
#include <iostream>
#include <queue>

using Json = nlohmann::json;

namespace Robot {

Location LERR = {-1,-1};
map<int,int>smap;  // Sobj
map<int,int>dmap;  // Dobj
map<int,int>dmapBak;  // 备份dmap

std::string Player::SerializeRegistration()
{
    Json r_json = {
        {"msg_type", "registration"},
        {"msg_data", {{"team_token", token.c_str()}}}
    };

    std::string ser_reg = r_json.dump();

    char buff[16] = { 0 };
    sprintf(buff, "%05d", (int)ser_reg.size());
    std::string rt(buff, 5);
    return rt + ser_reg;
}

std::string Player::SerializeActions()
{
    Json array_json = Json::array();
    for (auto& action : GetActions()) {
        array_json.push_back(action.GetActionMap());
    }

    Json a_json =  {
        {"msg_type", "action"},
        {"msg_data", {
            {"round", round.round},
            {"actions", array_json}}}
    };

    std::string ser_act = a_json.dump();

    char buff[16] = { 0 };
    sprintf(buff, "%05d", (int)ser_act.size());
    std::string rt(buff, 5);
    return rt + ser_act;
}

// 解析首次发送的全局信息
void Player::ParseContext(std::string& context_string)
{
    Json m_json = Json::parse(context_string);
    if (m_json["msg_type"] != "game_start") {
        std::cout << "receive invalid message type: " << m_json["msg_type"] << "vs game_start." << std::endl;
        return;
    }
    auto& c_json = m_json["msg_data"];

    ctx.timeout = c_json["action_timeout"];
    ctx.max_round = c_json["max_round"];
    ctx.trailer_size = c_json["trailer_size"];
    ctx.map.height = c_json["map_height"];
    ctx.map.width = c_json["map_width"];
    ctx.warehouse.id = c_json["registry"]["id"];
    ctx.warehouse.location.x = c_json["registry"]["location"][0];
    ctx.warehouse.location.y = c_json["registry"]["location"][1];
    ctx.warehouse.size = c_json["registry"]["size"];

    for (auto& element : c_json["registry"]["ports"]) {
        Location loc {element[0], element[1]};
        ctx.warehouse.ports.push_back(loc);
    }

    for (auto& player : c_json["teams"]) {
        if (player["team_name"] == name) {
            ctx.id_range.min = player["object_id_range"][0];
            ctx.id_range.max = player["object_id_range"][1];
        }
    }
}

// 解析每次发的消息
void Player::ParseInquire(std::string& inquire_string)
{
    Json m_json = Json::parse(inquire_string);
    if (m_json["msg_type"] == "game_over") {
        std::cout << "Server wants you home for dinner, shield number: ";
        for (auto & player : m_json["msg_data"]) {
            if (player["team_name"] == name) {
                std::cout << player["shield_num"] << std::endl;
                break;
            }
        }

        round.round = -1;
        return;
    }
    if (m_json["msg_type"] != "inquire") {
        std::cout << "receive invalid message type: " << m_json["msg_type"] << "vs inquire." << std::endl;
        return;
    }

    auto& i_json = m_json["msg_data"];

    round.round = i_json["round"];
    round.objects.clear();
    for (auto& element : i_json["objects"]) {
        Object oj;
        oj.type = element["type"];
        oj.id = element["id"];
        oj.location.x = element["location"][0];
        oj.location.y = element["location"][1];
        oj.number = 1;
        if (oj.type == SHIELD || oj.type == TRAILER) {
            oj.number = element["number"];
        }
        round.objects.push_back(oj);
    }
}

std::vector<Action> Player::GetActions()
{
    static int flag = 1;
    if(flag)fillCtx();
    flag=0;
    fillMap();
    vector<Action> ans = move(ctx.timeout);
    return ans;
}

// 记录全局信息,只执行一次
void Player::fillCtx()
{
    for(int i = ctx.warehouse.location.x;i<ctx.warehouse.location.x+ctx.warehouse.size;i++){
        for(int j = ctx.warehouse.location.y;j<ctx.warehouse.location.y+ctx.warehouse.size;j++)
            smap[Lint(i,j)]=R1; // 记录我方基地所有格子
    }
    for(auto obj:round.objects){
        cout<<" obj.type="<<obj.type<<endl;
        cout<<" obj.id="<<obj.id<<endl;
        cout<<"player.ctx.id_range.min="<<ctx.id_range.min<<endl;
        cout<<"player.ctx.id_range.max="<<ctx.id_range.max<<endl;
        if(obj.type==ROBOT && Mine(obj.id))myRobotId.push_back(obj.id); // 记录我方所有机器人ID
        if(!Mine(obj.id))cout<<" why not!! \n";
    }
}

// 记录地图信息
void Player::fillMap()
{
    // 记录 map<Location,int>smap
    for(auto obj:round.objects){
        if(obj.type==REGISTRY){
            if(Mine(obj.id))continue;//第一次已经记录我方基地所有格子
            smap[Lint(obj)] = R2;
            /// 此处需要补充,根据局部格子和基地大小推测对方基地位置
            /// 只要探测到任何一个角落,就能推算出基地的整个位置
        }
        else if(obj.type==WALL)smap[Lint(obj)]=W;
        else smap[Lint(obj)]=NRNW;
    }
    for(auto obj:round.objects){
        if(obj.type==EMPTY)dmap[Lint(obj)]=EM;
        else if(obj.type==SHIELD)dmap[Lint(obj)]=SH;
        else if(obj.type==ROBOT)dmap[Lint(obj)]=Mine(obj.id)?H1:H2;
        else if(obj.type==TRAILER)dmap[Lint(obj)]=Mine(obj.id)?T1:T2;
    }
    /// 根据上一回合dmapBak推测本回合dmap,比如对方车头现在只能是车头或车尾
    /// 之前有屏蔽器的地方现在可能有,之前没有屏蔽器的地方现在一定没有
    dmapBak = dmap;
}


//获取所有的邻居,保证输出的位置都在地图范围内,但还需校验是否avail
vector<Location> Player::neig(Location s)
{
    vector<Location>ans;
    for(int i=0;i<4;i++){
        Location e = Lnei(s,i);
        if(Lin(e))ans.push_back(e);
    }
    return ans;
}

// flag = 0 只把墙和对方仓库当成障碍物 flag = 1 当前真实障碍物
bool Player::avail(Location s, int flag)
{
    if(flag==0){
        return smap[Lint(s)]==R1 || smap[Lint(s)]==NRNW;
    }else if(flag==1){
        return smap[Lint(s)]==R1 || (smap[Lint(s)]==NRNW && dmap[Lint(s)]==EM);
    }
    //-----------------------路过对方基地旁边、对方机器人旁边的情况怎么算
    return  false;
}

// 从s到e的最短路的第一步的位置
Location Player::p2p(Location s, Location e, int flag)
{
    map<int,int>m;
    m[Lint(e)]=1;
    queue<Location>q;
    q.push(e);
    Location t;
    while(!q.empty()){
        t = q.front();
        if(Lsame(s,e))break;
        vector<Location> v = neig(t);
        for(auto vi:v){
            if(m[Lint(vi)])continue;
            if(!avail(vi,flag))continue;
            m[Lint(vi)]=m[Lint(t)]+1;
            q.push(vi);
        }
        q.pop();
    }
    for(int i=0;i<4;i++){
        Location e = Lnei(s,i);
        if(Lin(e)==Lin(s)-1)return e;
    }
    return LERR;
}
// 从车子到e的最短路的第一步的移动方向
// FORWARD = 0, // 前进 RIGHT = 1, // 右转 LEFT = 3, // 左转  -1 不可达
// flag = 0 只把墙和对方仓库当成障碍物 flag = 1 当前真实障碍物
int Player::p2p(Location head, Location tail, Location e, int flag)
{
    int r1 = L2d(head, tail);
    Location la = p2p(head,e,flag);
    if(Lsame(la, LERR))return -1;
    int r2 =  L2d(la, head);
    return d2d(r1,r2);
}
int Player::p2p(Location head, Location tail, Location e)
{
    int ans=p2p(head,tail,e,1);
    if(ans!=-1)return ans;
    ans=p2p(head,tail,e,0);
    //-----------------------  需要特判这个方向不是空地的情况
    return ans;
}

vector<Action> Player::move(int timeout)
{
    std::vector<Action> actions;
    /*
    Action action(GO_OUT, myRobotId[0], 0);
    actions.push_back(action);
    Action action2(GO_OUT, myRobotId[1], 1);
    actions.push_back(action2);
    Action action3(GO_OUT, myRobotId[2], 2);
    actions.push_back(action3);
    Action action4(GO_OUT, myRobotId[3], 3);
    actions.push_back(action4);
    */
    return actions;
}


}

cal.cpp

#include "cal.h"
#include <iostream>
using namespace std;


int dx[]={-1,0,1,0}; //上右下左
int dy[]={0,1,0,-1}; //上右下左

//上右下左
Location Lnei(Location s,int dir)
{
    return {s.x+dx[dir],s.y+dy[dir]};
}

bool Lcmp(Location l1,Location l2)
{
    if(l1.x==l2.x)return l1.y<l2.y;
    return l1.x<l2.x;
}

bool Lin(Location s)//在矩形内
{
    Robot::Player player = Robot::PlayerSingleton::GetInstance();
    return s.x>=0 && s.x<player.ctx.map.height && s.y>=0 && s.y<player.ctx.map.width;
}

Location L(int i,int j)//坐标变成位置Location
{
    Location ans={i,j};
    return ans;
}

int Lint(Location s)//位置Location变成整数,-1表示矩形外
{
    Robot::Player player = Robot::PlayerSingleton::GetInstance();
    if(Lin(s))return s.x*player.ctx.map.width+s.y;
    return -1;
}
int Lint(Object obj)//obj的位置变成整数
{
    return Lint(obj.location);
}
int Lint(int i,int j)//坐标变成整数,-1表示矩形外
{
    return Lint(L(i,j));
}

int Ldis(Location s,Location e)//曼哈顿距离
{
    int x=s.x-e.x,y=s.y-e.y;
    x=x>0?x:-x, y=y>0?y:-y;
    return x+y;
}
bool Lsame(Location s,Location e)//相同位置
{
    return Ldis(s,e)==0;
}
bool LisNei(Location s,Location e)//相邻位置
{
    return Ldis(s,e)==1;
}

int L2d(Location head,Location tail)//head相对于tail的方向,上右下左
{
    for(int i=0;i<4;i++){
        if(Lsame(Lnei(tail,i),head))return i;
    }
    return -1;
}

int d2d(int d1,int d2)//方向d1到方向d2之间的移动方向,前右后左
{
    if(d1==-1||d2==-1)return -1;
    return (d2+4-d1)%4;
}

bool Mine(int id) //id属于我方
{
    Robot::Player player = Robot::PlayerSingleton::GetInstance();
    cout<<"start Mine\n";
    cout<<"id ="<<id<<endl;
    cout<<"player.ctx.id_range.min="<<player.ctx.id_range.min<<endl;
    cout<<"player.ctx.id_range.max="<<player.ctx.id_range.max<<endl;
    return id>=player.ctx.id_range.min && id<player.ctx.id_range.max;
}

然后开始逐步添加策略:
(1)把车子分为去挖矿的车子、去探索迷雾的车子等,如何高效的把整个地图探索完
(2)挖矿的策略,是根据矿去分配最近的车,还是根据车去选择最近的矿?
根据运行的结果来看,这2种策略都很有局限性。
有个继续优化的思路是把车子和矿配对的所有二元组放到一起,按照策略去整体规划。
(3)很多很多细小的策略

最终提交版本:

#include <iostream>
#include <queue>
#include "path.h"
#include "player.h"
#include "cal.h"
#include "json.hpp"

using Json = nlohmann::json;

namespace Robot {

Location LERR = {-1,-1};
#define TIME1 clock_t start,finish;start=clock();
#define TIME2 finish=clock();cout<<(finish-start)/1000<<"ms\n";

//输出一维vector
void fcout(vector<int>v)
{
    cout<<"\n fcout vector \n";
    for(unsigned int i=0;i<v.size();i++)cout<<v[i]<<" ";
    cout<<endl;
}
void fcout(int s)
{
    cout<<s<<" ";
}
template<typename T>
void fcout(T s)
{
    cout<<"Location:"<<s.x<<" "<<s.y<<"      ";
}
template<typename T>
void fcout(vector<T>v)
{
    cout<<"\n fcout vector \n";
    for(unsigned int i=0;i<v.size();i++)fcout(v[i]);
    cout<<endl;
}
#define OUT(x) cout<<#x<<"   ";fcout(x);

std::string Player::SerializeRegistration()
{
    Json r_json = {
        {"msg_type", "registration"},
        {"msg_data", {{"team_token", token.c_str()}}}
    };

    std::string ser_reg = r_json.dump();

    char buff[16] = { 0 };
    sprintf(buff, "%05d", (int)ser_reg.size());
    std::string rt(buff, 5);
    return rt + ser_reg;
}

std::string Player::SerializeActions()
{
    Json array_json = Json::array();
    for (auto& action : GetActions()) {
        array_json.push_back(action.GetActionMap());
    }

    Json a_json =  {
        {"msg_type", "action"},
        {"msg_data", {
            {"round", round.round},
            {"actions", array_json}}}
    };

    std::string ser_act = a_json.dump();

    char buff[16] = { 0 };
    sprintf(buff, "%05d", (int)ser_act.size());
    std::string rt(buff, 5);
    return rt + ser_act;
}

// 解析首次发送的全局信息
void Player::ParseContext(std::string& context_string)
{
    Json m_json = Json::parse(context_string);
    if (m_json["msg_type"] != "game_start") {
        std::cout << "receive invalid message type: " << m_json["msg_type"] << "vs game_start." << std::endl;
        return;
    }
    auto& c_json = m_json["msg_data"];
    ctx.timeout = c_json["action_timeout"];
    ctx.max_round = c_json["max_round"];
    ctx.robot_view_range = c_json["robot_view_range"];
    ctx.trailer_size = c_json["trailer_size"];
    ctx.map.height = c_json["map_height"];
    ctx.map.width = c_json["map_width"];
    ctx.warehouse.id = c_json["registry"]["id"];
    ctx.warehouse.location.x = c_json["registry"]["location"][0];
    ctx.warehouse.location.y = c_json["registry"]["location"][1];
    ctx.warehouse.size = c_json["registry"]["size"];

    for (auto& element : c_json["registry"]["ports"]) {
        Location loc {element[0], element[1]};
        ctx.warehouse.ports.push_back(loc);
    }

    for (auto& player : c_json["teams"]) {
        if (player["team_name"] == name) {
            ctx.id_range.min = player["object_id_range"][0];
            ctx.id_range.max = player["object_id_range"][1];
        }
    }

    Path::GetInstance().CreateMap(ctx.map.height, ctx.map.width);
    //update warehouse
    vector<struct Barrier> warehouse;
    struct Barrier barrier;
    for(int i = ctx.warehouse.location.x; i<ctx.warehouse.location.x + ctx.warehouse.size; i++) {
        for(int j = ctx.warehouse.location.y;j<ctx.warehouse.location.y + ctx.warehouse.size; j++) {
            barrier.movable = false;
            barrier.pos.x = i;
            barrier.pos.y = j;
            warehouse.push_back(barrier);
        }
    }
    Path::GetInstance().UpdateMap(warehouse);
}

// 解析每次发的消息
void Player::ParseInquire(std::string& inquire_string)
{
    Json m_json = Json::parse(inquire_string);
    if (m_json["msg_type"] == "game_over") {
        std::cout << "Server wants you home for dinner, shield number: ";
        for (auto & player : m_json["msg_data"]) {
            if (player["team_name"] == name) {
                std::cout << player["shield_num"] << std::endl;
                break;
            }
        }

        round.round = -1;
        return;
    }
    if (m_json["msg_type"] != "inquire") {
        std::cout << "receive invalid message type: " << m_json["msg_type"] << "vs inquire." << std::endl;
        return;
    }

    auto& i_json = m_json["msg_data"];

    round.round = i_json["round"];
    round.objects.clear();
    for (auto& element : i_json["objects"]) {
        Object oj;
        oj.type = element["type"];
        oj.id = element["id"];
        oj.location.x = element["location"][0];
        oj.location.y = element["location"][1];
        oj.number = 1;
        if (oj.type == SHIELD || oj.type == TRAILER) {
            oj.number = element["number"];
        }
        round.objects.push_back(oj);
    }
}

// 记录全局信息,只执行一次
void Player::fillCtx()
{
    //cout<<"fill start\n";
    for(int i = ctx.warehouse.location.x;i<ctx.warehouse.location.x+ctx.warehouse.size;i++){
        for(int j = ctx.warehouse.location.y;j<ctx.warehouse.location.y+ctx.warehouse.size;j++){
            smap[Lint(i,j)]=R1; // 记录我方基地所有格子
            knowRound[Lint(i,j)]=1;
        }
    }
    //outMap(smap);
    for(auto obj:round.objects){
        cout<<"player.ctx.id_range.max="<<ctx.id_range.max<<endl;
        if(obj.type==ROBOT && Mine(obj.id)){
            myRobotId.push_back(obj.id); // 记录我方所有机器人ID
        }
    }
    setPara();
}

void Player::setPara() // 设置参数
{
    para.searchSize = ctx.map.height/(myRobotId.size()+1);
    para.searchSize = max(para.searchSize, 2);
    para.searchSize = min(para.searchSize, 10);
    para.goHome = 0.8;
    para.splitSize = 10;
}

// 记录地图信息
void Player::fillMap()
{
    //update warehouse
    vector<struct Barrier> barriers;
    struct Barrier barrier;

    for(auto obj:round.objects) {
        barrier.pos = obj.location;
        barrier.movable = false;
        if ((obj.type == ROBOT) || (obj.type == TRAILER) || (obj.type == SHIELD)) {
            barrier.movable = true;
        }
        barriers.push_back(barrier);
    }
    Path::GetInstance().UpdateMap(barriers);

    dmap.clear();
    for (unsigned int i = 0; i < myRobotId.size(); i++) {
        Object trailer;
        trailer.id = myRobotId[i];
        trailer.number = 0;
        trailer.location.x = -1;
        trailer.location.y = -1;
        myT[trailer.id] = trailer;
    }
    // 记录 map<Location,int>smap dmap
    for(auto obj:round.objects){
        if(obj.type==REGISTRY){
            dmap[Lint(obj)] = RW;
            if(Mine(obj.id))continue;//第一次已经记录我方基地所有格子
            smap[Lint(obj)] = R2;
            /// 此处需要补充,根据局部格子和基地大小推测对方基地位置
            /// 只要探测到任何一个角落,就能推算出基地的整个位置
        }
        else if(obj.type==WALL){
            smap[Lint(obj)] = W;
            dmap[Lint(obj)] = RW;
        }
        else{
            smap[Lint(obj)] = NRNW;
            if(obj.type==SHIELD){
                dmap[Lint(obj)] = SH;
                shNum[Lint(obj)] = obj.number;
            }
            else if(obj.type==ROBOT){
                dmap[Lint(obj)]=Mine(obj.id)?H1:H2;
                if(Mine(obj.id))myH[obj.id]=obj; //记录所有车头
            }
            else if(obj.type==TRAILER){
                dmap[Lint(obj)]=Mine(obj.id)?T1:T2;
                if(Mine(obj.id))myT[obj.id]=obj; //记录所有车尾
            }
        }
    }
    fillEmpty();
}
void Player::fillEmpty(vector<Location> v)// 解析所有视野,保存空地
{
    for(auto vi:v){
        if(dmap[Lint(vi)] == UN)dmap[Lint(vi)]=EM, shNum[Lint(vi)] = 0;
        knowRound[Lint(vi)] = round.round+1;
    }
}
void Player::fillEmpty() // 解析所有视野,保存空地
{
    vector<int> cars = isOutOrJustOutCars(); // 车头出来了,车尾不一定的所有车子id
    for(int ci:cars){
        vector<Location> v = Lneig(myH[ci].location, ctx.robot_view_range);
        fillEmpty(v);
    }
    fillEmpty(ctx.warehouse.ports);
}
void Player::fillMapBak() // 保存历史dmap
{
    dmapBak.insert(dmapBak.begin(), dmap); // 可以优化,防止dmapBak过大
}

Action Player::Move(int id, Location e) // 计算路径,刷新地图,返回action
{
    Action action(MOVE, id, 0);
    action.currPos = myH[id].location;
    action.targetPos = e;
    action.trailePos = myT[id].location;
    Path::GetInstance().FindPath(action);
    Location head = myH[id].location, tail=myT[id].location;
    myT[id].location = action.nextPos, myT[id].location=head;
    dmap[Lint(action.nextPos)]=H1, dmap[Lint(head)]=T1, dmap[Lint(tail)]=EM;
    return action;
}
void Player::Pick(int id, int num)
{
    //
}

/// 打分
    // dmap 里面寻找目标
    // dmapBak 里面寻找目标
    // 探索地图
int Player::GetPoint(Location s)
{
    if(shNum[Lint(s)]){
        int point = 100 - (round.round+1-knowRound[Lint(s)])*5; / 需要调参
        point += (shNum[Lint(s)] / ctx.trailer_size + 1)*50; / 需要调参
        return max(point, 20);
    }
    if(knowRound[Lint(s)]==0){
        vector<Location> v =  Lneig(s, 2);
        for(auto vi:v){
            if(shNum[Lint(vi)])return 15; // 屏蔽器聚集预测
        }
        return 10;
    }
    return 0;
}

bool cmp(LP a,LP b)
{
    return a.point>b.point;
}
//移动
void Player::GetGoActions(vector<int> &cars, vector<Action> &actions)
{
    vector<LP> ans;
    for(int i=0;i<ctx.map.height;i++)for(int j=0;j<ctx.map.width;j++){
        int p = GetPoint(L(i,j));
        point[Lint(i,j)] = p;
        if(p >= 10)ans.push_back({i,j,p});
    }
    sort(ans.begin(),ans.end(),cmp);
    //OUT(ans);shNum[Lint(s)]=0
    int s = 0, carNum=cars.size();
    cout<<"GetTarget carNum1="<<carNum<<endl;
    //OUT(ans);
    for(int i=0;i<carNum && i<ans.size();i++){  // 去挖矿
        if(ans[i].point > 10)s++;
        else break;
        Location loc = {ans[i].x, ans[i].y};
        // res.push_back(loc);
        int fd = findNear(cars, i, loc);
        Action action = Move(cars[fd], loc); // 刷新地图
        actions.push_back(action);
        OUT(fd);
        if(fd > i){
            int tmp=cars[i];
            cars[i]=cars[fd],cars[fd]=tmp; // 调换2个车子的顺序
        }
        //OUT(loc);
    }
    cout<<"GetTarget carNum2="<<carNum-s<<endl; // 需要去探索地图的车子数量
    vector<Location> ansb;
    vector<Location> res;
    for(auto ai:ans)ansb.push_back({ai.x,ai.y});
    for(int i=s;i<carNum && i<ansb.size();i++){
        int fd = findNearButAway(ansb, s, myH[cars[i]].location, res, ctx.robot_view_range*2);
        Action action = Move(cars[i], ansb[fd]); // 刷新地图
        actions.push_back(action);
        res.push_back(ansb[fd]);
    }
}
// 回基地
void Player::GetGoHomeActions(vector<int> &cars, vector<Action> &actions)
{
    for(unsigned int i=0;i<cars.size();){
        cout<< "myT[cars[i]].number= "<<myT[cars[i]].number<<endl;
        if(myT[cars[i]].number > para.goHome * ctx.trailer_size){
            printf("id:%d go home\n", cars[i]);
            Action action = Move(cars[i], ctx.warehouse.location); /// 基地目标选择
            actions.push_back(action);
            cars.erase(cars.begin() + i);
        } else {
            i++;
        }
    }
}
//挖矿
void Player::GetPickActions(vector<int> &cars, vector<Action> &actions)
{
    for(unsigned int i=0;i<cars.size();){
        int c = canPick(myH[cars[i]].location);
        if (c) {
            Action action(PICK_UP, cars[i], d2d(L2d(cars[i]),c-1));
            actions.push_back(action);
            cars.erase(cars.begin()+i);
            cout<<"GetPickActions "<<cars[i]<<endl;
        }else i++;
    }
}

//完全没出来的车子
void Player::GetOutActions(vector<Action> &actions)
{
    for(unsigned int i=0;i<myRobotId.size();i++){
        if (outOrJustOut(myRobotId[i])) {
            continue;
        }
        for(int j=0;j<ctx.warehouse.ports.size();j++){
            if(dmap[Lint(ctx.warehouse.ports[j])]!=EM)continue;
            Action action(GO_OUT, myRobotId[i], j); 
            actions.push_back(action);
            dmap[Lint(ctx.warehouse.ports[j])] = H1;
            break;
        }
    }
}
vector<Action> Player::GetActions(int timeout)
{
    cout<<"------------GetActions----------\n";
    std::vector<Action> actions;
    vector<int> cars = isOutOrJustOutCars(); // 已经出库的所有车子id
    cout<<"cars.size1= "<<cars.size()<<endl;
    GetGoHomeActions(cars, actions);
    GetPickActions(cars, actions);
    cout<<"cars.size2= "<<cars.size()<<endl;
    GetGoActions(cars, actions);
    GetOutActions(actions);
    cout<<"------------GetActions----end------\n";
    return actions;
}
vector<Action> Player::GetActions()
{
    static int flag = 1;
    if(flag)fillCtx();
    flag=0;
    fillMap();
    vector<Action> ans = GetActions(ctx.timeout);
    //Path::GetInstance().FindPath(ans);
    return ans;
}
}

cal.cpp

#include "cal.h"
#include <iostream>
using namespace std;


int dx[]={-1,0,1,0}; //上右下左
int dy[]={0,1,0,-1}; //上右下左
Robot::Player& player = Robot::PlayerSingleton::GetInstance();

//输出一维vector
template<typename T>
void fcout(vector<T>&v)
{
    cout<<"\n fcout \n";
    for(int i=0;i<v.size();i++)cout<<v[i]<<" ";
    cout<<endl;
}
void outMap(map<int,int>m) //打印整个map
{
    cout<<"map---------start\n";
    for(int i=0;i<player.ctx.map.height;i++){
        for(int j=0;j<player.ctx.map.width;j++)cout<<m[Lint(i,j)]<<' ';
        cout<<endl;
    }
    cout<<"map---------end\n";
}
void outMapWithSe(map<int,int>m,Location s,Location e) //打印整个map
{
    cout<<"map---------start\n";
    for(int i=0;i<player.ctx.map.height;i++){
        for(int j=0;j<player.ctx.map.width;j++){
            if(Lsame(s,{i,j}))cout<<"s ";
            else if(Lsame(e,{i,j}))cout<<"e ";
            else cout<<m[Lint(i,j)]<<' ';
        }
        cout<<endl;
    }
    cout<<"map---------end\n";
}

Location L(int i,int j)//坐标变成位置Location
{
    Location ans={i,j};
    return ans;
}
Location L(int id)//整数变成位置Location
{
    Location ans={id/player.ctx.map.width,id%player.ctx.map.width};
    return ans;
}

bool Lin(Location s)//在矩形内
{
    
    return s.x>=0 && s.x<player.ctx.map.height && s.y>=0 && s.y<player.ctx.map.width;
}
int Lint(Location s)//位置Location变成整数,-1表示矩形外
{
    if(Lin(s))return s.x*player.ctx.map.width+s.y;
    return -1;
}
int Lint(Object obj)//obj的位置变成整数
{
    return Lint(obj.location);
}
int Lint(int i,int j)//坐标变成整数,-1表示矩形外
{
    return Lint(L(i,j));
}

bool Lcmp(Location l1,Location l2)//按照位置排序
{
    if(l1.x==l2.x)return l1.y<l2.y;
    return l1.x<l2.x;
}
int Ldis(Location s,Location e)//曼哈顿距离
{
    int x=s.x-e.x,y=s.y-e.y;
    x=x>0?x:-x, y=y>0?y:-y;
    return x+y;
}
bool Lsame(Location s,Location e)//相同位置
{
    return Ldis(s,e) == 0;
}
bool LisNei(Location s,Location e)//相邻位置
{
    return Ldis(s,e)==1;
}

int getLen(Location s,Location e) // 两点之间的路线距离
{
    return Ldis(s,e); /// 改成最短路长度
}
int getLen(Location s, int eid) // 两点之间的路线距离
{
    return Ldis(s,L(eid)); /// 改成最短路长度
}
bool Lerror(Location s)
{
    return Ldis(s,{-1,-1}) == 0;
}
int findNear(vector<Location>v, int startId, Location s) // 寻找最近的点
{
    int len = 123456789,ans=startId;
    for(unsigned int i=startId;i<v.size();i++){
        int d = getLen(s, v[i]);
        if(len>d)len=d,ans=i;
    }
    return ans;
}
int findNear(vector<int>v, int startId, Location s) // 寻找最近的点
{
    int len = 123456789,ans=startId;
    for(unsigned int i=startId;i<v.size();i++){
        int d = getLen(s, v[i]);
        if(len>d)len=d,ans=i;
    }
    return ans;
}
// 寻找离ne最近的点,但是要远离aw至少awLen
int findNearButAway(vector<Location>v, int startId, Location ne, vector<Location>aw, int awLen) 
{
    int len = 123456789,ans=startId;
    for(unsigned int i=startId;i<v.size();i++){
        for(auto awi:aw)if(getLen(awi, v[i]) <= awLen)continue;
        int d = getLen(ne, v[i]);
        if(len>d)len=d,ans=i;
    }
    return ans;
}

Location Lnei(Location s,int dir)//上右下左的邻居
{
    return {s.x+dx[dir],s.y+dy[dir]};
}
//获取所有的邻居,保证输出的位置都在地图范围内
vector<Location> neig(Location s)
{
    vector<Location>ans;
    for(int i=0;i<4;i++){
        Location e = Lnei(s,i);
        if(Lin(e))ans.push_back(e);
    }
    return ans;
}
//获取所有距离不超过len的位置
vector<Location> Lneig(Location s, int len)
{
    vector<Location>ans;
    for(int i=s.x-len;i<=s.x+len;i++){
        for(int j=s.y-len;j<=s.y+len;j++){
            if(Ldis(s,{i,j})<=len && Lin({i,j}))ans.push_back({i,j});
        }
    }
    return ans;
}
int findH(Location head)
{
    for(auto hi:player.myH){
        if(Lsame(hi.second.location, head))return hi.first;
    }
    return 0;
}
int L2d(Location head,Location tail)//head相对于tail的方向,上右下左
{
    for(int i=0;i<4;i++){
        if(Lsame(Lnei(tail,i),head))return i;
    }
    return -1;
}
int L2d(int id)//id对应的车子的head相对于tail的方向,上右下左
{
    if(Lsame(player.myT[id].location, {-1,-1})){
        if(player.myH[id].location.x < player.ctx.warehouse.location.x) return 0;
        if(player.myH[id].location.x >= player.ctx.warehouse.location.x + player.ctx.warehouse.size) return 2;
        if(player.myH[id].location.y < player.ctx.warehouse.location.y) return 3;
        if(player.myH[id].location.y >= player.ctx.warehouse.location.y + player.ctx.warehouse.size) return 1;
    }
    return L2d(player.myH[id].location, player.myT[id].location);
}
int L2d(Location head)//head相对于tail的方向
{
    int id = findH(head);
    //cout<<"find id="<<id<<endl;
    return L2d(id);
}
int d2d(int d1,int d2)//方向d1到方向d2之间的移动方向,前右后左
{
    if(d1==-1||d2==-1)return -1;
    return (d2+4-d1)%4;
}

bool Mine(int id) //id属于我方
{
    return id>=player.ctx.id_range.min && id<player.ctx.id_range.max;
}

bool isOut(int id) // 车子是否已经完全出库
{
    return !Lsame(player.myT[id].location, {-1,-1});
}
bool isJustOut(int id) // 车头出来了,车尾没出来
{
    return player.myH[id].location.x>=0 && Lsame(player.myT[id].location, {-1,-1});
}
bool outOrJustOut(int id) // 车头出来了,车尾不一定
{
    return player.myH[id].location.x >= 0;
}
typedef bool(*func)(int);
int getCarNum(func f)
{
    int ans=0;
    for(unsigned int i=0;i<player.myRobotId.size();i++){
        if(f(player.myRobotId[i]))ans++;
    }
    return ans;
}
vector<int> getCars(func f) 
{
    vector<int> ans;
    for(unsigned int i=0;i<player.myRobotId.size();i++){
        if(f(player.myRobotId[i])){
            ans.push_back(player.myRobotId[i]);
        }
    }
    return ans;
}
int isOutNum() // 已经出库的车子数量
{
    return getCarNum(isOut);
}
vector<int> isOutCars() // 已经出库的所有车子id
{
    return getCars(isOut);
}
int isJustOutNum() // 车头出来了,车尾没出来的车子数量
{
    return getCarNum(isJustOut);
}
vector<int> isJustOutCars() // 车头出来了,车尾没出来的所有车子id
{
    return getCars(isJustOut);
}
vector<int> isOutOrJustOutCars() // 车头出来了,车尾不一定的所有车子id
{
    return getCars(outOrJustOut);
}
int nearSH(Location s) //是否挨着屏蔽器SH, 上右下左1234, 没有就是0
{
    for(int i=0;i<4;i++){
        Location e = Lnei(s,i);
        if(Lin(e) && player.dmap[Lint(e)]==SH)return i+1;
    }
    return 0;
}

int canPick(Location s) //能否采矿
{
    int ans = nearSH(s);
    if(ans)return ans;
    / 采自己车里的或者对方车里的矿
    return 0;
}

int sizePoint(int size) // 0-para.searchSize分,zise越大分数越低,表面需要返回基地
{
    int alls = player.ctx.trailer_size;
    return player.para.searchSize-size*player.para.searchSize/alls;
}
int getSplitNum() //计算分区总数
{
    int size = player.para.splitSize;
    return ((player.ctx.map.height-1)/size + 1) * ((player.ctx.map.width-1)/size + 1);
}
vector<vector<int>> split() //整个地图分成若干个size*size的区域
{
    static vector<vector<int>>ans;
    if(ans.empty()){
        int size = player.para.splitSize;
        int col = (player.ctx.map.width-1)/size +1;
        ans.resize(getSplitNum());
        for(int i=0;i<player.ctx.map.height;i++){
            for(int j=0;j<player.ctx.map.width;j++){
                ans[i/size*col+j/size].push_back(Lint(i,j));
            }
        }
    }
    return ans;
}
int getSplitId(Location s) //获取某个位置所在分区id
{
    int size = player.para.splitSize;
    int col = (player.ctx.map.width-1)/size +1;
    return s.x/size *col + s.y/size;
}
int getSplitId(int id) //获取某个id的车子所在分区id
{
    Location lo = player.myH[id].location;
    return getSplitId(lo);
}
vector<int> getSplitUnknowArea(int id) //获取某个id的分区的所有UN位置
{
    static vector<vector<int>>ans;
    if(ans.empty()){
        ans = split();
    }
    if(id>=ans.size())return ans[0];
    for(int i=0;i<ans[id].size();){
        if(player.knowRound[ans[id][i]])ans[id].erase(ans[id].begin()+i);
        else i++;
    }
    return ans[id];
}
int getUnAreaNum() //获取含有未知格子的分区数目
{
    int d = getSplitNum();
    int ans=0;
    for(int i=0;i<d;i++)if(!getSplitUnknowArea(i).empty())ans++;
    return ans;
}

在这个版本之后,本来还写了一些策略的,还有很多策略没写,还有很多策略没想好,可惜通通没有调好。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值