package warbot.chevri_t;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.TreeMap;
import madkit.kernel.AgentAddress;
import warbot.kernel.Food;
import warbot.kernel.Percept;
import warbot.kernel.WarbotMessage;
/**
* @author chevri_t
*
*/
@SuppressWarnings("serial")
public final class Terminator extends Mobile
{
boolean haveToEat = false;
boolean defend = false;
boolean explore = false;
Double attackDir = null;
int timeToReload = 0;
MobileFoe foeToAttack = null;
HashMap<AgentAddress, Ally> allies = new HashMap<AgentAddress, Ally>();
public Terminator() {}
@Override
public void activate() {
super.activate();
specificRoleName = "Launcher";
requestRole(groupName, specificRoleName, null);
points.setPerceptRadius(Cst.DR.LauncherDR);
}
@Override
public void doIt() {
super.doIt();
if (posToRef == null)
return;
if (timeToReload > 0)
timeToReload--;
haveToEat = false;
hasAction = false;
Percept[] perception = getPercepts();
for (Percept element : perception) {
String elmType = element.getPerceptType();
Boolean foe = !element.getTeam().equals(getTeam());
if (elmType.equals("RocketLauncher")) {
int perceptRad = foe ? Cst.DR.LauncherDR : 20;
if (foe) {
nbEnnemis++;
foeAttackPos = toWBPoint(element);
}
foes.put(element, posToRef, foe, perceptRad);
} else if (elmType.equals("Explorer")) {
int perceptRad = foe ? Cst.DR.ExplorerDR : 20;
foes.put(element, posToRef, foe, perceptRad);
} else if (elmType.equals("Food")) {
if (!isNearABase(toWBPoint(element)))
points.add(new InterestPoint(toWBPoint(element),
InterestPoint.Type.Food));
if ((getRocketNumber() == 0 || getEnergyLevel() * 1.5 < baseEnergyLevel)
&& getEnergyLevel() < getMaximumEnergy())
eatFood((Food)element);
} else if (elmType.equals("Home")) {
if (foe) {
points.add(new InterestPoint(toWBPoint(element),
InterestPoint.Type.Base));
foes.put(element, posToRef, foe, 60);
} else
homes.put(element.getAgent(), toWBPoint(element));
obst.add(new Obstacle(toWBPoint(element), element.getRadius() - 13));
} else if (elmType.equals("Obstacle"))
obst.add(new Obstacle(toWBPoint(element), element.getRadius()));
else if (elmType.equals("Rocket"))
foes.put(element, posToRef, true, 70);
}
SelectTarget();
UpdateFoesAndIP();
PerformAction();
allies.clear();
SendMessages();
}
private boolean attack() {
MobileFoe foe = foeToAttack;
WBPoint attackPos = null;
if (foe == null)
return false;
attackPos = calculateAttackPos(foe);
if (posToRef.distance(foe.getPosition()) > 200)
return false;
for (Entry<AgentAddress, Ally> ally : allies.entrySet()) {
if (posToRef.distance(ally.getValue().getPosition()) > 210)
continue;
if (GeoUtil.areCircleSegmentIntersected(posToRef, attackPos, ally
.getValue().getPosition(), ally.getValue().getRadius() + 15)) {
// TODO:select better tempTarget
Say("Can't shoot, there is an ally, foe pos", attackPos.toString(),
"ally pos", ally.getValue().getPosition().toString(), "my pos",
posToRef.toString());
double delta = Math.random() > 0.5 ? -90 : 90;
if (tempTarget == null || tempTarget.equals(posToRef.x, posToRef.y))
tempTarget = posToRef.getTargetPoint(100,
getDeltaDir(posToRef.direction(attackPos), delta));
return false;
}
}
double dir = posToRef.direction(attackPos);
shotRocket(dir);
return true;
}
private WBPoint calculateAttackPos(MobileFoe f) {
if (f.getType().equals(MobileFoe.Type.Rocket) || f.getDirection() == -1)
return f.getPosition();
double vMag = Cst.CD.RocketCD;
double x = posToRef.getX();
double y = posToRef.getY();
double Bx = f.getPosition().getX();
double By = f.getPosition().getY();
double ux = f.getVelocityVector().getX();
double uy = f.getVelocityVector().getY();
// Find the vector AB
double ABx = Bx - x;
double ABy = By - y;
// Normalize it
double ABmag = Math.sqrt(ABx * ABx + ABy * ABy);
ABx /= ABmag;
ABy /= ABmag;
// Project u onto AB
double uDotAB = ABx * ux + ABy * uy;
double ujx = uDotAB * ABx;
double ujy = uDotAB * ABy;
// Subtract uj from u to get ui
double uix = ux - ujx;
double uiy = uy - ujy;
// Set vi to ui (for clarity)
double vix = uix;
double viy = uiy;
// Calculate the magnitude of vj
double viMag = Math.sqrt(vix * vix + viy * viy);
double vjMag = Math.sqrt(vMag * vMag - viMag * viMag);
// Get vj by multiplying it's magnitude with the unit vector AB
double vjx = ABx * vjMag;
double vjy = ABy * vjMag;
// Add vj and vi to get v
double vx = vjx + vix;
double vy = vjy + viy;
WBPoint result = new WBPoint(x + vx * 120, y + vy * 120);
return result;
}
/**
* @param element
*/
private void eatFood(Food p) {
if (p.getDistance() < 10)
Say("Distance to food", Double.toString(distanceTo(p)));
if (p.getDistance() < 2) {
eat(p);
hasAction = true;
} else {
haveToEat = true;
target = toWBPoint(p);
}
}
private void PerformAction() {
if (foeToAttack != null && !haveToEat) {
if (attack())
return;
if (/* target == null && */posToRef.distance(foeToAttack.getPosition()) >= 200)
target = foeToAttack.getPosition();
else
target = null;
}
if (hasAction || (target == null || posToRef.equals(target.x, target.y))
&& tempTarget == null && !explore)
return;
if (explore
&& (tempTarget == null || tempTarget.equals(posToRef.x, posToRef.y)))
if (target == null)
tempTarget = posToRef.getTargetPoint(Cst.DR.ExplorerDR / 2,
getDeltaDir(getHeading(), (Math.random() - 0.5) * 65));
else
tempTarget = new WBPoint(target.x, target.y);
else if (!isMoving())
tempTarget = posToRef.getTargetPoint(Cst.DR.ExplorerDR / 2,
Math.random() * 360);
TreeMap<Double, Point2D.Double> practicablePoints = new TreeMap<Double, Point2D.Double>();
if (/*
* (tempTarget == null || posToRef.equals(tempTarget.x, tempTarget.y))
* &&
*/target != null)
tempTarget = new WBPoint(target.x, target.y);
// Say("TempTarget", tempTarget.toString());
double direction = posToRef.direction(tempTarget);
double newDirection = 0;
double disTar = posToRef.distance(tempTarget);
boolean isSafe = true;
boolean isPracticable = true;
Obstacles obsts = GeoUtil.getLocalObstacles(obst, 100, posToRef);
ArrayList<MobileFoe> mfoes = GeoUtil.getLocalFoes(foes, Cst.DR.ExplorerDR,
posToRef);
double i = 1;
boolean isNegatif = true;
final double delta = 360 / 33;
Point2D.Double practicablePoint = null;
do {
isSafe = true;
isPracticable = true;
for (Obstacle ob : obsts)
if (ob.getPos().distance(tempTarget) < disTar
&& GeoUtil.areCircleLineIntersected(posToRef, tempTarget,
ob.getPos(), ob.getRadius() + 11)) {
isNegatif = !isNegatif;
i = isNegatif ? i : i + 1;
double mult = isNegatif ? i * delta : -i * delta;
newDirection = getDeltaDir(direction, mult);
tempTarget = posToRef.getTargetPoint(Cst.DR.ExplorerDR / 2,
newDirection);
isPracticable = false;
break;
}
if (isPracticable)
if (defend) {
for (Entry<AgentAddress, Ally> al : allies.entrySet())
if (al.getValue().getPosition().distance(tempTarget) < disTar
&& GeoUtil.areCircleLineIntersected(posToRef, tempTarget, al
.getValue().getPosition(), al.getValue().getRadius() + 11)) {
isNegatif = !isNegatif;
i = isNegatif ? i : i + 1;
double mult = isNegatif ? i * delta : -i * delta;
newDirection = getDeltaDir(direction, mult);
tempTarget = posToRef.getTargetPoint(Cst.DR.ExplorerDR / 2,
newDirection);
isPracticable = false;
break;
}
continue;
}
practicablePoint = new Point2D.Double();
practicablePoint.setLocation(tempTarget);
double score = 0;
for (MobileFoe mf : mfoes) {
score += ScoreDirection(newDirection, mf);
int maxDistance = mf.IsFoe() ? Cst.DR.LauncherDR + 20 : 88;
if (!mf.getType().equals(MobileFoe.Type.Rocket)
&& (GeoUtil.areCircleLineIntersected(posToRef, tempTarget,
mf.getPosition(), mf.getPerceptRadius() + 20) || GeoUtil
.areLineLineIntersected(posToRef, tempTarget, mf.getPosition(),
mf.getTargetPoint(300), maxDistance))) {
isNegatif = !isNegatif;
i = isNegatif ? i : i + 1;
double mult = isNegatif ? i * delta : -i * delta;
newDirection = getDeltaDir(direction, mult);
tempTarget = posToRef.getTargetPoint(Cst.DR.ExplorerDR / 2,
newDirection);
isSafe = false;
break;
}
if (mf.getType().equals(MobileFoe.Type.Rocket)) {
if (mf.getDirection() == -1 || !mf.isApproaching(posToRef))
continue;
// double step = i;
while (GeoUtil.angleBetween2Lines(posToRef, tempTarget,
mf.getPosition(), mf.getTargetPoint(2)) < 60
&& i < 360 / delta) {
isNegatif = !isNegatif;
i = isNegatif ? i : i + 1;
double mult = isNegatif ? i * delta : -i * delta;
newDirection = getDeltaDir(direction, mult);
tempTarget = posToRef.getTargetPoint(Cst.DR.ExplorerDR / 2,
newDirection);
}
break;
}
}
practicablePoints.put(score, practicablePoint);
}
while ((!isSafe || !isPracticable) && i < 360 / delta);
if (!isSafe) {
Say("Take best practicable point");
tempTarget.setLocation(practicablePoints.lastEntry().getValue());
}
setHeading(posToRef.direction(tempTarget));
if (!isPracticable || !isMoving())
randomHeading();
move();
}
private Double ScoreDirection(double myDir, MobileFoe foe) {
Point2D.Double newPos = posToRef.getTargetPoint(1, myDir);
Point2D.Double foeNewPos = foe.getTargetPoint(1);
if (foeNewPos == null)
foeNewPos = foe.getPosition();
return newPos.distance(foeNewPos);
}
private InterestPoint selectBestTargetToAttack() {
InterestPoint ip = points.getNearest(InterestPoint.Type.Base, posToRef);
if (ip != null) {
if (posToRef.distance(ip) < 230) {
String[] args = new String[] { Cst.Priority.High,
Double.toString(ip.getX()), Double.toString(ip.getY()) };
Messenger(groupName, "Explorer", Cst.Msg.Goal.attack, args);
}
return ip;
}
Messenger(groupName, "Explorer", Cst.Msg.cancel, Cst.Msg.Goal.attack);
Comparator<InterestPoint> comp = new Comparator<InterestPoint>() {
@Override
public int compare(InterestPoint o1, InterestPoint o2) {
if (o1.distance(posToRef) > o2.distance(posToRef))
return 1;
else if (o1.distance(posToRef) < o2.distance(posToRef))
return -1;
else
return 0;
}
};
Collections.sort(points, comp);
for (InterestPoint spot : points)
if (spot.getType().equals(InterestPoint.Type.Food))
for (MobileFoe foe : foes)
if (spot.distance(foe.getPosition()) < 50)
return spot;
return null;
}
private WBPoint selectBestTargetToHelp(Mission top) {
int priority = Integer.parseInt(top.getPriority());
if (priority < 3 || points.size() == 0)
return top.getLocation();
return selectBestTargetToAttack();
}
private void SelectTarget() {
TreeMap<Double, MobileFoe> rocket = new TreeMap<Double, MobileFoe>();
TreeMap<Double, MobileFoe> foe = new TreeMap<Double, MobileFoe>();
if (getRocketNumber() == 0 || getEnergyLevel() * 1.5 < baseEnergyLevel) {
int currentEnergy = getEnergyLevel();
int maxEnergy = baseEnergyLevel;
if (currentEnergy * 1.5 < maxEnergy) {
Messenger(groupName, "Explorer", Cst.Msg.Goal.help,
String.valueOf(maxEnergy - currentEnergy));
foeToAttack = null;
return;
} else {
Messenger(groupName, "Explorer", Cst.Msg.cancel, Cst.Msg.Goal.help);
buildRocket();
if (getRocketNumber() != 0)
hasAction = true;
}
}
if (!defend)
for (InterestPoint ip : points)
if (ip.getType().equals(InterestPoint.Type.Base)
&& ip.distance(posToRef) < 150) {
MobileFoe mf = new MobileFoe(MobileFoe.Type.Default, ip.x, ip.y,
12000, true, 200);
foe.put(mf.getPosition().distance(posToRef) * mf.getHitPoint() / 2,
mf);
}
for (MobileFoe f : foes)
if (f.IsFoe() && f.getRefreshed())
if (f.getType().equals(MobileFoe.Type.Rocket)
&& f.getDirection() != -1
&& f.isApproaching(posToRef)
&& GeoUtil.areCircleSegmentIntersected(f.getPosition(),
f.getTargetPoint(80), posToRef, 12))
rocket.put(f.getDistance(posToRef), f);
else if (!f.getType().equals(MobileFoe.Type.Rocket)) {
double factor;
if (f.getType().equals(MobileFoe.Type.Explorer))
factor = f.getHitPoint() * 80 / 1000;
else
factor = f.getHitPoint() * 80 / 4000;
foe.put(f.getDistance(posToRef) * factor, f);
}
if (!rocket.isEmpty())
foeToAttack = rocket.firstEntry().getValue();
else if (!foe.isEmpty())
foeToAttack = foe.firstEntry().getValue();
else
foeToAttack = null;
if (foeToAttack != null)
broadcast(groupName, "Robot", Cst.Msg.ping);
}
private boolean shotRocket(double dir) {
if (getRocketNumber() > 0)
if (timeToReload == 0) {
attackDir = dir;
launchRocket(dir);
hasAction = true;
timeToReload = 3;
return true;
}
return false;
}
@Override
protected void CheckMessages() {
WarbotMessage msg = null;
TreeMap<KnightCandidate, Mission> boss = new TreeMap<KnightCandidate, Mission>();
ArrayList<KnightCandidate> candidatesAttack = new ArrayList<KnightCandidate>();
ArrayList<KnightCandidate> candidatesHelp = new ArrayList<KnightCandidate>();
ArrayList<KnightCandidate> candidatesFood = new ArrayList<KnightCandidate>();
// TODO: Check Message
while (!isMessageBoxEmpty()) {
msg = readMessage();
if (msg.getSender() == msg.getReceiver())
continue;
if (!MessageRefPos(msg) && !CommonMessages(msg))
if (msg.getAct().equals(Cst.Msg.goalRep)) {
AgentAddress k_aa = msg.getSender();
double k_x = msg.getFromX();
double k_y = msg.getFromY();
double k_score = DefinePriority(k_x, k_y, 1);
KnightCandidate k = new KnightCandidate(k_aa, k_score + 100
* Double.parseDouble(msg.getArg1()));
boss.put(k, new Mission(msg.getArg1(), msg.getSender(),
msg.getArg2(), toWBPoint(msg)));
Say("RLauncher receive goal response");
} else if (msg.getAct().equals(Cst.Msg.Goal.help)) {
if (missions.isEmpty()
|| Cst.Priority.compareTo(missions.first().getPriority(),
msg.getArg1()) > 0) {
WBPoint pos = msg.getLength() > 1 ? new WBPoint(
Double.parseDouble(msg.getArgN(2)), Double.parseDouble(msg
.getArgN(3))) : toWBPoint(msg);
Mission mission = new Mission(msg.getArg1(), msg.getSender(),
Cst.Msg.Goal.help, pos);
if (!missions.add(mission))
Say("Didn't add mission.");
else
send(msg.getSender(), Cst.Msg.helpRT,
new String[] { Integer.toString(getEnergyLevel()) });
} else if (msg.getSender() == missions.first().getNakamaAddress())
send(msg.getSender(), Cst.Msg.helpRT,
new String[] { Integer.toString(getEnergyLevel()) });
} else if (msg.getAct().equals(Cst.Msg.pong)) {
double radius = msg.getArg1().equals("Mobile") ? 22 : 32;
allies.put(msg.getSender(), new Ally(toWBPoint(msg), radius));
} else if (msg.getAct().equals(Cst.Msg.refreshMission)) {
if (msg.getArg1().equals(Cst.Msg.Goal.attack)
&& !missions.first().getMissionType()
.equals(Mission.MissionType.ATTACK))
send(msg.getSender(), Cst.Msg.cancel, Cst.Msg.Goal.attack);
} else if (msg.getAct().equals(Cst.Msg.attackRT)) {
double k_score = DefinePriority(msg.getFromX(), msg.getFromY(), 1);
KnightCandidate k = new KnightCandidate(msg.getSender(), k_score);
candidatesAttack.add(k);
} else if (msg.getAct().equals(Cst.Msg.helpRT)) {
int k_hp = Integer.parseInt(msg.getArg1());
double k_score = DefinePriority(msg.getFromX(), msg.getFromY(), k_hp);
KnightCandidate k = new KnightCandidate(msg.getSender(), k_score);
candidatesHelp.add(k);
} else if (msg.getAct().equals(Cst.Msg.helpRT)) {
double k_score = Integer.parseInt(msg.getArg1());
KnightCandidate k = new KnightCandidate(msg.getSender(), k_score);
candidatesFood.add(k);
} else if (msg.getAct().equals(Cst.Msg.Goal.explore))
explore = true;
}
if (candidatesAttack.size() > 0) {
Collections.sort(candidatesAttack);
int i = 1;
for (; i < candidatesAttack.size(); ++i)
send(candidatesAttack.get(i).getAgentAddr(), Cst.Msg.cancel,
new String[] { Cst.Msg.Goal.attack });
}
if (candidatesFood.size() > 0) {
Collections.sort(candidatesFood);
int i = 1;
for (; i < candidatesFood.size(); ++i)
send(candidatesFood.get(i).getAgentAddr(), Cst.Msg.cancel,
new String[] { Cst.Msg.Goal.help });
}
if (candidatesHelp.size() > 0) {
int i = 0;
for (; i < nbEnnemis && i < candidatesHelp.size(); ++i)
send(candidatesHelp.get(i).getAgentAddr(), Cst.Msg.ok,
new String[] { Cst.Msg.Goal.help });
for (; i < candidatesHelp.size(); ++i)
send(candidatesHelp.get(i).getAgentAddr(), Cst.Msg.ko,
new String[] { Cst.Msg.Goal.help });
}
if (boss.size() > 0) {
send(boss.lastKey().getAgentAddr(), Cst.Msg.ok,
new String[] { Cst.Msg.goalRep });
missions.add(boss.remove(boss.lastKey()));
for (Entry<KnightCandidate, Mission> k : boss.entrySet())
send(k.getKey().getAgentAddr(), Cst.Msg.ko,
new String[] { Cst.Msg.goalRep });
}
}
@Override
protected void ManageMissions() {
if (missions.isEmpty())
return;
Mission top = missions.first();
if (top.incrementTick().getTick() > 100) {
send(top.getNakamaAddress(), Cst.Msg.refreshMission,
top.getMissionString());
top.incrementTick().resetTick();
}
switch (top.getMissionType()) {
case ATTACK:
defend = false;
InterestPoint ip = selectBestTargetToAttack();
if (ip == null)
target = null;
else
target = new WBPoint(ip);
break;
case EXPLORE:
break;
case HELP:
defend = true;
target = selectBestTargetToHelp(top);
break;
case RECOLT:
break;
default:
break;
}
}
@Override
protected void SendHelp() {
WBPoint pos = foeAttackPos == null ? posToRef : foeAttackPos;
String[] args = new String[] { Cst.Priority.High, Double.toString(pos.x),
Double.toString(pos.y) };
if (getShot() || foeToAttack != null
&& foeToAttack.getType().equals(MobileFoe.Type.RocketLauncher))
Messenger(groupName, "Launcher", Cst.Msg.Goal.help, args);
if (!foeNear && !estAttaquee && foeToAttack == null)
Messenger(groupName, "Launcher", Cst.Msg.cancel, Cst.Msg.Goal.help);
int currentEnergy = getEnergyLevel();
int maxEnergy = baseEnergyLevel;
if (currentEnergy * 2 < maxEnergy)
Messenger(groupName, "Explorer", Cst.Msg.Goal.help,
String.valueOf(maxEnergy - currentEnergy));
else
Messenger(groupName, "Explorer", Cst.Msg.cancel, Cst.Msg.Goal.help);
}
@Override
protected void toDoWhenDead(AgentAddress dead) {
if (dead == null)
Say("Agent Address of the dead is dead");
allies.remove(dead);
return;
}
}