/**
*
*/
package rampancy.util.weapon;
import rampancy.RampantRobot;
import rampancy.standard.*;
import rampancy.util.*;
import rampancy.util.wave.RBulletWave;
import rampancy_old.util.Util;
import robocode.util.Utils;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.GeneralPath;
import java.util.*;
/**
* @author Matthew Chun-Lum
*
*/
public class RDCGun extends RGun {
public static final String DC_GUN = "dynamic clustering gun";
private RDefaultKDTree kdTree;
public RDCGun() {
super(DC_GUN);
kdTree = new RDefaultKDTree();
}
/* (non-Javadoc)
* @see rampancy.util.weapon.RGun#getFiringSolution(rampancy.util.REnemyRobot)
*/
@Override
public RFiringSolution getFiringSolution(REnemyRobot enemy) {
RRobotState enemyState = enemy.getCurrentState();
ArrayList<RDefaultKDPoint> points = kdTree.getNearestPoints(enemyState);
double bestGuessFactor = 0;
double bestProbability = 0.5;
double[] probabilityDensity = new double[201];
if(!points.isEmpty()) {
double p = -1.0;
for(int i = 0; i < 201; i++) {
probabilityDensity[i] = kernelDensityEstimate(p, points, 36.0/enemyState.distance);
if(probabilityDensity[i] > bestProbability) {
bestGuessFactor = p;
bestProbability = probabilityDensity[i];
}
p += 0.01;
}
}
double power;
if(enemyState.distance < 100) {
power = 3.0;
} else {
power = (1 - enemyState.distance / 1500.0) * 3.0;
}
power = Util.limit(0.1, power, 3.0);
double maxEscapeAngle = RUtil.computeMaxEscapeAngle(RUtil.computeBulletVelocity(power));
double offsetAngle = enemyState.directionTraveling * bestGuessFactor * maxEscapeAngle;
offsetAngle = Utils.normalRelativeAngle(offsetAngle);
double maxPreciseEscapeAngle = RUtil.computePreciceMaxEscapeAngle(RUtil.computeBulletVelocity(power),
enemy.getReference(), enemy, RUtil.nonZeroSign(enemyState.directionTraveling * bestGuessFactor));
double preciseOffsetAngle = enemyState.directionTraveling * bestGuessFactor *maxPreciseEscapeAngle;
preciseOffsetAngle = Utils.normalRelativeAngle(preciseOffsetAngle);
double gunBearingToTarget = enemyState.absoluteBearing - enemy.getReference().getGunHeadingRadians();
gunBearingToTarget = Utils.normalRelativeAngle(gunBearingToTarget);
DCDrawableObject drawableObject = null;//new DCDrawableObject(probabilityDensity);
return new RFiringSolution(null, power, gunBearingToTarget + preciseOffsetAngle, bestProbability, bestGuessFactor, Color.cyan, this, drawableObject);
}
/* (non-Javadoc)
* @see rampancy.util.weapon.RGun#update(rampancy.util.wave.RBulletWave)
*/
@Override
public void update(RBulletWave wave) {
super.update(wave);
double desiredDirection = RUtil.computeAbsoluteBearing(wave.getOrigin(), wave.getTarget().getLastState().location);
double angleOffset = Utils.normalRelativeAngle(desiredDirection - wave.getTargetState().absoluteBearing);
double guessFactor = Math.max(-1, Math.min(1, angleOffset / RUtil.computeMaxEscapeAngle(wave.getVelocity()))) * wave.getTargetState().directionTraveling;
kdTree.addPoint(wave.getTargetState(), guessFactor);
}
private double kernelDensityEstimate(double targetGuessFactor, ArrayList<RDefaultKDPoint> points, double bandwidth) {
double scale = 1.0 / (points.size() * bandwidth * Math.sqrt(2 * Math.PI));
double sigma = 0;
for(RDefaultKDPoint point : points) {
sigma += Math.exp(-RUtil.square(targetGuessFactor - point.guessFactor) / (2.0 * bandwidth * bandwidth));
}
return scale * sigma;
}
/* (non-Javadoc)
* @see rampancy.util.weapon.RGun#updateNewRound()
*/
@Override
public void updateNewRound() {
kdTree.rebalance();
}
class DCDrawableObject implements RDrawableObject {
public double[] probabilityDensity;
public GeneralPath curve;
public double max;
public int max_index;
public DCDrawableObject(double[] probabilityDensity) {
this.probabilityDensity = Arrays.copyOf(probabilityDensity, probabilityDensity.length);
max = 0;
max_index = 0;
for(int i = 0; i < probabilityDensity.length; i++)
if(probabilityDensity[i] > max) {
max = probabilityDensity[i];
max_index = i;
}
// normalize
if(max != 0)
for(int i = 0; i < probabilityDensity.length; i++)
this.probabilityDensity[i] = (probabilityDensity[i] / max) * 200.0;
curve = new GeneralPath(GeneralPath.WIND_EVEN_ODD, probabilityDensity.length);
curve.moveTo(0, 0);
for(int i = 0; i < probabilityDensity.length; i += 3) {
curve.lineTo(i * .39, Math.round(this.probabilityDensity[i]));
}
}
public void draw(Graphics2D g) {
Color lastColor = g.getColor();
g.setColor(Color.white);
g.draw(curve);
g.setColor(Color.red);
RUtil.drawOval(new RPoint(max_index * 12 + 10, probabilityDensity[max_index]), 3, g);
g.setColor(lastColor);
}
}
}