标签:
/*
* 坦克大战(TankCraft) AI程序
* 颜世光
* 2010.05.21
*/
#define _CRT_SECURE_NO_DEPRECATE
#include "Tank.h"
#include <string.h>
//请勿修改以上头文件
#include <iostream>
#include <algorithm>
#include <limits>
#include <queue>
#include <map>
#include <set>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <cassert>
#include <fstream>
using namespace std;
ofstream fout("./amai.log");
// 判断坐标是否合法
#define in_range(nx,ny) (nx>=0 && nx<=22 && ny>=0 && ny <=22)
#define valid(nx,ny) (nx > 0 && nx <22 && ny>0 && ny<22 && smap[nx][ny].type !=STONE)
// 翻转坐标
#define RV(x) (22-(x))
// 浮点差值
#define eps (numeric_limits<double>::epsilon())
// 上一轮的命令
struct LSO
{
LSO(){type = STOP;target = -1;conf = 0;}
OrderType type; // 行为
int target; // 目标坦克
int x,y; // 目标点
int conf; // 自信
};
struct point
{
int x,y;
point(int xx,int yy):x(xx),y(yy) {}
point():x(-2),y(-2) {}
bool operator<(const point& ot) const
{
return x<ot.x; // 仅仅是为了能用set
}
};
// pos
struct pos
{
int x;
int y;
double p; // 处在此位置的可能性
double stop_p; // 这些可能性中来自stop的部分
double fork[5]; // 向4个方向的贡献
pos():x(-1),y(-1),p(0.0),stop_p(0.0)
{
for(int i=0;i<5;i++)
fork[i] = 0.0;
}
pos(int xx,int yy,double pp=1.0) :x(xx),y(yy),p(pp),stop_p(0.0)
{
for(int i=0;i<5;i++)
fork[i] = 0.0;
}
// 相等被定义为位置一样
bool operator==(const pos& ot) const
{
return (x==ot.x && y==ot.y);
}
bool operator!=(const pos& ot) const
{
return !(*this==ot);
}
bool operator>(const pos& ot) const
{
if(p > ot.p + eps)
return true;
else if( p + eps <ot.p)
return false;
if(x > ot.x)
return true;
else if(x <ot.x)
return false;
return y > ot.y;
}
bool operator<(const pos& ot) const
{
if(p + eps < ot.p)
return true;
else if( p > ot.p + eps)
return false;
if(x < ot.x)
return true;
else if(x>ot.x)
return false;
return y < ot.y;
}
};
// *-------------------常量----------------------*
const int d0x[1] = {0};
const int d0y[1] = {0};
const int ddx[5] = {-1,0,1,0,0};
const int ddy[5] = {0,-1,0,1,0};
const int d2x[8] = {-2,-1,0,1,2,1,0,-1}; // 2格
const int d2y[8] = {0,1,2,1,0,-1,-2,-1};
const int d3x[12]= {-3,-2,-1,0,1,2,3,2,1,0,-1,-2}; // 3格
const int d3y[12]= {0,1,2,3,2,1,0,-1,-2,-3,-2,-1}; //
const int d4x[16]= {-4,-3,-2,-1,0,1,2,3,4,3,2,1,0,-1,-2,-3};
const int d4y[16]= {0,1,2,3,4,3,2,1,0,-1,-2,-3,-4,-3,-2,-1};
const int d5x[20]= {-5,-4,-3,-2,-1,0,1,2,3,4,5,4,3,2,1,0,-1,-2,-3,-4};
const int d5y[20]= {0,1,2,3,4,5,4,3,2,1,0,-1,-2,-3,-4,-5,-4,-3,-2,-1};
const int *xdx[] = {d0x,ddx,d2x,d3x,d4x,d5x};
const int *xdy[] = {d0y,ddy,d2y,d3y,d4y,d5y};
const int ddn[] = {1,4,8,12,16,20};
const int MX_STOP = 4; // 允许我方坦克最多stop次数
const int O_STOP = 5; // 敌方stop多少次后判定为故意
// *------------------全局变量-------------------*
DataForAI sdata; // 翻转后的data参数
int mask[23][23]; // 我方迷雾 非0为不可视, 0为可视
int dmask[23][23]; // 敌方迷雾
Point* src; // 矿点
TankData *stank; // 原始坦克数组
TankData tank[11]; // 坦克数组
int vtank[10]; // 坦克位置可确定
Order orders[10]; // 当前回合的所有指令
MapCell lsmap[23][23]; // 上一轮地图
MapCell (*smap)[23]; // 传入地图
int src_num; // 矿点数量
int nround; // 当前回合
LSO last_orders[10]; // 上回合指令
int tank_w[10][23][23]; // 坦克到各个点的距离
int src_w[2][13][23][23]; // 矿到各点的距离
int esc_w[11][23][23]; // 逃跑用距离 10为出生点的...
int esc_v[11]; // 距离有效
TankData dtank[10]; // 敌方坦克数组,用于预测敌方坦克行动
pos e_next[10]; // 敌方下一步要走的(如果不攻击的话)
int wt_map[4][23][23]; // 路径权值
int m_src; // 己矿个数
int e_src; // 敌矿个数
int m_gold;
int e_gold;
Order norder; // STOP
int willfire[10]; // 愿意开火
int willstop[10]; // 当前轮准备stop
int sn_stop[10]; // stop轮数
int e_willstop[10]; // 断定敌方本轮stop
int e_target[10]; // 敌方本轮目标
int stop_for[10]; // 为某个sn停止的轮数
// *------------------全息变量-------------------*
pos tankpt[405][10]; // 坐标
vector<pos> allpt[405][10]; // 所有坐标
TankData ldtank[10]; // 当前轮坦克信息(包含预测的敌方位置)
// *------------------策略变量-------------------*
bool st_track = false; // st是否追逐
bool pn_track = true; // p是否追逐
int e_forecast; // 对方预测指数
int e_stop; // 对方stop指数
int e_farbreak; // 远距离开路
int dir_p[4][4]; // 4向优先级对比矩阵
int e_sniper,e_pioneer,e_striker; // 敌方坦克个数
// *------------------临时变量-------------------*
int tmp_mx[23][23];
// *------------------前向声明-------------------*
void init_data(DataForAI& data); // 初始化本轮数据
void flood(int id); // 搜索坦克与矿的距离
Order step_to(int id,int dx,int dy); // 单步移动
Order attack(int sid,int did); // 攻击
void analyse(); // 分析 决策
bool fire(); // 寻找目标开火
Order move_to(int id,int dx,int dy); // 向某点移动
Order sniper_escape(int id); // sniper躲避
void sniper_ai(int id); // sniper行动ai
void sniper_stop(); // sniper是否要停下一轮
void pioneer_ai(int id); // pioneer行动ai
int tank_dis(int id,int did,TankData* _tank = tank);
void recalc_p(vector<pos>& vpt); // 重新计算概率
void calc_w(); // 计算路径权值
void calc_w_for_run(void); // 闪避路径权值
void calc_w_for_move(); //
void flood_from(int sx,int sy,int vm[][23],int at);
Order rv_order(Order order); // 翻转命令
void rv_data(DataForAI& data); // 翻转数据
Order suicide(int id); // 自杀
Order dance(DataForAI& data); // 跳舞
// *-------------------入口函数-------------------*
//平台0回合时调用此函数获取AI名称及坦克类型信息,请勿修改此函数声明。
extern "C" InitiateInfo chooseType()
{
InitiateInfo Info;
Info.tank[0] = Sniper;
Info.tank[1] = Sniper;
Info.tank[2] = Sniper;
Info.tank[3] = Sniper;
Info.tank[4] = Sniper;
strcpy(Info.aiName,"AMAI"); //AI名请勿使用中文
// nround = 0;
nround = 0;
// 空指令
norder.type = STOP;
// sn的连续埋伏次数
for(int i=0;i<10;i++)
sn_stop[i] = 0;
// 远距离打墙
e_farbreak = 0;
// tank位置
for(int i=0;i<10;i++)
tankpt[0][i] = pos(-2,-2);
// 这个没必要么?
for(int i=0;i<400;i++)
for(int d=0;d<10;d++)
allpt[i][d].clear();
return Info;
}
//平台从第1回合开始调用此函数获得每回合指令,请勿修改此函数声明。
extern "C" Order makeOrder(DataForAI data)
{
// 计时开始
int start = clock();
// 数据预处理,现在我们永远是红方
rv_data(data);
// 当前坦克id
int nid = sdata.myID;
// 如果不是新的一轮,返回决策
if(sdata.round == nround)
return orders[nid];
// 新的一轮
nround = sdata.round;
// fout<<"--------------------------------Round: "<<nround<<"----------------------------------"<<endl;
// 更新全局变量
init_data(sdata);
// 决策
analyse();
// 保存结果地图
memcpy(lsmap,smap,sizeof(lsmap));
// 打印敌方参数
// fout<<"敌方参数:e_forecast-"<<e_forecast<<" e_stop-"<<e_stop<<endl;
// 处理指令
for(int i=0;i<10;i++)
if(data.myFlag == BLUE)
orders[i] = rv_order(orders[i]);
// 输出处理时间
int usetime = clock() - start;
// fout<<"Time: "<<usetime<<endl;
if(usetime > 100)
fout<<"Round "<<nround<<"用时:"<<usetime<<"毫秒"<<endl;
return orders[nid];
}
// *-------------------------------自定义函数---------------------------------*
// 向x,y点开火,不处理伤害
Order fire_at(int x,int y)
{
Order order;
order.type = FIRE;
order.row = x;
order.col = y;
return order;
}
// 计算我方视野
void our_shadow()
{
// 没有视野的地方是 -1 而不是 1
memset(mask,-1,sizeof(mask));
// 矿点视野
for(int si=0;si<src_num;si++)
{
int sx = src[si].row;
int sy = src[si].col;
for(int i=-2;i<=2;i++)
for(int j=-2;j<=2;j++)
if( abs(i) + abs(j) <=2 && valid(sx+i,sy+j)) // 所有矿点视野
mask[sx+i][sy+j] = 0;
}
// tank视野
for(int id=0 ;id<5; id++)
{
if(stank[id].row < 0)
continue;
int sx = stank[id].row;
int sy = stank[id].col;
// 4格视野
for(int i= -4;i<=4; i++)
{
int bd = 4-abs(i);
for(int j= -bd; j<=bd;j++)
if(in_range(sx+i,sy+j))
mask[sx+i][sy+j] = 0;
}
}
}
// 第一轮, 初始化一些与战术有关的变量
void first_round()
{
for(int id=5; id<10;id++)
switch(stank[id].type)
{
case Striker:
e_striker ++;
break;
case Pioneer:
e_pioneer ++;
break;
case Sniper:
e_sniper ++;
break;
default:
break;
}
// 初始化敌方预测指数
e_forecast = e_sniper * 4;
e_stop = e_sniper;
tank[10].row = stank[4].StartRow;
tank[10].col = stank[4].StartCol;
}
// 交换两个坦克的历史数据
void swap_tankpt(int si,int di,int nr)
{
assert(nr > 0);
if(nr<0)
return;
bool s_end = false;
bool d_end = false;
while(nr && (!s_end || !d_end))
{
if(tankpt[nr][si].p + eps > 1.0)
s_end = true;
if(tankpt[nr][di].p + eps > 1.0)
d_end = true;
swap(tankpt[nr][si],tankpt[nr][di]);
swap(allpt[nr][si],allpt[nr][si]);
nr --;
}
}
// 否定当前轮的一个点
//
void negate_point(int id,int dx,int dy)
{
vector<pos>& vpt = allpt[nround][id];
for(vector<pos>::iterator it=vpt.begin();it!=vpt.end();++it)
{
if(it->x == dx && it->y == dy)
{
it->p = 0.0;
it->stop_p = 0.0;
}
}
vector<pos>& lvpt = allpt[nround-1][id];
for(vector<pos>::iterator it=lvpt.begin();it!=lvpt.end();++it)
{
int x = it->x;
int y = it->y;
for(int i=0;i<5;i++)
{
int nx = x + ddx[i];
int ny = y + ddy[i];
if(nx == dx && ny ==dy)
{
it->fork[i] = 0.0;
}
// 这里是否需要修正it->p呢?
}
}
recalc_p(vpt);
// recalc_p(lvpt) 需要么?
}
// 否定一个本轮在视野中的所有坐标,修正allpt
void negate_points(int id)
{
int nr = nround;
// 上一轮
vector<pos>& lvpt = allpt[nr-1][id];
// 本轮
vector<pos>& vpt = allpt[nr][id];
// 查找上轮的每个点,看其分支是否在视野中
for(vector<pos>::iterator it = lvpt.begin();it!=lvpt.end();++it)
{
double ap = 0.0; // ap是正常概率,也是重分配的基础
double tp_insight = 0.0; // 因为视野中而要转移的概率
double tp_brick = 0.0; // 一位不可通过而要转移的概率
// 对上轮节点进行分支,计算要转移的概率
for(int i=0;i<5;i++)
{
int nx = it->x + ddx[i];
int ny = it->y + ddy[i];
if(!valid(nx,ny))
continue;
// 砖
if(smap[nx][ny].type != PERVIOUS)
{
tp_brick += it->fork[i];
it->fork[i] = 0.0;
}
// 在视野中
else if(mask[nx][ny] == 0)
{
tp_insight += it->fork[i]; // 因视野转移
it->fork[i] = 0.0;
}
// 不在视野中
else
ap += it->fork[i];
}
double tp;
bool may_stop = false;
if(mask[it->x][it->y] &&
((e_sniper < 3 && e_stop > O_STOP) || stank[id].range == 5)) // sniper为主,假设只有sn会stop
{
for(int i=0;i<5;i++)
{
if(dtank[i].life <= 0)
continue;
// 上轮与我方坦克的距离
int d = abs(dtank[i].row - it->x) + abs(dtank[i].col - it->y);
// 为6时可能stop
if(d==6)
{
may_stop = true;
break;
}
}
}
// 如果对方不故意stop, 两部分都按比例转移
if(!may_stop)
tp = tp_insight + tp_brick;
else // 否则只转移是砖的那一部分
tp = tp_brick;
// 按比例转移
if(ap < eps)
tp = 0;
else
tp = tp / ap;
for(int i=0;i<5;i++)
{
int nx = it->x + ddx[i];
int ny = it->y + ddy[i];
if(!valid(nx,ny))
continue;
// 可以得到的概率
double nap = tp * it->fork[i];
if(nap < eps) // 本身可能就是被否定的点
continue;
for(vector<pos>::iterator cit=vpt.begin();cit!=vpt.end();++cit)
{
if(cit->x == nx && cit->y == ny)
{
// 可以存在
if(mask[nx][ny] && smap[nx][ny].type == PERVIOUS)
{
it->fork[i] += nap;
cit->p += nap;
if(i==5)
cit->stop_p += nap;
}
// 在视野中
else
{
it->fork[i] = 0;
cit->p = 0.0;
cit->stop_p = 0.0;
}
break;
}
}
}
// e_stop >= O_STOP
// 向stop转移
if(may_stop && tp_insight > eps)
{
for(vector<pos>::iterator cit=vpt.begin();cit!=vpt.end();++cit)
{
if(cit->x == it->x && cit->y == it->y)
{
cit->p += tp_insight;
cit->stop_p += tp_insight;
break;
}
}
}
}
// 在e_stop >= O_STOP时,并没有完全清零这些
for(vector<pos>::iterator cit=vpt.begin();cit!=vpt.end();++cit)
{
if(mask[cit->x][cit->y] == 0 || smap[cit->x][cit->y].type != PERVIOUS) // 视野中
{
cit->p = 0;
cit->stop_p = 0;
}
}
recalc_p(vpt);
}
// 开火没有打中, 否定一个上轮的坐标,修正allpt
void negate_last_point(int id,int dx,int dy)
{
int nr = nround - 1;
vector<pos>& lvpt = allpt[nr-1][id];
vector<pos>& vpt = allpt[nr][id];
vector<pos>& nvpt = allpt[nr+1][id];
// 推断对方没有在这点,是否是因为stop导致的
double dp=-1.0;
double all_stop = 0;
double all_p = 0;
for(vector<pos>::iterator it = vpt.begin();it!=vpt.end();++it)
{
if(it->x==dx && it->y == dy)
{
if(it->p > 0)
{
dp = it->stop_p / it->p;
}
else
{
assert(0);
}
}
else
{
all_stop += it->stop_p;
all_p += it->p;
}
}
if(dp + eps > 0 && all_p > eps)
{
if(dp < 0.2 && all_stop/all_p > 0.5)
{
// fout<<"根据上轮开火未命中,推断对方stop"<<endl;
e_stop ++;
}
}
// 遍历上轮节点, 取消否定节点 给 子节点的概率
for(vector<pos>::iterator it=vpt.begin();it!=vpt.end();++it)
{
if(it->x != dx || it->y != dy)
continue;
// 取消所有带给子节点的概率
for(int i=0;i<5;i++)
{
int nx = dx + ddx[i];
int ny = dy + ddy[i];
if(!valid(nx,ny) || smap[nx][ny].type != PERVIOUS)
continue;
for(vector<pos>::iterator cit=nvpt.begin();cit!=nvpt.end();++cit)
{
if(cit->x == nx && cit->y == ny)
{
cit->p -= it->fork[i];
if(i==4)
cit->stop_p = 0.0; // 这个没有办法衰减
assert(cit->p + eps > 0);
if(cit->stop_p < 0)
cit->stop_p = 0.0;
if(cit->p < 0.0)
cit->p =0.0;
break;
}
}
}
// 清零这点概率
it->p = 0;
it->stop_p = 0;
}
// 如果敌方故意stop
if(e_stop >= O_STOP)
{
// 遍历上上轮的所有节点
for(vector<pos>::iterator it = lvpt.begin();it!=lvpt.end();++it)
{
// 查找所有分支节点
for(int i=0;i<4;i++) // 0-4
{
int nx = it->x+ddx[i];
int ny = it->y+ddy[i];
if(!valid(nx,ny) || smap[nx][ny].type != PERVIOUS)
continue;
// 分支节点为 否定节点
if(nx == dx && ny == dy) //
{
// 转移这个否定节点概率的%80到 父节点
double tp = it->fork[i] * 0.8;
it->fork[4] += tp;
// 假设这些概率都是在父节点stop
for(vector<pos>::iterator cit = vpt.begin();cit!=vpt.end();++cit)
{
// 找到父节点stop的分支(位置和父节点相同,是否定节点的兄弟节点), 修正它的概率
if(cit->x == it->x && cit->y == it->y)
{
double ap = tp / cit->p;
// 兄弟节点 将得到的概率把向下分发
for(int j =0;j<5;j++)
{
int nnx = it->x + ddx[j];
int nny = it->y + ddy[j];
if(!valid(nnx,nny) || smap[nnx][nny].type != PERVIOUS)
continue;
// 查找其子节点, 增加概率
for(vector<pos>::iterator nit = nvpt.begin();nit!=nvpt.end();++nit)
if(nit->x == nnx && nit->y == nny)
{
nit->p += cit->fork[j] * ap;
break;
}
}
cit->p += tp;
cit->stop_p += tp;
break;
}
}
it->fork[i] = 0.0; // 否定这个分支
}
}
// i < 5 时, 概率被转移到stop
// i = 5 时, 也应该转移概率
// 但i = 5时 应该转移的是 stop -> 其他
if(it->x == dx && it->x == dy)
{
double tp = it->fork[4] / it->p;
for(int j=0;j<4;j++)
{
for(vector<pos>::iterator cit = vpt.begin();cit!=vpt.end();++cit)
{
if(cit->x == dx+ddx[j] && cit->y == dx+ddy[j])
{
// 这个分支可以向下传递的部分
double ntp = tp * it->fork[j];
for(int t =0;t<5;t++)
{
double ap = ntp / cit->p;
int nnx = cit->x + ddx[t];
int nny = cit->y + ddy[t];
// 查找其子节点, 增加概率
for(vector<pos>::iterator nit = nvpt.begin();nit!=nvpt.end();++nit)
if(nit->x == nnx && nit->y == nny)
{
nit->p += cit->fork[t] * ap;
break;
}
}
break;
}
}
}
}
// 感觉把i=5写这么复杂就是个悲剧...
}
}
// 从新计算概率
recalc_p(vpt);
recalc_p(nvpt);
}
// 删除一个坐标,仅仅是删除当前轮
void delete_point_p(int nr,int id,int dx,int dy)
{
bool needrc = false;
vector<pos>& vpt = allpt[nr][id];
for(vector<pos>::iterator it=vpt.begin();it!=vpt.end();++it)
{
if(it->x == dx && it->y == dy)
{
it->p = 0.0;
it->stop_p = 0.0;
needrc = true;
break;
}
}
if(needrc)
recalc_p(vpt);
}
// 提高一个当前轮坐标概率到p
// 由于没有修正之前的值,所以可能会出问题...
void verify_point_p(int id,int dx,int dy,double p)
{
int nr = nround;
pos newpt(dx,dy,p);
vector<pos>& vpt = allpt[nr][id];
double lf = 1.0 - p;
for(vector<pos>::iterator it=vpt.begin();it!=vpt.end();++it)
{
if(it->x == dx && it->y == dy)
{
double oldp = it->p;
it->p = oldp * lf + p;
if(oldp > eps) // 扩大相同的倍数
it->stop_p *= it->p/oldp;
}
else
{
it->p *= lf;
it->stop_p *= lf;
}
}
}
// 核实当前轮一个新坐标
void verify_point(int id,int dx,int dy)
{
int nr = nround;
pos newpt(dx,dy);
vector<pos>& vpt = allpt[nr][id];
for(vector<pos>::iterator it=vpt.begin();it!=vpt.end();++it)
{
if(it->x == dx && it->y == dy) // 找到这点
{
// fout<<"verify_point,Tank"<<id<<" p="<<it->p<<",stop_p="<<it->stop_p<<endl;
if(it->p > 0.0 && it->stop_p/it->p > 0.5) // 这一点有50%以上可能是stop导致的
{
// fout<<"怀疑敌方故意stop,e_stop++"<<endl;
e_stop ++;
}
}
}
tankpt[nr][id] = newpt;
allpt[nr][id].clear();
allpt[nr][id].push_back(newpt);
}
// 开火打中, 确认上一轮的某点,
// 没有修改上上一轮的信息
void verify_last_point(int id,int dx,int dy)
{
int nr = nround - 1;
vector<pos>& lvpt = allpt[nr][id];
vector<pos>& vpt = allpt[nr+1][id];
for(vector<pos>::iterator it=lvpt.begin();it!=lvpt.end();++it)
{
// 错误的上轮坐标
if(it->x == dx && it->y == dy)
continue;
for(int i=0;i<5;i++)
{
int nx = it->x + ddx[i];
int ny = it->y + ddy[i];
double p = it->fork[i];
for(vector<pos>::iterator cit=vpt.begin();cit!=vpt.end();++cit)
{
if(cit->x == nx && cit->y == ny)
{
cit->p -= p;
cit->stop_p = 0;
if(cit->p < 0)
cit->p = 0;
break;
}
}
it->fork[i] = 0;
}
it->p = 0;
it->stop_p = 0;
}
recalc_p(lvpt);
recalc_p(vpt);
}
// 坐标按概率排序
void sort_points(vector<pos>& vpt)
{
sort(vpt.begin(),vpt.end(),greater<pos>());
}
// 保持现状是否能赢
bool can_win()
{
int m_lf = 1000 - m_gold;
int e_lf = 1000 - e_gold;
// 这个不是绝对的
if(e_src < 1)
return true;
if(m_src < 1)
return false;
int m_lr = (m_lf + m_src - 1) / m_src;
int e_lr = (e_lf + e_src - 1) / e_src;
return m_lr < e_lr;
}
bool can_wait()
{
if (e_src + 2 <= m_src) // 我方多两个矿
return true;
if (m_src + 1 >= e_src && e_gold < m_gold + 5) // 仅少一个矿,且比分不落后
return true;
if (can_win() && m_src + 2 >= e_src) // 少2个矿, 且比分领先
return true;
return false;
}
// 对于向野外乱开炮的,寻找受伤者
void find_injured(int id)
{
int dx = last_orders[id].x;
int dy = last_orders[id].y;
int did = - last_orders[id].target;
if(tank[did].life == stank[did].life) // 打中了
{
;
}
}
// 对方上轮的指令进行反馈处理
// 本函数的所有 tank[id] 数据都是上轮的计算结果
void feedback()
{
int badpos[10] = {0}; // 坐标错误的tank
int t_back[10] = {0}; // 需要回退的tank?
// 强制某个敌方stop
memset(e_willstop,0,sizeof(e_willstop));
// 先扫描乱打的命令
for(int id=0; id<5; id++)
{
if(last_orders[id].type != FIRE || last_orders[id].conf != 0)
continue;
int did = last_orders[id].target;
if(did < 0)
{
did = -did;
if(stank[did].life == tank[did].life)
{
// // fout<<"Round"<<nround<<" 意外开火打中Tank"<<did;
}
else if(stank[did].life == tank[did].life + 1)
{
bool fd = false;
for(int i=0;i<5;i++)
{
if(last_orders[i].target == did)
{
last_orders[i].type = STOP;
fd = true;
}
}
if(!fd)
{
// 这是最正常的情况
}
else
{
// 干扰了其他坦克
// // fout<<"Round"<<nround<<" Tank:"<<id<<"乱打,干扰了其他坦克"<<endl;
}
}
}
}
// 对我方上次的命令进行确认
for(int id=0; id<5; id++)
{
// 不是向视野外开火
if(last_orders[id].type != FIRE || last_orders[id].conf != 0)
continue;
// 我方坦克坐标
int x = ldtank[id].row;
int y = ldtank[id].col;
// 开火目标
int did = last_orders[id].target;
if(did < 0)
{
find_injured(id);
continue;
}
int dx = ldtank[did].row;
int dy = ldtank[did].col;
assert(valid(x,y));
assert(valid(dx,dy));
// 前一个我方坦克的攻击指令已经回退过这个敌方坦克了,或者他上轮是无敌的
if(t_back[did] || ldtank[did].noharm > 0)
continue;
// 开火命中
if(tank[did].life == stank[did].life)
{
// fout<<"Tank:"<<id<<" 上轮命中Tank:"<<did<<endl;
// 修正坐标可信度
verify_last_point(did,dx,dy);
tankpt[nround-1][did] = allpt[nround-1][did][0];
if(last_orders[did].type != FIRE) // 如果上轮没开火
continue;
int dtid = last_orders[did].target;
if(stank[dtid].life > dtank[dtid].life) // 我方没有减血
continue;
// 我方掉血, 对方坐标位置不变
vector<pos>& vpt = allpt[nround][did];
vector<pos>& lvpt = allpt[nround-1][did];
for(int i=0;i<5;i++)
lvpt[0].fork[i] /= 10;
lvpt[0].fork[4] += 0.9;
for(int it=0;it<(int)vpt.size();it++)
{
if(vpt[it].x == dx && vpt[it].y == dy)
vpt[it].p = 0.9;
else
vpt[it].p /= 10;
}
recalc_p(vpt);
continue;
}
// 诡异的无法处理的情况
if(tank[did].life > stank[did].life)
{
// fout<<"Tank"<<did<<"血值低于预期, 他撞墙了?"<<endl;
continue;
}
// 上轮开火没有打中对方, 标记这个坦克坐标不可信
badpos[did] = 1;
// 是否可以通过交换解决
bool chg = false;
for(int nid = 5; nid<10; nid++)
{
if(tank[nid].life - stank[nid].life > 0) // 没有打他,它却掉血了
{
// fout<<"根据伤害推断,交换 Tank"<<did<<" 与 Tank"<<nid<<" 坐标"<<endl;
swap(dtank[did].row,dtank[nid].row);
swap(dtank[did].col,dtank[nid].col);
swap_tankpt(did,nid,nround);
// 修正其他向这个坦克开火的指令
for(int i=0;i<5;i++)
if(last_orders[id].target == did)
last_orders[id].target = nid;
// 修正这个坦克的开火指令
if(last_orders[did].type == FIRE)
last_orders[nid] = last_orders[did];
chg = true;
break; // 不要交换两次
}
}
if(chg)
{
// 当前坦克其实并没有被打,所以无法从这里得到任何信息, 返回
continue;
}
// fout<<"上轮Tank"<<id<<"开火sn_stop="<<sn_stop[id]<<",没有击中目标 Tank"<<did<<", ";
if(sn_stop[id] <= MX_STOP)
sn_stop[id] ++;
if(sn_stop[id] >= MX_STOP && !can_wait())
{
negate_point(did,dx,dy);
e_willstop[did] = 1;
// // fout<<"Round "<<nround<<" Tank"<<id<<" sn_stop=="<<sn_stop[id]<<endl;
}
// 修正移动方向
// 在上一轮的坐标集中否定这个点,并跟新本轮坐标概率
negate_last_point(did,dx,dy);
// 更新坐标
sort_points(allpt[nround][did]);
// tankpt
pos newpt = allpt[nround][did][0];
tankpt[nround][did] = newpt;
// tank
dtank[did].row = newpt.x;
dtank[did].col = newpt.y;
// fout<<"坐标更新为("<<newpt.x<<","<<newpt.y<<")"<<endl;
if(newpt.x == dx && newpt.y == dy)
{
e_stop++;
// fout<<"怀疑对方故意STOP"<<endl;
}
}
// 对方指令
for(int id=5; id<10; id++)
{
// 位置预测错误 或者 上轮这个坦克不存在 或者他回退了
if(badpos[id] || ldtank[id].life <= 0)
continue;
LSO &lso = last_orders[id];
// 不处理非开火指令
if( lso.type != FIRE) // 对方没有开火
continue;
int did = lso.target; // 打击的目标, 我方id
// 这个坦克回退了
if(t_back[id])
{
// 我仍然挨打了
if(dtank[did].life == stank[did].life)
{
// fout<<"Tank"<<id<<"错误回退问题, 必须检查确认"<<endl;
assert(0);
}
else
continue;
}
// 我方没有收到伤害
if( dtank[did].life < stank[did].life)
{
if(lso.conf == 0) // 对方没有视野的情况
{
if(e_forecast)
e_forecast--;
// fout<<"对方Tank"<<id<<"没有开火,stop概率降低"<<endl;
}
else
{
// fout<<"对方Tank"<<id<<"没有开火,位置前进一轮, 咋回事?"<<endl;
}
}
else
{
// 盲打
if(lso.conf == 0)
{
e_forecast += 15; // +++
// fout<<"对方Tank"<<id<<"盲打我方Tank"<<did<<endl;
}
}
}
// 莫名奇妙的掉血
for(int id=0;id<5;id++)
{
if(stank[id].life >= dtank[id].life)
continue;
int x = ldtank[id].row;
int y = ldtank[id].col;
int fd = 0;
for(int did=5;did<10;did++)
{
int dx = ldtank[did].row;
int dy = ldtank[did].col;
if(dy <0)
continue;
if(abs(x-dx) + abs(y-dy) <= stank[did].range)
{
fd ++;
break;
}
}
if(fd)
continue;
int tid,dx,dy;
// 周围没有敌方
for(int did=5;did<10;did++)
{
if(ldtank[did].col < 0)
continue;
vector<pos>& vpt = allpt[nround-1][did];
for(vector<pos>::iterator it=vpt.begin();it!=vpt.end();++it)
{
if(abs(x - it->x) + abs(y - it->y) == 5)
{
fd ++;
tid=did;
dx = it->x;
dy = it->y;
}
}
}
if(fd != 1)
continue;
// 可能性唯一
verify_point_p(tid,dx,dy,0.9);
// // fout<<"Round: "<<nround<<" 根据伤害推断出Tank:"<<tid<<" 在("<<dx<<","<<dy<<")"<<endl;
}
}
// 地图diff分析
void map_diff()
{
// 敌人远距离开路, diff反而起反作用
if(e_farbreak)
return;
// 分析每个格
for(int i=1;i<22;i++)
{
for(int j=1;j<22;j++)
{
// 没变
if( smap[i][j].type == lsmap[i][j].type)
continue;
//
if( smap[i][j].type == BRICK || // 砖
(smap[i][j].type == BREAKBRICK && lsmap[i][j].type == PERVIOUS) )
{
// fout<<"WARNING: 地图("<<i<<","<<j<<") 没有被破坏,预测存在错误"<<endl;
continue;
}
// 有地图元素被破坏
assert( (lsmap[i][j].type == BRICK && smap[i][j].type!= BRICK)
|| (lsmap[i][j].type == BREAKBRICK && smap[i][j].type == PERVIOUS) );
vector<pair<int,int> > can; // 可能存在敌方的地点
int go_back = -1; // 需要回退的坦克
// 拉人过来顶罪啦
int mi_dis = 1000;
int cn = -1; // 坦克id
int cd = -1; // 位置序号
// 分析4个方向
for(int k=0;k<4;k++)
{
int tx = i+ddx[k];
int ty = j+ddy[k];
if(!valid(tx,ty))
continue;
// 黑暗中的空地
if(mask[tx][ty] && smap[tx][ty].type == 0)
can.push_back(make_pair(tx,ty));
// 遍历敌方坦克
for(int did = 5; did<10; did++)
{
if(stank[did].row == tx && stank[did].col == ty) // 看到敌方坦克
goto find_enemy;
// 敌方上轮这里有坦克
if( ldtank[did].row == tx && ldtank[did].col == ty)
{
// 本轮阵亡
if(stank[did].life<=0)
goto find_enemy;
// 预测到上轮这里有敌方坦克,且是黑暗
if(mask[tx][ty] )
{
// 预测上轮不移动
if(dtank[did].row == tx && dtank[did].col == ty)
{
verify_point_p(did,tx,ty,0.9);
delete_point_p(nround,did,i,j);
goto find_enemy;
}
else
go_back = did; // 让他回退
}
}
}
}
// 需要回退一个坦克才解决问题
if(go_back != -1)
{
int tx = tankpt[nround-1][go_back].x;
int ty = tankpt[nround-1][go_back].y;
verify_point_p(go_back,tx,ty,0.9);
vector<pos>& vpt = allpt[nround][go_back];
// 删除向墙上的点
delete_point_p(nround,go_back,i,j);
verify_point_p(go_back,tx,ty,0.9);
sort_points(vpt);
tankpt[nround][go_back] = vpt[0];
dtank[go_back].row = tankpt[nround-1][go_back].x;
dtank[go_back].col = tankpt[nround-1][go_back].y;
// fout<<"通过地图diff,回退Tank"<<go_back<<"到 ("<<dtank[go_back].row<<","<<dtank[go_back].col<<")"<<endl;
goto find_enemy; // continue;
}
// 遍历周围每个点
for(int it=0;it<(int)can.size();it++)
{
int dx = can[it].first;
int dy = can[it].second;
for(int did = 5; did<10; did++)
{
// 这轮能看到, 上轮已经挂了,都不符合要求
if(stank[did].col > 0 || ldtank[did].life <= 0)
continue;
int ndis;
if(dtank[did].col > 0 && tank_w[did][dx][dy] >= 0) // 上一轮距犯罪现场的距离
ndis = tank_w[did][dx][dy];
else
ndis = 500; // 无法判断位置的地方坦克
if(ndis < mi_dis)
{
mi_dis = ndis;
cn = did;
cd = it;
}
}
}
// 这个是必然的...只要对方没挂光...
if(cn != -1)
{
assert(cd != -1 && (cn <10 || cn >= 5));
int dx = can[cd].first;
int dy = can[cd].second;
dtank[cn].row = dx;
dtank[cn].col = dy;
verify_point_p(cn,dx,dy,0.9);
sort_points(allpt[nround][cn]);
tankpt[nround][cn] = allpt[nround][cn][0];
// fout<<"通过地图diff得到坐标Tank"<<cn<<"("<<dx<<","<<dy<<")"<<endl;
}
else
{
// 没有找到敌人
// 这个或许可以作为敌军远距离开路的证据
bool fd = false;
// fout<<"WARNING: 地图diff出现问题在"<<i<<","<<j<<endl;
for(int did=5; did<10;did++)
{
if(ldtank[did].col > 0 && tank_w[did][i][j] < 6)
{
fd=true;
// fout<<"可能的破坏者Tank"<<did<<"("<<dtank[did].row<<","<<dtank[did].col<<")"<<endl;
// e_farbreak = 1;
}
if(!fd)
{
// fout<<"没有找到破坏者,是否bug?"<<endl;
}
}
}
find_enemy:
// 找到,继续分析下一个格
continue;
}
}
}
// 重新计算各点的概率
void recalc_p(vector<pos>& vpt)
{
if(vpt.empty())
return;
// 概率和
double sum = 0.0;
// 节点数
int vsz = (int)vpt.size();
// 遍历所有节点
for(int it=0;it<vsz;it++)
{
assert(vpt[it].p + eps >0); // 不允许负值
// 为0的移到末尾, 不为0的加和
if(vpt[it].p < eps)
{
vsz--;
if(it<vsz)
swap(vpt[it--],vpt[vsz]);
}
else
sum += vpt[it].p;
}
// 删除末尾节点
vpt.resize(vsz);
if(sum < eps)
{
// assert(0);
vpt.clear();
for(int i=5;i<10;i++)
{
vpt.push_back(pos(tank[i].StartRow,tank[i].StartCol,0.2));
}
return;
}
// 重新计算概率
for(vector<pos>::iterator it=vpt.begin();it!=vpt.end();++it)
{
it->p /= sum;
it->stop_p /= sum;
if(it->stop_p > it->p)
it->stop_p = it->p;
for(int i=0;i<5;i++)
it->fork[i] /= sum;
}
return;
}
// 修正历史,由nr+1反推
void modify_history(int id,int nr)
{
memset(tmp_mx,0,sizeof(tmp_mx));
while(tankpt[nr][id].p + eps < 1.0) // 直到坐标准确的那轮
{
// 可能在的点
vector<pos>& nvpt = allpt[nr+1][id];
for(vector<pos>::iterator it=nvpt.begin();it!=nvpt.end();++it)
{
for(int j = 0;j<4;j++)
{
int nnx = it->x + ddx[j];
int nny = it->y + ddy[j];
if(valid(nnx,nny) && smap[nnx][nny].type == PERVIOUS) // 可行
{
tmp_mx[nnx][nny] = 1;
}
}
}
bool need_recalc = false;
// 删除不可能的点,从新计算概率
for(int it=0;it<(int)allpt[nr][id].size();it++)
{
pos& pt = allpt[nr][id][it];
if(!tmp_mx[pt.x][pt.y]) // 不可能在这点
{
pt.p = 0.0;
pt.stop_p = 0.0;
need_recalc = true;
}
}
if(need_recalc)
recalc_p(allpt[nr][id]);
nr --;
}
}
// 确定敌方坦克位置
void find_enemy()
{
// 逐个确定
for(int i=5; i<10; i++)
{
// 挂了
if(stank[i].revive != -1)
{
ldtank[i] = dtank[i] = stank[i];
// tankpt
tankpt[nround][i] = pos(-2,-2);
// allpt
allpt[nround][i].clear();
// fout<<"Tank"<<i<<" 已经死亡"<<endl;
//continue;
}
// 刚复活
else if(stank[i].noharm == 2)
{
int nx = stank[i].StartRow;
int ny = stank[i].StartCol;
// dtank
dtank[i] = stank[i];
dtank[i].row = nx;
dtank[i].col = ny;
// ldtank
ldtank[i] = dtank[i];
// tankpt
verify_point(i,nx,ny);
//continue;
}
// 在视野中,收到准确坐标
else if(stank[i].col > 0)
{
// 新坐标
int nx = stank[i].row;
int ny = stank[i].col;
// 预测的坐标
pos fc_pt = tankpt[nround][i];
int oldx = fc_pt.x;
int oldy = fc_pt.y;
// 更新数据
ldtank[i] = dtank[i] = stank[i];
pos newpt(nx,ny,1.0);
// 不需反馈
if(nx < 0 || oldx < 0 || nround == 1)
{
verify_point(i,nx,ny);
continue;
}
// 预测正确
if(oldx==nx && oldy == ny)
{
verify_point(i,nx,ny);
continue;
}
bool fc_match = false;
// 查找有没有坦克和自己弄混了, 只查找比自己号大的坦克
for(int did = i+1; did<10; did++)
{
if(stank[did].col > 0) // 位置明确
continue;
if(stank[did].life <= 0 || ldtank[did].col < 0) // 死亡坦克
continue;
if(dtank[did].row != nx || dtank[did].col != ny) // 不和当前位置一致
continue;
// 交换坦克位置
// fout<<"将Tank"<<i<<"原预测位置("<<oldx<<","<<oldy<<") 交换给坦克"<<did<<endl;
dtank[did].row = oldx;
dtank[did].col = oldy;
swap_tankpt(i,did,nround);
ldtank[did] = dtank[did];
//ldtank[did].row = tankpt[nround][did].x;
//ldtank[did].col = tankpt[nround][did].y;
fc_match = true;
break;
}
if(fc_match)
{
verify_point(i,nx,ny);
continue;
}
// 预测存在误差, 对预测进行反馈
// 这时候我们还保留这旧的tankpt 和 allpt
// fout<<"Tank"<<i<<"坐标值更新"<<"("<<oldx<<","<<oldy<<"),->("<<nx<<","<<ny<<")"<<endl;
// 修正搜索顺序
pos& lpt = tankpt[nround-1][i];
int old_dir = -1;
int new_dir = -1;
for(int j=0;j<5;j++)
{
int nnx = lpt.x + ddx[j];
int nny = lpt.y + ddy[j];
if(nnx == oldx && nny == oldy)
old_dir = j; // 选择的方向
else if(nnx == nx && nny == ny)
new_dir = j;
}
if(old_dir != -1 && new_dir != -1 && new_dir<4 && old_dir<4 // 两个方向都有效
&& lpt.fork[old_dir] /2 < lpt.fork[new_dir]) // 新的方向也是一个选择
{
dir_p[old_dir][new_dir] ++;
}
verify_point(i,nx,ny);
}
// 敌方坦克在阴影中, 未收到准确坐标
else
{
pos& fc_pt = tankpt[nround][i];
int x = fc_pt.x;
int y = fc_pt.y;
dtank[i] = stank[i];
// 此点不在我方视野中, 检查是否和其他坦克弄混了
if(mask[x][y] == 0)
{
bool re_check = true;
while(re_check)
{
int tid = smap[x][y].whoIsHere; // 谁在这
if(tid > i) // 对方比自己号大
{
x = dtank[tid].row;
y = dtank[tid].col;
swap_tankpt(i,tid,nround);
dtank[tid].row = tankpt[nround][tid].x;
dtank[tid].col = tankpt[nround][tid].y;
if(dtank[i].row == x && dtank[i].col == y)
{
re_check = false;
}
else
{
dtank[i].row = x;
dtank[i].col = y;
}
// fout<<"Tank"<<i<<"得到Tank"<<tid<<"预测位置("<<x<<","<<y<<")"<<endl;
}
else
re_check = false;
}
}
// 否定在视野中的所有点
negate_points(i);
// 修正历史记录,太多了就算了
//if(vpt.size()< 30)
// modify_history(i,nround-1);
vector<pos>& vpt = allpt[nround][i];
if(vpt.empty())
{
assert(0);
// fout<<"坐标丢失"<<endl;
tankpt[nround][i] = pos(-2,-2);
dtank[i].row = dtank[i].col = -2;
ldtank[i] = tank[i];
}
sort_points(vpt);
pos& newpt = vpt[0];
// 预测不准确
if(mask[x][y] == 0 || smap[x][y].type != PERVIOUS)
{
// fout<<"Tank"<<i<<" 没有出现在("<<x<<","<<y<<"), "; // 没换行
}
if(newpt.x != x || newpt.y != y)
// fout<<"Tank"<<i<<"坐标更新为("<<newpt.x<<","<<newpt.y<<") e_stop="<<e_stop<<endl;
tankpt[nround][i] = newpt;
dtank[i].row = newpt.x;
dtank[i].col = newpt.y;
ldtank[i] = dtank[i];
// 如果对方坐标可信度>2/3
if(newpt.p > 0.67)
{
tank[i].row = dtank[i].row;
tank[i].col = dtank[i].col;
vtank[i] = 1;
if(smap[newpt.x][newpt.y].whoIsHere == -1)
smap[newpt.x][newpt.y].whoIsHere = i;
}
}
}
}
// 对每轮传入的数据进行预处理
// 这个函数太长了,一定要拆开
void init_data(DataForAI& data)
{
smap = data.map; // smap
stank = data.tank; // stank
src = data.source; // 矿点数组
src_num = data.totalSource; // 矿点总数
m_src = data.redSource; // 我方矿点数
e_src = data.blueSource; // 敌方矿点数
m_gold = data.redGoldNum; // 分数
e_gold = data.blueGoldNum; //
// 计算我方事业
our_shadow();
// 第一轮
if(nround == 1)
first_round();
else
feedback();
// 初始化 tank和vtank 数组
memset(vtank,0,sizeof(vtank)); // 坦克可视
for(int i=0;i<10;i++)
{
tank[i] = stank[i];
if(tank[i].row < 0)
vtank[i] = 0;
else
vtank[i] = 1;
}
// 假设敌方知道我方坦克信息, 其中ldtank是全息的
for(int i=0; i<5;i++)
ldtank[i] = dtank[i] = stank[i];
// diff地图
if(nround > 1)
map_diff();
// 敌方位置
find_enemy();
// 计算对方视野
memset(dmask,-1,sizeof(dmask));
for(int si=0;si<src_num;si++)
{
int sx = src[si].row;
int sy = src[si].col;
for(int i=-2;i<=2;i++)
for(int j=-2;j<=2;j++)
if( abs(i) + abs(j) <=2 && valid(sx+i,sy+j)) // 所有矿点视野
dmask[sx+i][sy+j] = 0;
}
// 敌方坦克视野
for(int id=5; id<10; id++)
{
if(tank[id].revive != -1)
continue;
int sx = tank[id].row;
int sy = tank[id].col;
for(int i=-4; i<=4; i++)
{
int bd = 4-abs(i);
for(int j= -bd; j<=bd; j++)
if(valid(sx+i,sy+j))
dmask[sx+i][sy+j] = 0;
}
}
calc_w();
// 初始化tank_w数组
for(int id=0; id<5; id++)
if(tank[id].col > 0)
flood_from(tank[id].row,tank[id].col,tank_w[id],stank[id].attack);
for(int id=5; id<10;id++)
if(dtank[id].col >0)
flood_from(dtank[id].row,dtank[id].col,tank_w[id],stank[id].attack);
// esc_w[id][0]有效?
for(int i=0;i<11;i++)
esc_v[i] = 0;
// src_w
for(int i=0;i<src_num;i++)
flood_from(src[i].row,src[i].col,src_w[1][i],1);
if(e_striker > 0)
{
for(int i=0;i<src_num;i++)
flood_from(src[i].row,src[i].col,src_w[0][i],2);
}
// 初始化orders数组
for(int id=0;id<10;id++)
orders[id].type = STOP;
// last_orders
for(int id=0;id<10;id++)
{
last_orders[id].type = STOP;
last_orders[id].target = -1;
last_orders[id].conf = -1;
}
}
// 敌军攻击
void enemy_fire()
{
for(int id=5; id<10; id++)
{
// 不在视野或者死的
if(dtank[id].col < 0)
continue;
int tx = dtank[id].row;
int ty = dtank[id].col;
for(int i=0; i<5; i++)
{
if(dtank[i].life > 0 && tank_dis(i,id,dtank) <= dtank[id].range)
{
// 这里不考虑敌方视野,假设敌方也会预测
int dx = dtank[i].row;
int dy = dtank[i].col;
// 如果没有视野, 那么conf = 0;
last_orders[id].conf = (dmask[dx][dy] == 0);
last_orders[id].type = FIRE;
last_orders[id].target = i;
orders[id].type = FIRE;
orders[id].row = dtank[i].row;
orders[id].col = dtank[i].col;
dtank[i].life -= dtank[id].attack;
if(dtank[i].life < 0)
dtank[i].life = 0;
// fout<<"Tank"<<id<<"("<<tx<<","<<ty<<")-"<<tankpt[nround][id].p<<" 攻击: Tank"<<i<<"("<<dx<<","<<dy<<")"<<endl;
break;
}
}
}
}
// 为预测服务的
double em[10][13]; // 权值矩阵
double lx[5],ly[13]; // 顶标
int ilink[13]; // 矿->坦克序号(非id)的映射
int ta[5],sa[13];
bool bifind(int t)
{
ta[t] = 1; // 表示t坦克有目标了
for(int i=0; i<src_num;i++)
{
if(!sa[i] && em[t][i] < lx[t]+ly[i]+1e-9 && em[t][i]+1e-9 >lx[t]+ly[i])
{
sa[i] = 1;
if(ilink[i] == -1 || bifind(ilink[i]))
{
ilink[i] = t;
return true;
}
}
}
return false;
}
void enemy_match(int tmt[10])
{
int tn = 0;
// 参与匹配的坦克
int mk[10];
for(int i=5; i<10;i++)
if(dtank[i].col > 0) // 所有坦克参与匹配 这里应该有个参数控制
mk[tn++] = i;
for(int i=0;i<tn;i++)
{
for(int si=0;si<src_num;si++)
{
int sx = src[si].row;
int sy = src[si].col;
bool needc = true; // 需要计算
if(smap[sx][sy].isHereSource == BlueSource) // 敌方自己的矿
{
needc = false;
for(int mid = 0;mid<5;mid++)
{
int mx = dtank[mid].row;
int my = dtank[mid].col;
if(dtank[mid].life < 0 || dmask[mx][my]) // 敌方看不到我
continue;
if(tank_w[mid][sx][sy] < 4 && tank_w[mid][sx][sy] < tank_w[mk[i]][sx][sy] ) // 敌方看到我靠近
{
needc = true;
break;
}
}
}
if(needc)
em[i][si] = 1.0/(tank_w[mk[i]][sx][sy]+1); // 敌方目标矿
else
em[i][si] = 1.0 / 1000; // 敌方认为安全的矿
}
}
// KM算法求最大二分匹配
// tn 坦克数 src_num 矿数
// init()
for(int i=0;i<tn;i++)
for(int j=0;j<src_num;j++)
if( em[i][j] > lx[i])
lx[i] = em[i][j];
memset(ilink,-1,sizeof(ilink));
memset(ly,0,sizeof(ly));
// km循环
for(int i= 0;i< tn;i++)
{
while(1)
{
memset(ta,0,sizeof(ta));
memset(sa,0,sizeof(sa));
if(bifind(i)) // 找到最大匹配
break;
double d = 1000.0;
for(int j=0; j<tn; j++)
{
if(ta[j])
{
for(int k=0; k< src_num; k++)
{
if(!sa[k])
d = min(d, lx[j] + ly[k] - em[j][k]);
}
}
}
if(d > 100.0)
break;
for(int j= 0;j<tn;j++)
{
if(ta[j])
lx[j] -= d;
}
for(int j=0;j<src_num;j++)
{
if(sa[j])
ly[j] += d;
}
}
}
for(int i=0;i<src_num;i++) // 为了顺序输出坦克, 放弃了执行效率
if(ilink[i] != -1)
tmt[mk[ilink[i]]] = i;
}
void enemy_match_greey(int tmt[10])
{
// 可以行动的坦克和坦克数量
int tv[10];
int tn = 0;
for(int i=5;i<10;i++)
{
if(dtank[i].col < 0)
tv[i] = 1;
else
{
tv[i] = 0;
tn ++;
}
}
// 有效的目标矿
int sv[13] = {0};
for(int i=0;i<src_num;i++)
{
int sx = src[i].row;
int sy = src[i].col;
if(smap[sx][sy].isHereSource == BlueSource)
{
bool need_d = false;
for(int j=0;j<5;j++)
{
if(dtank[j].life <= 0)
continue;
int tx = tank[j].row;
int ty = tank[j].col;
// 如果对方看不到我,不考虑防守
if(dmask[tx][ty])
continue;
// 对方需要防守此矿
if(tank_w[j][sx][sy] < 4)
{
need_d = true;
break;
}
}
if(need_d)
sv[i] = 0;
else
sv[i] = 1;
}
else
sv[i] = 0;
}
// 匹配
while(tn)
{
int mi_w = 10000;
int ct,cs;
for(int i=5;i<10;i++)
{
if(tv[i])
continue;
for(int si=0;si<src_num;si++)
{
int n_w;
if(sv[si])
{
n_w = 5000;
}
else
{
int sx = src[si].row;
int sy = src[si].col;
n_w = tank_w[i][sx][sy];
}
if(n_w < mi_w)
{
mi_w = n_w;
ct = i;
cs = si;
}
}
}
assert(mi_w < 10000);
tmt[ct] = cs;
tv[ct] = 1;
sv[cs] = 1;
tn --;
}
}
// 预测对方移动方向
void enemy_move(int tmt[10])
{
// 坐标集合的目的很简单,不让两个敌方坦克出现在同一位置
set<pair<int,int> > npts;
for(int id=5; id<10; id++)
if(dtank[id].col > 0)
npts.insert(make_pair(tankpt[nround][id].x,tankpt[nround][id].y));
// 敌方坦克行动
for(int id=5; id<10; id++)
{
if(ldtank[id].life <=0 || tankpt[nround][id].x < 0)
continue;
int sn = tmt[id]; // 目标矿id
int tx = dtank[id].row; // 当前坦克位置
int ty = dtank[id].col;
pos& fc_pt = tankpt[nround][id];
assert(sn != -1);
// 矿点坐标
int dx = src[sn].row;
int dy = src[sn].col;
// 计算路径权值
// 计算矿点距各点的距离
flood_from(dx,dy,tmp_mx,stank[id].attack);
// 本轮可能的所有坐标
vector<pos>& vpt = allpt[nround][id];
map<pos,double> newpt; // 下一步
map<pos,double> newstop; // 下一步来自stop的部分
// 删除自己的位置
int selfx = tankpt[nround][id].x;
int selfy = tankpt[nround][id].y;
npts.erase(make_pair(selfx,selfy));
// 对本轮所有可能点进行概率扩散
for(vector<pos>::iterator it=vpt.begin();it!=vpt.end();++it)
{
int min_w=1000;
int s_num = 0; // 短路径条数
int l_num = 0; // 长路径条数
// 和我方坦克的距离
bool may_stop = false;
if(stank[id].range == 5) // sniper
{
for(int i=0;i<5;i++)
{
if(ldtank[i].life <= 0)
continue;
int disk = abs(it->x - ldtank[i].row) + abs(it->y - ldtank[i].col);
if(disk == 5 || (disk == 6 && e_stop >= O_STOP && dtank[i].life > 0))
{
may_stop = true;
break;
}
}
}
else
{
// 处理st和p的stop行为
}
// 线性查找最短路
for(int i=0;i<4;i++)
{
int nx = it->x + ddx[i];
int ny = it->y + ddy[i];
if(!valid(nx,ny))
continue;
int w = tmp_mx[nx][ny]; // 路径长度 - 1
if( w < min_w)
{
l_num += s_num;
if(npts.find(make_pair(nx,ny)) != npts.end()) // 这个点有其他坦克了
{
l_num ++;
s_num = 0;
}
else
s_num = 1;
min_w = w;
}
// 最短路,且没有己方坦克
else if(w == min_w && npts.find(make_pair(nx,ny)) == npts.end())
s_num ++;
else
l_num++;
}
// stop的可能性
double stop_p;
double flood_p = 0.01; // 扩散几率
// 强制stop
if(e_willstop[id] == 1 && *it == fc_pt)
stop_p = 0.85;
// 开火
else if(orders[id].type == FIRE && *it == fc_pt)
{
if(last_orders[id].conf == 0) // 盲打
stop_p = 0.3;
else
stop_p = 0.85;
}
// 对方是sn, 距离我方5格
else if(may_stop)
stop_p = 0.3;
// 其他情况
else
stop_p = flood_p;
// stop
pos stop_pt(it->x,it->y);
double sp;
if(s_num == 0) // 最短路径上有队友
{
// 被动stop
sp = (1 - l_num * flood_p) * it->p;
newstop[stop_pt] += (1 - l_num * flood_p) * it->stop_p;
}
else
{
// 主动stop
sp = stop_p * it->p;
newstop[stop_pt] += sp;
}
newpt[stop_pt] += sp;
it->fork[4] += sp;
// move
for(int i=0;i<4;i++)
{
int nx = it->x + ddx[i];
int ny = it->y + ddy[i];
if(!valid(nx,ny)) // 无效
continue;
// 此点已有坦克 或者 非最短路
if(npts.find(make_pair(nx,ny)) != npts.end() || tmp_mx[nx][ny] > min_w)
{
newpt[pos(nx,ny)] += flood_p * it->p;
newstop[pos(nx,ny)] += flood_p * it->stop_p;
it->fork[i] += flood_p * it->p;
}
else // 无坦克,正常路径
{
double p = (1 - stop_p - l_num * flood_p) / s_num;
newpt[pos(nx,ny)] += p * it->p;
newstop[pos(nx,ny)] += p * it->stop_p;
it->fork[i] += p * it->p;
}
}
}
npts.insert(make_pair(selfx,selfy)); // 恢复npts
// 统计
vector<pos>& nvpt = allpt[nround+1][id];
nvpt.clear();
for(map<pos,double>::iterator it=newpt.begin();it!=newpt.end();++it)
{
pos pt = it->first; // 点
pt.stop_p = newstop[pt]; // 从stop得来得概率
pt.p = it->second; // 概率
nvpt.push_back(pt);
}
// 按概率排序
sort(nvpt.begin(),nvpt.end(),greater<pos>());
pos oldpt = tankpt[nround][id];
pos npt = nvpt[0];
npts.erase(make_pair(oldpt.x,oldpt.y));
npts.insert(make_pair(npt.x,npt.y));
// 修改位置信息
tankpt[nround+1][id] = npt;
dtank[id].row = npt.x;
dtank[id].col = npt.y;
if(orders[id].type != FIRE)
{
// fout<<"Tank"<<id<<"("<<oldpt.x<<","<<oldpt.y<<")-"<<tankpt[nround][id].p<<" 目标:"<<"("<<dx<<","<<dy<<") ";
// fout<<"方向:( "<<npt.x<<","<<npt.y<<"),准确度:"<<npt.p<<endl;
}
// 下下一步
vector<pos>& nnvpt = allpt[nround+2][id];
nnvpt.clear();
if(smap[npt.x][npt.y].type != PERVIOUS || tmp_mx[npt.x][npt.y] == 0) // 已达目标
nnvpt.push_back(npt);
else
{
for(int i=0;i<5;i++)
{
int nnx = npt.x + ddx[i];
int nny = npt.y + ddy[i];
if(tmp_mx[nnx][nny] + 1 == tmp_mx[npt.x][npt.y]) // 路径上一点
{
nnvpt.push_back(pos(nnx,nny));
}
}
}
if(nnvpt.size() == 1)
tankpt[nround+2][id] = nnvpt[0];
else
tankpt[nround+2][id] = npt;
}
}
void enemy_act()
{
#ifdef _DEBUG
// 敌方所有可能坐标
for(int id=5; id<10; id++)
{
// fout<<"Tank "<<id<<" 可能坐标"<<endl;
vector<pos>& vpt = allpt[nround][id];
for(vector<pos>::iterator it = vpt.begin();it!=vpt.end();++it)
{
// fout<<" ("<<it->x<<","<<it->y<<")-"<<it->p<<endl;
}
}
#endif
// 敌方射击
enemy_fire();
// 得到对方坦克目标
memset(e_target,-1,sizeof(e_target));
enemy_match_greey(e_target);
enemy_move(e_target); // 这里要先于我方攻击处理对方移动,原因是sniper要用对方位置数据
}
// 把stop更改为其他行动
void kill_stop()
{
for(int i=0;i<5;i++)
{
// 存在,且stop的坦克
if(orders[i].type != STOP || stank[i].life <= 0)
continue;
// 当前位置
int x = stank[i].row;
int y = stank[i].col;
double mx_p = 0.0;
int cx,cy,cid;
for(int did=5;did<10;did++)
{
if(tank[did].life <= 0)
continue;
// 遍历所有敌方可能存在的点
vector<pos>& vpt = allpt[nround][did];
for(vector<pos>::iterator it=vpt.begin();it!=vpt.end();++it)
{
if(abs(it->x - x) + abs(it->y - y) == 5)
{
if(it->p > mx_p + eps )
{
mx_p = it->p;
cx = it->x;
cy = it->y;
cid = did;
}
}
}
}
if(mx_p > eps)
{
// // fout<<"Round "<<nround<<"Tank:"<<i<<" FIRE 代替 STOP"<<endl;
orders[i] = fire_at(cx,cy);
tank[cid].life --;
last_orders[i].type = FIRE;
last_orders[i].target = -cid;
last_orders[i].conf = 0;
last_orders[i].x = cx;
last_orders[i].y = cy;
}
else
{
// 没有敌方单位
bool fd = false;
int si;
if(dmask[x][y])
si = 2;
else
si = 1;
for(int j=si;j<=5;j++)
{
int sz = ddn[j];
for(int k=0;k<sz;k++)
{
int tx = x + xdx[j][k];
int ty = y + xdy[j][k];
if(!valid(tx,ty) || smap[tx][ty].type == PERVIOUS)
continue;
if(abs(tx - stank[4].StartRow) + abs(ty - stank[4].StartCol) > // 到对方出生点的距离更小
abs(tx - stank[9].StartRow) + abs(ty - stank[9].StartCol))
continue;
orders[i] = fire_at(tx,ty);
if(smap[tx][ty].type == BRICK)
smap[tx][ty].type = BREAKBRICK;
else
smap[tx][ty].type = PERVIOUS;
fd = true;
// // fout<<"Tank:"<<i<<"随机开火"<<endl;
break;
}
if(fd)
break;
}
}
}
}
void calc_src_w(int vs[13],int e_want[13],int s_w[13])
{
for(int i=0;i<src_num;i++)
{
for(int j=5;j<10;j++)
{
if(e_target[j] == i && tank[j].life > 0)
{
e_want[i] = j;
break;
}
}
int sx = src[i].row;
int sy = src[i].col;
if(smap[sx][sy].isHereSource == RedSource) // 我方矿
{
if(e_want[i] == -1)
{
vs[i] = 1; // 标记无效
continue;
}
for(int k=0;k<4;k++)
{
int nx = sx + ddx[k];
int ny = sy + ddy[k];
if(!valid(nx,ny))
continue;
if(smap[nx][ny].isHereSource == RedSource)
s_w[i] ++; // 附近有矿,加权3
else if(smap[nx][ny].isHereSource == NeutralSource)
s_w[i] ++;
}
for(int k=0;k<8;k++)
{
int nx = sx + d2x[k];
int ny = sy + d2y[k];
if(!valid(nx,ny))
continue;
if(smap[nx][ny].isHereSource == RedSource)
s_w[i] ++;
else if(smap[nx][ny].isHereSource == NeutralSource)
s_w[i] ++;
}
}
else // 敌方或中立矿
{
for(int k=0;k<4;k++)
{
int nx = sx + ddx[k];
int ny = sy + ddy[k];
if(!valid(nx,ny))
continue;
if(smap[nx][ny].isHereSource == BlueSource)
s_w[i] ++;
else if(smap[nx][ny].isHereSource == NeutralSource)
s_w[i] ++;
}
for(int k=0;k<8;k++)
{
int nx = sx + d2x[k];
int ny = sy + d2y[k];
if(!valid(nx,ny))
continue;
if(smap[nx][ny].isHereSource == BlueSource)
s_w[i] ++;
else if(smap[nx][ny].isHereSource == NeutralSource)
s_w[i] ++;
}
}
}
}
// 任务分配
// tank,目标点
void assignment(int tmt[5])
{
// 我方坦克
int vt[10] = {0}; // 0表示可用
int tn = 0; // 可用坦克数
for(int i=0;i<5;i++)
{
if(tank[i].life <= 0)
vt[i] = 1;
else
tn ++;
}
// 矿点
int vs[13] = {0}; // 0表示没有坦克前往
int e_want[13]; // 哪个敌方以此为目标
int s_w[13] = {0}; // 矿点重要性
memset(e_want,-1,sizeof(e_want));
calc_src_w(vs,e_want,s_w);
// 循环匹配
while(tn)
{
int mi_w = 10000;
int ct,cs;
for(int id=0;id<5;id++)
{
if(vt[id]) // 已有任务
continue;
for(int s=0;s<src_num;s++)
{
int sx = src[s].row;
int sy = src[s].col;
int m_w = tank_w[id][sx][sy]; // 离我方坦克的距离
int n_w = m_w;
if(vs[s]) // 对此矿没有需求
{
n_w = 5000 + m_w - s_w[s];
}
else if(smap[sx][sy].isHereSource == RedSource) // 我方矿需要防守
{
int did = e_want[s];
assert(did >= 5);
int d_w = tank_w[did][sx][sy]; // 敌方距离
int d_bound;
if(m_src > e_src)
d_bound = 10 + (m_src - e_src);
else
d_bound = 10;
if( d_w < d_bound)
n_w = max(m_w,d_w) - s_w[s];
else
n_w = max(m_w,3*d_w) - s_w[s];
// 多血p
if(tank[did].type == Pioneer && tank[did].life > 6)
{
if(s_w[s] == 0) // 孤矿放弃
n_w += 5; // +5
else
; // 猜想还会有其他坦克来的
}
}
else
{
n_w = m_w - s_w[s]; // 优先级提高
if(smap[sx][sy].isHereSource == BlueSource) // 对方的矿
n_w --; // 优先级提高1
else if(e_want[s] != -1) // 中立矿
{
int did = e_want[s];
int d_w = tank_w[did][sx][sy]; // 敌方距离
if( (tank[did].type == Pioneer && tank[did].life > 6) // 对方是p
|| (tank[id].life < 2 && tank[did].range == 5) ) // 我血少与对方sn
{
if(d_w < m_w && s_w[s] == 0) // 孤矿放弃
n_w += 15; // +15
else
; // 猜想还会有其他坦克来的
}
}
}
if(n_w < mi_w)
{
mi_w = n_w;
cs = s;
ct = id;
}
}
}
vs[cs] = 1;
vt[ct] = 1;
tmt[ct] = cs;
tn --;
int sx = src[cs].row;
int sy = src[cs].col;
// fout<<"Tank:"<<ct<<" 匹配矿点"<<cs<<" ("<<sx<<","<<sy<<") mi_w="<<mi_w<<endl;
int did = e_want[cs];
if(did == -1) // 没人管
{
for(int i=0;i<src_num;i++)
{
if(vs[i] || e_want[i] != -1)
continue;
// 没人要的矿
if(src_w[1][i][sx][sy] <= 4) // 离这矿很近
{
vs[i] = 1;
}
}
}
}
}
void otu()
{
// 选矿 贪心匹配
int vs[13] = {0};
int vt[10] = {0};
// 标记无效坦克
int tn = 0;
for(int id=0; id<5; id++)
{
if(tank[id].life <=0)
vt[id] =1;
else
tn ++;
}
vector<pair<int,int> > comm;
while(tn)
{
int ct,cs;
int mi_w = 10000;
// 对每个矿点
for(int i=0; i<src_num;i++)
{
if(vs[i]) // 已有我方坦克前往
continue;
int sx = src[i].row;
int sy = src[i].col;
int mi_d = 10000; // 我军距离
int dmd = 10000; // 敌军距离
int dmid= -1; // 敌方id
int cid = -1; // 我方距离此矿最近的坦克
for(int id=0; id<5; id++)
{
if (vt[id]) // 当前坦克已有任务
continue;
if (tank_w[id][sx][sy] < mi_d)
{
mi_d = tank_w[id][sx][sy];
cid = id;
}
}
// 敌方坦克距离
for(int id=5; id<10; id++)
{
if (dtank[id].col < 0)
continue;
if (e_target[id] != i) // 对方目标不是当前矿点
continue;
if(dmd > tank_w[id][sx][sy])
{
dmd = tank_w[id][sx][sy];
dmid = id;
}
}
int weight; // 任务权重
if(smap[sx][sy].isHereSource == RedSource) // 我方矿点
{
if(dmd > 7) // 距离>5时不需防守
{
if(dmd< 5000)
dmd += 5000; // 降低到最低优先
else
{
int ndx = tank[5].StartRow;
int ndy = tank[5].StartCol;
dmd = 7000 + abs(sx -ndx) + abs(sy-ndy); // 冲向地方老家
}
}
weight = max(mi_d,dmd); // 3----------------------防守降级权值
}
else // 敌方矿
weight = mi_d;
// 更新最优值
if (weight < mi_w)
{
mi_w = weight;
ct = cid; // 坦克
if(tank_w[cid][sx][sy] < weight && weight < 5000) // 我方距离更近
cs = dmid*100 + i; // 而不是向矿移动
else
cs = i; // 矿
}
}
if(ct != -1)
{
int dsx = src[cs%100].row;
int dsy = src[cs%100].col;
comm.push_back(make_pair(ct,cs));
vs[cs%100] = 1;
vt[ct] = 1;
tn --; // 等待指令坦克数--
// fout<<"移动指令:Tank"<< ct <<"-> "<<dsx<<","<< dsy<<endl;
}
else // 没有发现敌方坦克
{
assert(0);
}
}
}
// 执行指令
void implement(int tmt[5])
{
for(int id=0;id<5;id++)
{
if( stank[id].life <= 0 || orders[id].type != STOP || willstop[id]==1) //为1的表示肯定stop
continue;
int cs = tmt[id];
int sx = src[cs].row;
int sy = src[cs].col;
if( smap[sx][sy].isHereSource != RedSource) // 占领命令
{
orders[id] = move_to(id,sx,sy);
}
else // 防守命令
{
int m_dis = tank_w[id][sx][sy];
int did = -1;
// 确定防守目标
for(int i=5;i<10;i++)
if(e_target[i] == cs)
did = i;
// 存在目标, 是p, 我方矿少, 就不要防
if(did != -1 && (stank[did].range == 1 || (m_src <= e_src && !can_wait()) )) // p 或我方劣势
{
int e_dis = tank_w[did][sx][sy];
if(m_dis >= e_dis)
orders[id] = move_to(id,sx,sy);
else
orders[id] = move_to(id,dtank[did].row,dtank[did].col);
}
else if(stank[id].range == 1) // 我方是p
{
orders[id] = move_to(id,sx,sy);
}
else
{
// 敌方距离
int d_w = tank_w[did][sx][sy];
// 确定对方入口
set<point> rukou;
for(int i=0;i<4;i++)
{
int nx = sx + ddx[i];
int ny = sy + ddy[i];
if(tank_w[did][nx][ny] != d_w - 1)
continue;
int adw;
if(smap[nx][ny].type == PERVIOUS)
adw = 1;
else if(smap[nx][ny].type == BREAKBRICK || stank[did].attack == 2)
adw = 2;
else
adw = 3;
for(int ni =0;ni<4;ni++)
{
int nnx = nx + ddx[ni];
int nny = ny + ddy[ni];
if(tank_w[did][nnx][nny] != d_w - 1 - adw)
continue;
rukou.insert(point(nnx,nny));
}
}
int mi_w = 10000;
int cx,cy;
for(int k=3;k<5;k++)
{
for(int i=0;i<ddn[k];i++)
{
int tx = sx + xdx[k][i];
int ty = sy + xdy[k][i];
if(!valid(tx,ty) || smap[tx][ty].type != PERVIOUS)
continue;
// 不选视野中的点
if(dmask[tx][ty] == 0)
continue;
int w;
if(did != -1 && tank[id].life < 2)
{
int dx = dtank[did].row;
int dy = dtank[did].col;
w = tank_w[id][tx][ty] - abs(tx-dx) - abs(ty - dy); // 如果血量过少,就不要靠近敌方
}
else
w = tank_w[id][tx][ty];
bool can_cover = true;
for(set<point>::iterator it = rukou.begin();it!=rukou.end();++it)
{
if(abs(tx - it->x) + abs(ty - it->y) > stank[id].range) // 超出攻击范围
{
can_cover = false;
break;
}
}
if(can_cover && tank_w[id][tx][ty] <= d_w - 2)
w -= 5;
if(w <mi_w)
{
mi_w = w;
cx = tx;
cy = ty;
}
}
}
if(mi_w < 10000)
{
if(cx == tank[id].row && cy == tank[id].col)
{
// // fout<<"Round:"<<nround<<" 已经到达防守地点("<<cx<<","<<cy<<")"<<endl;
orders[id] = norder;
}
else
orders[id] = move_to(id,cx,cy);
}
else
orders[id] = move_to(id,sx,sy);
}
}
last_orders[id].type = orders[id].type;
}
}
void analyse()
{
// 考虑对方的攻击和移动
enemy_act();
// 计算sn逃跑的路径权值
if(nround > 1) // 第一轮负载太重...
calc_w_for_run();
memset(willfire,0,sizeof(willfire));
memset(willstop,0,sizeof(willstop));
memset(stop_for,-1,sizeof(stop_for));
// ai
for(int id=0; id<5;id++)
{
if(tank[id].life > 0) // 活者自卫
{
if(tank[id].type == Sniper)
sniper_ai(id);
else if(tank[id].type == Pioneer)
pioneer_ai(id);
else
willfire[id] = 1;
}
}
// 处理射击
fire();
//
sniper_stop();
calc_w_for_move();
int tmt[5];
memset(tmt,-1,sizeof(tmt));
assignment(tmt);
implement(tmt);
if(nround > 1)
kill_stop();
}
int tank_dis(int id,int did,TankData* _tank)
{
assert(_tank[did].col > 0 && _tank[did].revive == -1);
return abs(_tank[id].row - _tank[did].row) + abs(_tank[id].col-_tank[did].col);
}
// ******************射击********************
Order attack(int id,int did)
{
Order order;
int sx = tank[id].row;
int sy = tank[id].col;
int dx = ldtank[did].row;
int dy = ldtank[did].col;
last_orders[id].type = FIRE;
last_orders[id].target = did;
if(stank[did].col < 0)
last_orders[id].conf = 0;
else
{
if(sn_stop[id] > 0)
sn_stop[id] --;
last_orders[id].conf = 1;
}
// fout<<"Tank:"<<id<<" ("<<sx<<","<<sy<<") 攻击 目标:("<<dx<<","<<dy<<")"<<endl;
tank[did].life -= tank[id].attack;
if(tank[did].life <= 0)
{
tank[did].life = 0;
smap[dx][dy].whoIsHere = -1;
vtank[did] = 0;
}
order.type = FIRE;
order.row = dx;
order.col = dy;
return order;
}
// 移动一格
Order step_to(int id,int dx,int dy)
{
Order order;
int sx = tank[id].row;
int sy = tank[id].col;
assert(abs(sx-dx) + abs(sy-dy) == 1 && valid(sx,sy));
int did = smap[dx][dy].whoIsHere;
// 修改地图
if(did==-1)
{
smap[dx][dy].whoIsHere = id;
smap[sx][sy].whoIsHere = -1;
}
else if(did>=5) // 敌方坦克,这里不处理敌方坦克掉血
{
smap[sx][sy].whoIsHere = -1;
}
if(dx<sx) // 上
order.type = GOUP;
else if(dx>sx) // 下
order.type = GODOWN;
else if(dy <sy) // 左
order.type = GOLEFT;
else // 右
order.type = GORIGHT;
return order;
}
// 指定了移动的目标但,完成寻路与移动
Order move_to(int id,int dx,int dy)
{
// 与矿的距离
int (*vm)[23] = tmp_mx;
flood_from(dx,dy,vm,3);
int x = tank[id].row;
int y = tank[id].col;
int mi_w = 1000;
for(int i=0;i<4;i++)
{
int nx = x + ddx[i];
int ny = y + ddy[i];
if(valid(nx,ny) && vm[nx][ny] >= 0)
mi_w = min(mi_w, vm[nx][ny]);
}
// fout<<"Tank:"<<id<<" ("<<tank[id].row<<","<<tank[id].col<<") 移动 目标:("<<dx<<","<<dy<<")-"<<mi_w+1<<" 方向:";
int cx = -1;
int cy = -1;
double mx_score = -100;
// 从4个方向中选择一个
for(int i=0;i<4;i++)
{
int nx = x + ddx[i];
int ny = y + ddy[i];
if(!valid(nx,ny) || vm[nx][ny] <0)
continue;
// 与最短路径的差值
int diff = vm[nx][ny] - mi_w;
// 多于1点,还不如停一轮
if(diff > 1)
continue;
// 路径权值得分 12, 6
double score = 12 - diff * 6;
// 目标点无队友 +10
if(smap[nx][ny].whoIsHere < 0)
score += 10;
// 阴影 +8
if(dmask[nx][ny])
score += 8;
else if(willstop[id] == 2) // 不进敌方视野
score = -1;
// 与队友的最近距离,在 2 - 250 之间
// score增加 0 ~ 1
if(nround > 3)
{
int mi_td = 1000;
for(int t=0;t<5;t++)
if(t!=id && tank[t].col > 0)
mi_td = min(mi_td,abs(nx-tank[t].row) + abs(ny - tank[t].col));
if (mi_td > 1)
score += 2.0/mi_td;
}
// 根据下一步的视野微调,0 ~ 0.4之间
int yinying = 0;;
for(int di=0;di<4;di++)
{
int nnx = nx + ddx[di];
int nny = ny + ddy[di];
if(!valid(nnx,nny))
continue;
if(dmask[nnx][nny])
yinying ++;
}
score += 0.1*yinying;
// 不要靠近出生点,微调 0 ~ 0.125
int bdis = 0; // 距所有出生点的总距离, 应该在 8-1000 之间
for(int it=0; it<5; it++)
{
int stx = tank[it].StartRow;
int sty = tank[it].StartCol;
bdis += abs(nx-stx)+abs(ny-sty);
}
score -= 1.0/bdis;
if(score > mx_score + eps)
{
mx_score = score;
cx = nx;
cy = ny;
}
// fout<<"("<<nx<<","<<ny<<"-"<<vm[nx][ny]+1<<"-"<<score<<") ";
}
if(cx < 0)
return norder;
// fout<<"选择:("<<cx<<","<<cy<<")"<<endl; // 行进方向上有砖,开火
if(smap[cx][cy].type == BRICK || smap[cx][cy].type == BREAKBRICK) // 砖
{
Order order;
order.row = cx;
order.col = cy;
order.type = FIRE;
// 砖掉血
if(smap[cx][cy].type == BREAKBRICK || tank[id].attack > 1)
smap[cx][cy].type = PERVIOUS;
else
smap[cx][cy].type = BREAKBRICK;
return order;
}
if(willstop[id] == 2 && dmask[cx][cy] == 0) // 不进敌方视野
{
// fout<<"Tank:"<<id<<" 等待敌方进入攻击范围,sn_stop="<<sn_stop[id]<<endl;
sn_stop[id]+= 2; // 因为之前减了
if(sn_stop[id] > MX_STOP)
sn_stop[id] = MX_STOP + 1;
return norder; // stop
}
// 前方有队友
if(smap[cx][cy].whoIsHere != -1)
{
int did = smap[cx][cy].whoIsHere;
assert(did<5); // 己方
// fout<<"Tank:"<<id<<" 移动位置("<<cx<<","<<cy<<"),与Tank:"<<did<<"冲突,";
if(tank[id].range == 1)
{
// fout<<"stop"<<endl;
return norder;
}
if(orders[did].type == FIRE)
{
int tdx = orders[did].row;
int tdy = orders[did].col;
if(abs(tdx - tank[did].row) + abs(tdy - tank[did].col) == 1 && smap[tdx][tdy].whoIsHere == -1) // 打墙
{
if(smap[tdx][tdy].type == PERVIOUS)
{
orders[did] = step_to(did,tdx,tdy); // 让路
}
smap[tdx][tdy].type = PERVIOUS;
// fout<<"帮队友开路"<<endl;
return fire_at(tdx,tdy);
}
}
// 帮队友开路
int tx = tank[did].row;
int ty = tank[did].col;
for(int i = 0;i<4;i++)
{
int nnx = tx+ddx[i];
int nny = ty+ddy[i];
if(smap[nnx][nny].type == BREAKBRICK)
{
smap[nnx][nny].type = PERVIOUS;
// fout<<"帮队友开路"<<endl;
return fire_at(nnx,nny);
}
}
for(int i = 0;i<4;i++)
{
int nnx = x+ddx[i];
int nny = y+ddy[i];
if(smap[nnx][nny].type == BRICK)
{
if(tank[id].attack == 1)
smap[nnx][nny].type = BREAKBRICK;
else
smap[nnx][nny].type = PERVIOUS;
// fout<<"帮队友开路"<<endl;
return fire_at(nnx,nny);
}
}
// fout<<endl;
}
return step_to(id,cx,cy);
}
// sniper逃跑用
void calc_w_for_run()
{
//
for(int i=1;i<22;i++)
{
for(int j=1;j<22;j++)
if(smap[i][j].type == 0)
wt_map[0][i][j] = 1;
else
wt_map[0][i][j] = -1;
}
// 敌人会加大权值
for(int id=5;id<10;id++)
{
if(vtank[id]==0 || tank[id].life <= 0)
continue;
// 无视sn
if(stank[id].range == 5)
continue;
int r = tank[id].range;
int x = tank[id].row;
int y = tank[id].col;
for(int d=r;d<=r+2;d++)
{
for(int i= -d ;i<=d;i++)
{
int l = d-abs(i);
for(int j= -l;j<=l;j++)
{
if(!valid(x+i,y+j) || wt_map[0][x+i][y+j] == -1)
continue;
if(d==r)
wt_map[0][x+i][y+j] = -1;
else
wt_map[0][x+i][y+j] += 1; // 权值增加
}
}
}
}
for(int i=0;i<src_num;i++)
{
int sx = src[i].row;
int sy = src[i].col;
if(wt_map[0][sx][sy] == -1)
continue;
if(smap[sx][sy].isHereSource == RedSource)
{
// 矿附近权值增加
for(int d=0;d<4;d++)
{
int ad = 4-d; // 4,3,2,1
for(int j=0;j<ddn[d];j++)
{
int x = sx + xdx[d][j];
int y = sy + xdy[d][j];
if(!valid(x,y) || wt_map[0][x][y] == -1)
continue;
wt_map[0][x][y] += ad; // 把矿绕过去
}
}
}
else
{
wt_map[0][sx][sy] = 0;
}
}
}
void calc_w_for_move()
{
int tid;
for(int i=1; i<22; i++)
{
for(int j =1; j<22; j++)
{
if(!valid(i,j)) // 不是石头
continue;
switch(smap[i][j].type)
{
case 2: //breakbrick
wt_map[3][i][j] = 2;
break;
case 1: // 砖
wt_map[3][i][j] = 3;
break;
case 0: // 空地 // 敌人
tid = smap[i][j].whoIsHere;
if(tid < 5 && tid >=0 &&
(willstop[tid] || (orders[tid].type == FIRE && last_orders[tid].conf ==0))) // stop 或 盲打中
{
wt_map[3][i][j] = -1;
}
else
wt_map[3][i][j] = 1;
break;
default:
assert(0);
wt_map[3][i][j] = -1;
}
}
}
}
// 计算地图权值, 这个可以在开始一轮时计算完毕
void calc_w()
{
for(int i=1; i<22; i++)
{
for(int j =1; j<22; j++)
{
if(!valid(i,j)) // 不是石头
continue;
switch(smap[i][j].type)
{
case 2: //breakbrick
wt_map[1][i][j] = 2;
wt_map[2][i][j] = 2;
break;
case 1: // 砖
wt_map[1][i][j] = 3;
wt_map[2][i][j] = 2;
break;
case 0: // 空地 // 敌人
wt_map[1][i][j] = 1; // 暂时无视
wt_map[2][i][j] = 1;
break;
default:
assert(0);
wt_map[1][i][j] = -1;
wt_map[2][i][j] = -1;
}
}
}
}
// *----------------------------------------------*
// 洪泛,计算一点到地图其他点的距离,结果保存在参数vm中
// 假设调用前已初始化地图权值wt_map[][]
// 使用SPFA,希望高效
int in_queue[23][23]; // 标记是否在队列中
point pt_q[23*23]; // 点的队列
void flood_from(int sx,int sy,int vm[][23],int at)
{
assert(in_range(sx,sy));
memset(vm,-1,sizeof(int)*23*23);
memset(in_queue,0,sizeof(in_queue));
int top = 0; // 队首
int tail = 0; // 队尾
// 起点入队
vm[sx][sy] = 0;
pt_q[tail++] = point(sx,sy);
in_queue[sx][sy] = 1;
while(top != tail)
{
assert( (tail + 23*23 -top) % (23*23) < 22 * 22);
// 弹出首节点 pt
point pt = pt_q[top++];
top %= 23*23;
in_queue[pt.x][pt.y] = 0;
int w = vm[pt.x][pt.y]; // 节点权值
for(int i=0;i<4;i++)
{
int nx = pt.x + ddx[i];
int ny = pt.y + ddy[i];
if(!valid(nx,ny) || wt_map[at][nx][ny] == -1)
continue;
// 新节点
int nw = w + wt_map[at][nx][ny];
point npt(nx,ny);
// 可松弛且不在队列中
if(vm[nx][ny] == -1 || (nw < vm[nx][ny] && !in_queue[nx][ny]))
{
vm[nx][ny] = nw;
pt_q[tail++] = npt;
tail %= 23*23;
in_queue[nx][ny] = 1;
}
// 在队列中,更新权值
else if(nw < vm[nx][ny])
vm[nx][ny] = nw;
}
}
}
// 带权id
struct p_id
{
int id;
int w;
int done;
p_id(int i,int ww) :id(i),w(ww),done(0) {}
bool operator>(const p_id& ot) const
{
return w>ot.w;
}
bool operator<(const p_id& ot) const
{
return w<ot.w;
}
};
// 坦克间的距离
int t_dis[10][10];
// 射击处理,当前预测结果的优先级很低
bool fire()
{
memset(t_dis,0,sizeof(t_dis));
vector<p_id> vt; // 参与进攻的坦克 ,会挂的优先, 攻击高的优先, 号大的优先 willfire >= 10的最后
for(int i=0; i<5; i++)
{
bool has_e = false;
for(int did =5; did<10;did++)
{
int dis;
if(vtank[did])
dis = tank_dis(i,did);
else if(ldtank[did].col > 0)
dis = tank_dis(i,did,ldtank); // 和ld坦克的距离
else
continue;
t_dis[i][did] = dis; // 后面要用
if(dis <= tank[i].range)
has_e = true;
}
if(!has_e)
continue;
if(willfire[i]>=10)
{
vt.push_back(p_id(i,i%5 - 5)); // 最后
}
else if(willfire[i]>0)
{
int wt;
if( dtank[i].life <= 0)
wt = 20 + tank[i].attack*5; // 死的
else
wt = i%5 + tank[i].attack*5; // 攻高的优先
vt.push_back(p_id(i,wt));
}
}
sort(vt.begin(),vt.end(),greater<p_id>());
vector<p_id> vd; // 敌方坦克,
for(int i=5; i<10; i++)
{
if(ldtank[i].col <= 0)
continue;
if(tank[i].noharm != 0)
{
vd.push_back(p_id(i,-20));
}
int wt;
if(vtank[i])
{
if(stank[i].col < 0)
wt = 99;
else
wt = 100;
}
else
{
wt = 0;
}
for(int id=0;id<5;id++)
{
// 计算坦克距离
int dis =t_dis[id][i];
int ndis = tank_dis(id,i,dtank);
if(willfire[id]-10 == i)
{
wt += 25;
}
else
{
if( ndis <=tank[i].range)
{
wt += tank[i].attack;
}
if( dis <= tank[i].range) // 我在敌方射程
{
wt += tank[i].attack * 2;
}
else if(dis <= tank[id].range && wt%100==0) // 敌方在我射程
{
wt += 1; // 不是0就可以了
}
}
}
if(wt%100)
{
vd.push_back(p_id(i,wt));
}
}
sort(vd.begin(),vd.end(),greater<p_id>());
// 无需开火
if(vt.empty() || vd.empty())
return true;
int tn = (int)vt.size();
for(int i=0;i<(int)vd.size();i++)
{
if(!tn || vd[i].w < 100) // 这里不处理隐藏的
break;
// 目标id
int did = vd[i].id;
// 精确打击
for(int j=0;j<(int)vt.size();j++)
{
int tid = vt[j].id;
if(vt[j].done || t_dis[tid][did] > tank[tid].range)
continue;
if(tank[tid].attack == tank[did].life)
{
// fout<<"Tank:"<<tid<<" 精确打击"<<endl;
orders[tid] = attack(tid,did);
vt[j].done = 1;
tn --;
break;
}
}
// 击毙
if(tank[did].life < 1)
continue;
// 试打
int hp = tank[did].life;
for(int j=0;j<(int)vt.size();j++)
{
int tid = vt[j].id;
if(vt[j].done || t_dis[tid][did] > tank[tid].range)
continue;
hp -= tank[tid].attack;
}
// 打不死, 放弃这个目标
if(hp > 0)
{
// 受这个目标威胁,但还没出手的sn放弃
for(int j=0;j<(int)vt.size();j++)
{
int tid = vt[j].id;
if(willfire[tid] == 10 + did && !vt[j].done)
{
orders[tid] = sniper_escape(tid);
if(orders[tid].type == STOP) // 无路可逃
continue;
willfire[tid] = 0;
vt[j].done = 1;
vd[i].w -= 18; // 取消这个sn的加权
// 因为这个目标是打不死的,所以这里不需要从新排序,也不能重新排序
tn --;
// fout<<"Tank:"<<tid<<"退出攻击序列:无法击杀Tank"<<did<<endl;
}
}
continue;
}
// 打
for(int j=0;j<(int)vt.size();j++)
{
// 已经挂了
if(tank[did].life < 1)
break;
int tid = vt[j].id;
if(vt[j].done || t_dis[tid][did] > tank[tid].range)
continue;
// 如果不浪费伤害,开火
if(tank[did].life >= tank[tid].attack) // 1对1或者2对2
{
// fout<<"Tank:"<<tid<<"优先攻击"<<endl;
orders[tid] = attack(tid,did);
vt[j].done = 1;
tn --;
continue; // 下一位
}
// 2点伤害,但目标只有1点血, 寻找最合适的攻击者
for(int k = j+1;j<(int)vt.size();j++)
{
int ttid = vt[k].id;
if(vt[k].done || t_dis[ttid][did] > tank[ttid].range) // 已经有任务或者打不上
continue;
if(tank[ttid].attack > 1) // 同样是2点伤害
continue;
if( willfire[ttid] >= 10) // 受到其他目标威胁
{
if( willfire[ttid]-10 != i && tank[willfire[ttid] - 10].life > 0) // 威胁目标还在
continue;
}
// fout<<"Tank:"<<ttid<<"优化攻击"<<endl;
orders[ttid] = attack(ttid,did);
vt[k].done = 1;
tn --;
assert(tank[did].life == 0);
}
if(tank[did].life > 0)
{
orders[tid] = attack(tid,did);
vt[j].done = 1;
tn --;
}
}
}
// 在这里重排
sort(vd.begin(),vd.end(),greater<p_id>());
// 对其他目标进行打击
for(int i=0;i<(int)vd.size();i++)
{
if(!tn)
break;
int did = vd[i].id;
if(tank[did].life <=0)
continue;
for(int j=0;j<(int)vt.size();j++)
{
int tid = vt[j].id;
if(vt[j].done || t_dis[tid][did] > tank[tid].range)
continue;
orders[tid] = attack(tid,did);
vt[j].done = 1;
tn --;
if(tank[did].life <= 0)
break;
}
}
//
return true;
}
// pioneer AI. 现在这个ai还很不完善,最后要不要加入pioneer还有待考虑
void pioneer_ai(int id)
{
int hp = tank[id].life;
for(int i=5; i<10; i++)
if(vtank[i] && tank_dis(id,i) <= tank[i].range)
hp -= tank[i].attack;
if(hp<=0)
{
willfire[id] = 1;
return;
}
;
int x = tank[id].row;
int y = tank[id].col;
for(int i=5;i<10;i++)
{
if(tank_w[i][x][y] == 1)
{
willfire[id] =1;
return;
}
}
int ds = 0;
int ms = 0;
for(int i=0;i<src_num;i++)
{
int sx = src[i].row;
int sy = src[i].col;
if(tank_w[id][sx][sy] < 5)
{
if(smap[sx][sy].isHereSource == RedSource)
ms ++;
else
ds ++;
}
}
if(ds > ms && dtank[id].life > 3)
{
willfire[id] = 1;
return ;
}
int mi_dis = 15;
int ct;
for(int i=5;i<10;i++)
{
if(!vtank[i] || ldtank[i].col < 0)
continue;
int dx = ldtank[i].row;
int dy = ldtank[i].col;
int ndis = tank_dis(id,i,ldtank);
if(tank_w[id][dx][dy] < 5 && ndis <= stank[i].range)
{
if(ndis < mi_dis || (ndis == mi_dis && stank[ct].range < stank[i].range) )
{
mi_dis = ndis;
ct = i;
}
}
}
if(mi_dis < 15)
{
int dx = ldtank[ct].row;
int dy = ldtank[ct].col;
orders[id] = move_to(id,dx,dy);
}
return;
}
// 下一步的安全系数
int next_safe(int id,int x,int y)
{
if(!valid(x,y) || smap[x][y].type !=0) // 无法通过
return 0;
// 最大是100,每遇敌一次-10
int score = 100;
for(int i=5; i<10; i++)
{
int bound;
if(stank[i].range == 1 && tank[id].life > 1)
bound = 0;
else
bound = stank[i].range;
if(tank[i].life > 0)
{
if(abs(dtank[i].row - x) + abs(dtank[i].col - y) <= bound) // 这里使用的dtank
score -= 10;
if(abs(tank[i].row -x) + abs(tank[i].col - y) <= bound)
score -= 10;
}
}
// 与其他坦克冲突 -10
if(smap[x][y].whoIsHere >= 0)
score -= 10;
return score;
}
// 能逃的就4个点
Order sniper_escape(int id)
{
int x = tank[id].row;
int y = tank[id].col;
// 首先确定是否有逃跑可能
bool can = false;
for(int i=0;i<4;i++)
{
if(next_safe(id,x+ddx[i],y+ddy[i]) == 100)
{
can = true;
break;
}
}
if(!can)
{
// fout<<"sniper("<<x<<","<<y<<") 无路可逃"<<endl;
return norder;
}
// 尝试逃跑
if(!esc_v[id])
{
flood_from(x,y,esc_w[id],0);
esc_v[id] = 1;
}
vector<p_id> duiyou;
for(int i=0;i<5;i++)
{
if(id == i || tank[i].life <= 0)
continue;
int tx = tank[i].row;
int ty = tank[i].col;
if(tank_w[id][tx][ty] == 1) // 与队友的距离为1,不考虑.
continue;
if(esc_w[id][tx][ty] < 3) // 距离已经很近了
{
esc_w[id][tx][ty] += 80; // 不要进死胡同啊
}
bool is_safe = true;;
for(int j=5;j<10;j++)
{
if(tank[j].life <= 0 || tank[j].col < 0)
continue;
int w = tank_w[j][tx][ty]; // 与敌方的距离
if(w <= stank[j].range)
{
is_safe = false;
break;
}
}
if(is_safe)
duiyou.push_back(p_id(i,esc_w[id][tx][ty]));
}
// 排序目标点
sort(duiyou.begin(),duiyou.end());
// 加入出生点
duiyou.push_back(p_id(10,100));
for(vector<p_id>::iterator it= duiyou.begin();it!=duiyou.end();++it)
{
int tx = tank[it->id].row;
int ty = tank[it->id].col;
if(!esc_v[it->id])
{
flood_from(tx,ty,esc_w[it->id],0);
esc_v[it->id] = 1;
}
int mi_w = 1000;
int cx,cy;
for(int i=0;i<4;i++)
{
int nx = x + ddx[i];
int ny = y + ddy[i];
int w = esc_w[it->id][nx][ny];
if(w == -1 || smap[nx][ny].whoIsHere != -1)
continue;
if(w < mi_w)
{
mi_w = w;
cx = nx;
cy = ny;
}
}
if(mi_w < 1000)
{
willfire[id] = 0;
// fout<<"Tank:"<<id<<" ("<<x<<","<<y<<") sniper 躲避至:("<<cx<<","<<cy<<")"<<endl;
return step_to(id,cx,cy);
}
}
return norder;
}
// 处理sn是否需要stop,和反预测
void sniper_stop()
{
int crash_for[10]= {0};
// stop等待敌人进入射程
for(int id = 0; id<5; id++)
{
int sx = tank[id].row;
int sy = tank[id].col;
// 不是空闲sn
if(tank[id].life <= 0 || orders[id].type != STOP || tank[id].range != 5)
continue;
// 埋伏超过3轮,也就是说最多埋伏4轮
if( sn_stop[id] + 2 >= MX_STOP && !can_win())
{
// fout<<"Tank:"<<id<<" sniper 无法继续stop sn_stop="<<sn_stop[id]<<endl;
sn_stop[id] --; // 这个不应该降为0
for(int i = 5;i<10;i++)
{
if(dtank[i].col < 0)
continue;
if(tank_dis(id,i,dtank) == 5 || tank_dis(id,i,ldtank) == 5)
crash_for[i] = 1;
}
continue;
}
for(int did=5; did<10; did++)
{
// 无效单位
if(tank[did].life <=0 || dtank[did].col < 0 )
continue;
// 距离
int tk_dis = tank_dis(id,did,dtank);
// 和对方距离==6的情况
if(tk_dis == 6 && dmask[sx][sy] && tank[did].range == 5) // 等于6的情况很复杂啊, 正处于阴影中
{
bool ws = true;
vector<pos>& vpt = allpt[nround+2][did];
for(vector<pos>::iterator it=vpt.begin();it!=vpt.end();++it)
{
if(abs(it->x - sx) + abs(it->y -sy) != 5) // 下下一轮距离为5
{
ws = false;
break;
}
}
if(ws)
{
willstop[id] = 2; // 选择性stop
// fout<<"Tank:"<<id<<"选择性stop,sn_stop="<<sn_stop[id]<<endl;
}
}
if(tk_dis != 5)
continue;
if(dmask[sx][sy]) // 不在敌方的视野中,埋伏
{
willstop[id] = 1;
// fout<<"Tank:"<<id<<" sniper stop 在敌方视野外,sn_stop="<<sn_stop[id]<<"m_sn="<<m_src<<"e_sn="<<e_src<<endl;
break; // 一个目标就够了,没必要判断其他目标
}
// 下面是当前坦克处于对方视野中的处理
if(tank[did].range < 5 || nround < 30) // 对方非sn
{
// fout<<"Tank:"<<id<<" sniper stop 对方非sn,sn_stop="<<sn_stop[id]<<endl;
willstop[id] = 1;
stop_for[id] = did;
break;
}
bool canhide = false;
// 敌方是sn,且我在敌方视野中, 退出视野利用矿点诱杀对方
for(int i=0;i<4;i++)
{
int dx = sx + ddx[i];
int dy = sy + ddy[i];
if(dmask[dx][dy] && smap[dx][dy].type == PERVIOUS && next_safe(id,dx,dy) == 100) // 这里是否要加一个next_safe呢?????????
{
// fout<<"Tank:"<<id<<" 准备诱杀"<<"Tank"<<did<<",退出敌方视野"<<endl;
orders[id] = step_to(id,dx,dy);
canhide = true;
stop_for[id] = did;
break;
}
}
if(!canhide && !can_win())
{
// fout<<"Tank:"<<id<<" 位置不利,冲锋"<<endl;
crash_for[did] = 1;
}
else
{
willstop[id] = 1;
stop_for[id] = did;
// fout<<"Tank:"<<id<<" 形式有利,不冲锋"<<endl;
}
// 所处不不利,冲锋, 只要不丢失对方的坐标,冲锋并不会对我方造成什么损失
// 当然这里也可以根据矿是不是自己的,如果是自己的可以多搜索一格进行躲避
}
if(willstop[id]==1)
if(sn_stop[id] <= MX_STOP)
sn_stop[id] ++;
else
{
if(sn_stop[id])
sn_stop[id]--;
}
}
if(nround > 30)
{
int wait_e[10] = {0};
for(int id=0;id<5;id++)
{
if(stop_for[id] != -1)
{
int for_who = stop_for[id];
if( ++wait_e[for_who] > 0)
{
for(int i= 0;i<5;i++)
{
if(stop_for[i] == for_who)
{
if(willstop[id] == 1)
{
sn_stop[id] -= 2;
if(sn_stop[id] < 0)
sn_stop[id] = 0;
}
willstop[id]=0;
}
}
wait_e[for_who] = 0;
}
}
}
}
// 一起冲
for(int id=0;id<5;id++)
{
// 对准备stop的.
if(willstop[id])
{
for(int did=5;did<10;did++)
{
if(crash_for[did]==0)
continue;
if(tank_dis(id,did,ldtank) == 5 || tank_dis(id,did,dtank) == 5)
{
if(willstop[id] == 1)
{
sn_stop[id] -= 2;
if(sn_stop[id] < 0)
sn_stop[id] = 0;
}
willstop[id]=0;
}
}
}
}
}
// sniper行动ai
void sniper_ai(int id)
{
int x = tank[id].row;
int y = tank[id].col;
// 离出生点的距离
int home_dis = tank_w[id][stank[id].StartRow][stank[id].StartCol];
// fout<<"Tank:"<<id<<" sn_ai"<<endl;;
// 计算与敌军坦克的距离
int dis[10];
for(int i=5; i<10; i++)
{
if(vtank[i])
dis[i] = tank_dis(id,i);
else
dis[i] = 10000;
}
// 在敌人射程内了,就不要多想了,打吧
for(int i=5;i<10;i++)
{
if( dis[i] <= stank[i].range && stank[i].range > 1) // 现在除去了p
{
// fout<<"在敌方射程内,开火"<<endl;
willfire[id] = 1;
return;
}
}
// 视野外的
for(int i=5; i<10; i++)
{
if( ldtank[i].col > 0 && tank_dis(id,i,ldtank) <= ldtank[i].range && stank[i].range > 1)
{
willfire[id] = 1;
// fout<<"sniper发现视野外威胁,选择开火"<<endl;
return;
}
}
// 脚下有矿,优先占矿
for(int i=0;i<4;i++)
{
int nx = x + ddx[i];
int ny = y + ddy[i];
if(smap[nx][ny].isHereSource == BlueSource || smap[nx][ny].isHereSource == NeutralSource)
{
if(smap[nx][ny].whoIsHere == -1 && next_safe(id,nx,ny))
{
orders[id] = move_to(id,nx,ny);
return;
}
}
}
willfire[id] = 1; // 先假设可以开火
int cand = -1; // 需要击毙才能安全
for(int i=5; i<10;i++)
{
if(dtank[id].life <= 0)
continue; // 会死的话就不考虑躲避了
if(stank[i].range == 5 || dis[i] > 4) // sn
continue;
if(stank[i].range == 3 && dis[i] != 4) // 遇到st,只有4格时才考虑躲避
continue;
bool needrun = false; // 需要逃跑么?
if(stank[i].range == 1) // 遇到p
{
if(tank[id].life == 2 && dis[i] == 2) // 满血,距离为2, 不逃跑
continue;
if(tank[id].life == 1 && dis[i] == 1) // 1点血,距离为1,也不考虑跑
continue;
}
// 先判断对方是否能靠近, 这个无可争议
needrun = false;
if(dis[i] > 1)
{
for(int di = 0; di<4; di++)
{ // 穷举对手可能移动的方向
int dx = tank[i].row + ddx[di];
int dy = tank[i].col + ddy[di];
if(!valid(dx,dy))
continue;
if(smap[dx][dy].type != 0 || smap[dx][dy].whoIsHere > 0) // 不可通过
continue;
if(abs(dx-x)+abs(dy-y) <= tank[i].range) // 通过移动可以打击
{
needrun = true;
break;
}
}
}
else
needrun = true;
if(!needrun)
{
// fout<<"tank"<<i<<"无法靠近"<<endl;
continue;
}
if(dis[i] > 1 && dtank[i].row == tank[i].row && dtank[i].col == tank[i].col)
{
// fout<<"tank"<<i<<"打墙,不靠近"<<endl;
continue;
}
// 对方攻击范围内有友军, 这样对方极有可能开火而不是向自己靠近
needrun = true;
for (int fid = 0; fid<5; fid++)
{
if(fid != id && tank[fid].life > 0 && tank_dis(fid,i) <= tank[i].range)
{
needrun = false;
break;
}
}
if(!needrun)
{
// fout<<"tank"<<i<<"有攻击目标,不会靠近"<<endl;
continue;
}
// 判断对方坦克移动方向, 只有在敌方不追杀的情况下才那么干
if(tank[i].range == 1 && !pn_track || tank[i].range == 3 && !st_track)
{
vector<pos>& vpt = allpt[nround+1][i];
needrun = false;
// fout<<"Tank"<<i<<":可能移动方向: ";
for(vector<pos>::iterator it=vpt.begin();it!=vpt.end();++it)
{
if(it->p + eps > 0.25)
{
// fout<<"("<<it->x<<","<<it->y<<")-"<<it->p<<" ";
if(abs(it->x - x) + abs(it->y - y) <= stank[i].range) // 敌方能打到我
{
// fout<<"向我靠近"<<endl;
needrun = true;
break;
}
}
}
if(!needrun)
{
// fout<<"预测敌方不会靠近"<<endl;
continue;
}
}
// 考虑击毙敌人
int hp = 0;
for(int fid=0; fid<5; fid++) // 计算队友肯能给予的帮助
if(fid != id && tank[fid].life > 0 && tank_dis(fid,i) <= tank[fid].range) // 队友射程范围 , 这里假设队友会攻击当前敌人,多数情况下成立
hp += tank[fid].attack;
if(hp >= tank[i].life) // 猜想队友会击毙当前敌人
{
// fout<<"队友会击毙敌方坦克"<<endl;
cand = i;
continue;
}
if(hp+1 >=tank[i].life) // 与队友合作击毙
{
if(willfire[id] < 10)
{
// fout<<"与队友合作击毙敌方坦克"<<endl;
willfire[id] = i + 10;
continue;
}
// fout<<"敌军过多,不可能一次击毙"<<endl;
}
// 查看是否需要同归于尽
bool has_f = false;
for(int f=0;f<5;f++)
{
if(f==id || dtank[f].life <=0)
continue;
int fx = tank[f].row;
int fy = tank[f].col;
if(tank_w[id][fx][fy] < 6)
{
// fout<<"附近有队友,撤退"<<endl;
has_f = true;
break;
}
}
if(!has_f || dtank[id].life < 2) //
{
if((home_dis < 7 && e_pioneer < 4) || home_dis < 3)
{
// fout<<"离家太近,不需后退"<<endl;
continue;
}
}
bool willdie = false;
for(int si = 0;si<src_num;si++)
{
int sx = src[si].row;
int sy = src[si].col;
if(tank_w[i][sx][sy] < 4 && smap[sx][sy].isHereSource == RedSource) // 有矿需要保护
{
if(tank_w[id][sx][sy] <= 5 && has_f) // 自己离这矿很近能很快反抢, 且附近有队友
continue;
if(tank[i].range == 3 && hp + 2 >= tank[i].life)
{
willdie = true;
break;
}
if(tank[i].range == 1 && hp + tank_w[i][x][y] - 1 + tank[id].life >= tank[i].life)
{
willdie = true;
break;
}
}
}
if(willdie)
{
// fout<<"保护矿,与对手同归于尽"<<endl;
continue;
}
// 没有选择了,准备逃走
orders[id] = sniper_escape(id);
if(orders[id].type == STOP)
willfire[id] = 1;
else
willfire[id] = 0;
break;
}
if(cand != -1 && willfire[id] == 1)
willfire[id] = cand + 10;
return;
}
// 翻转命令
Order rv_order(Order order)
{
switch(order.type)
{
case GOUP:
order.type = GODOWN;
break;
case GODOWN:
order.type = GOUP;
break;
case GOLEFT:
order.type = GORIGHT;
break;
case GORIGHT:
order.type = GOLEFT;
break;
case FIRE:
order.row = RV(order.row);
order.col = RV(order.col);
break;
}
return order;
}
// 翻转传入参数, 结果放在sdata中
void rv_data(DataForAI& data)
{
if(data.myFlag == RED)
{
sdata = data;
return;
}
for(int i=0;i<23;i++)
{
for(int j=0;j<23;j++)
{
MapCell& mc = sdata.map[RV(i)][RV(j)];
mc = data.map[i][j];
if(mc.isHereSource == RedSource)
mc.isHereSource = BlueSource;
else if(mc.isHereSource == BlueSource)
mc.isHereSource = RedSource;
if(mc.whoIsHere != -1)
mc.whoIsHere = (mc.whoIsHere + 5)%10;
}
}
// tank
for(int i=0;i<10;i++)
{
TankData& td = sdata.tank[i];
td = data.tank[(i+5)%10];
if(td.row > 0)
td.row = RV(td.row);
if(td.col > 0)
td.col = RV(td.col);
td.flag = td.flag==RED?BLUE:RED;
td.ID = i;
td.StartRow = RV(td.StartRow);
td.StartCol = RV(td.StartCol);
}
// source
for(int i=0;i<data.totalSource;i++)
{
Point& pt = sdata.source[data.totalSource - 1 - i];
pt = data.source[i];
pt.col = RV(pt.col);
pt.row = RV(pt.row);
}
// myID
sdata.myID = (data.myID+5)%10;
sdata.round = data.round;
sdata.redGoldNum = data.blueGoldNum;
sdata.blueGoldNum = data.redGoldNum;
sdata.redScore = data.blueScore;
sdata.blueScore = data.redScore;
sdata.redSource = data.blueSource;
sdata.blueSource = data.redSource;
sdata.totalSource = data.totalSource;
sdata.redTime = sdata.blueTime;
sdata.blueTime = sdata.redTime;
}
// 自杀
Order suicide(int id)
{
int x = stank[id].row;
int y = stank[id].col;
int nx=-1;
int ny=-1;
for(int i=0;i<4;i++)
{
int nnx = x + ddx[i];
int nny = y + ddy[i];
if(smap[nnx][nny].type == STONE || smap[nnx][nny].type == BRICK)
{
nx = nnx;
ny = nny;
break;
}
else if(smap[nnx][nny].type == BREAKBRICK)
{
nx = nnx;
ny = nny;
}
}
Order order;
if(nx!=-1)
{
if(nx<x) // 上
order.type = GOUP;
else if(nx>x) // 下
order.type = GODOWN;
else if(ny <y) // 左
order.type = GOLEFT;
else // 右
order.type = GORIGHT;
}
else
{
order.type = FIRE;
order.row = x;
order.col = y;
}
return order;
}
// 集体舞
Order dance(DataForAI& data)
{
stank = data.tank;
smap = data.map;
int id = data.myID;
int center_row = stank[4].StartRow;
int center_col = stank[4].StartCol;
int my_row = data.tank[data.myID].row;
int my_col = data.tank[data.myID].col;
Order order;
order.type = STOP;
//当自己是4号坦克或9号坦克时,返回STOP指令
if (id == 4)
{
if(my_row == center_row && my_col == center_col)
return order;
else
return suicide(4);
}
else
{
if(abs(center_row - my_row) > 1 || abs(center_col - my_col) >1)
return suicide(id);
}
//Let‘s Dance!
if (my_row > center_row && my_col >= center_col)
order.type = GOLEFT;
if (my_row >= center_row && my_col < center_col)
order.type = GOUP;
if (my_row < center_row && my_col <= center_col)
order.type = GORIGHT;
if (my_row <= center_row && my_col > center_col)
order.type = GODOWN;
//返回指令
return order;
}
标签:
原文地址:http://www.cnblogs.com/AngelWing/p/5719990.html