/**
* MovementStatistic.java
*/
package rampancy_old.statistics;
import rampancy_old.management.EnemyListener;
import rampancy_old.management.MovementManager;
import rampancy_old.util.*;
import rampancy_old.util.kdTree.*;
import robocode.util.Utils;
import java.awt.geom.Point2D;
import java.util.*;
/**
* This class tracks our movment statistics per enemy
* @author Matthew Chun-Lum
*
*/
public class MovementStatistic implements EnemyListener {
public static final int NUM_BINS = 47;
public static final int PREFERRED_TREE_SIZE = 80;
public static final int NUM_NEIGHBORS = 30;
public static final double BANDWIDTH = 1;
private String enemyName;
private KDTree<SurfPoint> clusterTree;
private int shotsFired;
private int shotsHit;
private double hitPercentage;
/**
* Default constructor
* @param enemyName
*/
public MovementStatistic(String enemyName) {
this.enemyName = enemyName;
clusterTree = new KDTree<SurfPoint>(new ArrayList<SurfPoint>(), SurfPoint.getComparators());
}
public void rebuildTree() {
List<SurfPoint> points = clusterTree.getAllPoints();
Collections.sort(points, SurfPoint.FIRE_TIME_COMPARATOR);
System.out.println("Rebuilding kd tree, using " + Math.min(PREFERRED_TREE_SIZE, points.size()) + " of the newest points");
points = points.subList(0, Math.min(PREFERRED_TREE_SIZE, points.size()));
clusterTree = new KDTree<SurfPoint>(points, SurfPoint.getComparators());
// clusterTree = new KDTree<SurfPoint>(points, Math.min(PREFERRED_TREE_SIZE, points.size()), SurfPoint.getComparators());
}
public double getHitPercentage() {
return hitPercentage;
}
/**
* @param wave
* @param target
* @return the guess factor index for a given wave and target
*/
public double getFactorIndex(EnemyWave wave, Point2D.Double target) {
double offset = wave.computeOffsetAngle(target);
double factor = Utils.normalRelativeAngle(offset) / Util.computeMaxEscapeAngle(wave.getVelocity()) * wave.getDirection();
return (int) Util.limit(0, (factor * ((NUM_BINS - 1) / 2)) + ((NUM_BINS - 1) / 2), NUM_BINS - 1);
}
/**
* Compute the danger for a given wave and location
* @param wave
* @param location
* @return the computed danger
*/
public double getDanger(EnemyWave wave, Point2D.Double location) {
SurfPoint searchPoint = new SurfPoint(wave);
searchPoint.guessFactorIndex = getFactorIndex(wave, location);
List<SurfPoint> nearestNeighbors = clusterTree.getKNearestNeighbors(searchPoint, NUM_NEIGHBORS, SurfPoint.WEIGHTED_DISTANCE_FUNCTION);
if(nearestNeighbors == null) {
return 0;
}
List<Double> distances = new ArrayList<Double>();
for(SurfPoint neighbor : nearestNeighbors) {
distances.add(searchPoint.guessFactorIndex - neighbor.guessFactorIndex);
}
double density = Util.computeDensity(distances, BANDWIDTH);
return density;
}
/**
* Notes a hit by an enemy bullet
* @param wave
* @param location
*/
public void logHit(EnemyWave wave, Point2D.Double location) {
shotsHit++;
hitPercentage = (double) shotsHit / (double) shotsFired;
logVirtualHit(wave, location);
}
/**
* Notes a virtual hit, does not update the hit percentage
* @param wave
* @param location
*/
public void logVirtualHit(EnemyWave wave, Point2D.Double location) {
SurfPoint pt = new SurfPoint(wave);
pt.guessFactorIndex = getFactorIndex(wave, location);
clusterTree.add(pt);
}
/* (non-Javadoc)
* @see rampancy.management.EnemyListener#enemyUpdated(rampancy.util.EnemyRobot)
*/
public void enemyUpdated(EnemyRobot enemy) {
if(enemy.getShotsFired() != shotsFired) {
shotsFired = enemy.getShotsFired();
hitPercentage = (double) shotsHit / (double) shotsFired;
}
}
}