这是一个双方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;
}
在这个版本之后,本来还写了一些策略的,还有很多策略没写,还有很多策略没想好,可惜通通没有调好。