package marathon.tycho;
import robocode.*;
import robocode.util.Utils;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Point2D;
import java.util.*;
public class Tycho extends AdvancedRobot {
private Point2D.Double location;
private Point2D.Double enemyLocation;
private ArrayList<Wave> enemyWaves;
private ArrayList<BulletWave> bulletWaves;
private ArrayList<Integer> surfDirections;
private ArrayList<Double> surfBearings;
private static HashMap<String, EnemyRobot>enemies = new HashMap<String, EnemyRobot>();
public int direction;
public void run() {
setInitialState();
while(getRadarTurnRemainingRadians() == 0) {
turnRadarRightRadians(Helper.MAX_RADAR_TRACKING_AMOUNT);
}
}
public void onScannedRobot(ScannedRobotEvent e) {
location = new Point2D.Double(getX(), getY());
String name = e.getName();
EnemyRobot enemy = enemies.get(name);
if(enemy == null) {
enemy = new EnemyRobot(e, this);
enemies.put(name, enemy);
} else {
enemy.update(e);
}
setTurnRadarRightRadians(Utils.normalRelativeAngle(enemy.getAbsoluteBearing() - getRadarHeadingRadians() * 2));
surf();
double power = StandardGun.getSuggestedBulletPower(enemy);
if (enemy.getVelocity() != 0) {
if (Math.sin(e.getHeadingRadians() - enemy.getAbsoluteBearing()) * e.getVelocity() < 0)
direction = -1;
else
direction = 1;
}
double[] currentStats = enemy.getGuessFactorArray();
int[] currentReadings = enemy.getCurrentReadingArray();
int currentIndex = enemy.getCurrentReadingIndex();
BulletWave newWave = new BulletWave(location, getTime(), power, enemy.getAbsoluteBearing(), direction, currentStats, currentReadings, currentIndex);
int bestindex = 15;
for (int i=0; i<31; i++)
if (currentStats[bestindex] < currentStats[i])
bestindex = i;
double guessfactor = (double)(bestindex - (Helper.GUESS_FACTORS - 1) / 2) / ((Helper.GUESS_FACTORS - 1) / 2);
double angleOffset = direction * guessfactor * Helper.maxEscapeAngle(Helper.bulletVelocity(power));
setTurnGunRightRadians(Utils.normalRelativeAngle(enemy.getAbsoluteBearing() - getGunHeadingRadians() + angleOffset));
if(e.getDistance() < 200 || Math.random() > 0.6) {
setFireBullet(power);
enemy.addIncomingBullet(newWave);
}
focusRadar(e);
}
public void onHitByBullet(HitByBulletEvent e) {
if(enemies.containsKey(e.getName())) {
enemies.get(e.getName()).processBulletHit(e);
}
setTurnRadarRightRadians(Utils.normalRelativeAngle(e.getBearingRadians() - getRadarHeadingRadians() * 2));
}
public void onHitRobot(HitRobotEvent e) {
Helper.setBackAsFront(this, -Math.PI/4);
}
public void onPaint(Graphics2D g) {
if(!enemies.isEmpty())
for(EnemyRobot enemy : enemies.values())
enemy.draw(g);
super.onPaint(g);
}
public Point2D.Double getLocation() {
return (Point2D.Double) location.clone();
}
// ---------- Private Helpers ----------- //
private void focusRadar(ScannedRobotEvent e) {
double radarBearingOffset = Utils.normalRelativeAngle(getRadarHeadingRadians() - (e.getBearingRadians() + getHeadingRadians()));
setTurnRadarLeftRadians(radarBearingOffset + (Helper.nonZeroSign(radarBearingOffset) * (Helper.MAX_RADAR_TRACKING_AMOUNT / 2)));
}
private void surf() {
Wave wave = getClosestEnemyWave();
if(wave == null)
return;
double safetyLeft = evaluateSafety(wave, -1);
double safetyRight = evaluateSafety(wave, 1);
double angle = Helper.absoluteBearing(wave.getOrigin(), location);
if(safetyLeft < safetyRight) {
angle = Helper.wallSmoothing(location, angle - (Math.PI/2), -1);
} else {
angle = Helper.wallSmoothing(location, angle + (Math.PI/2), 1);
}
Helper.setBackAsFront(this, angle);
}
/*
* Computes the best factor based on the wave in question
*/
private double evaluateSafety(Wave wave, int direction) {
int index = Helper.getFactorIndex(wave, predictPosition(wave, direction));
int distance = Helper.getDistanceSegment(wave.getOrigin().distance(location));
return wave.getEnemy().getStatistic(distance, index);
}
/*
* predicts the position
*/
private Point2D.Double predictPosition(Wave wave, int direction) {
Point2D.Double predicted = (Point2D.Double) location.clone();
double predictedVelocity = getVelocity();
double predictedHeading = getHeadingRadians();
double maxTurning, moveAngle, moveDirection;
int tickCount = 0;
while(tickCount < 500) {
moveAngle = Helper.wallSmoothing(predicted, Helper.absoluteBearing(wave.getOrigin(), predicted) + (direction * (Math.PI/2)), direction) - predictedHeading;
moveDirection = 1;
if(Math.cos(moveAngle) < 0) {
moveAngle += Math.PI;
moveDirection = -1;
}
maxTurning = Math.PI/720d*(40d - 3d * Math.abs(predictedVelocity));
predictedHeading = Utils.normalRelativeAngle(predictedHeading + Helper.limit(-maxTurning, moveAngle, maxTurning));
predictedVelocity += (predictedVelocity * moveDirection < 0 ? 2 * moveDirection : moveDirection);
predictedVelocity = Helper.limit(-8, predictedVelocity, 8);
predicted = Helper.project(predicted, predictedHeading, predictedVelocity);
tickCount++;
if (wave.intercepted(predicted, tickCount))
break;
}
return predicted;
}
/**
* Returns the closest wave
*/
private Wave getClosestEnemyWave() {
double closest = 500000;
Wave closestWave = null;
for(EnemyRobot enemy : enemies.values()) {
Wave wave = enemy.getClosestWave();
if(wave != null) {
double distance = wave.distanceFrom(location);
if(distance < closest) {
closestWave = wave;
closest = distance;
}
}
}
return closestWave;
}
private boolean facingMe(double heading) {
return false;
}
private void setInitialState() {
setColors(Color.orange, Color.yellow, Color.red, Color.white, Color.orange);
location = new Point2D.Double(getX(), getY());
enemyWaves = new ArrayList<Wave>();
bulletWaves = new ArrayList<BulletWave>();
surfDirections = new ArrayList<Integer>();
surfBearings = new ArrayList<Double>();
if(!enemies.isEmpty()) {
for(EnemyRobot enemy : enemies.values())
enemy.reset(this);
}
direction = -1;
setAdjustGunForRobotTurn(true);
setAdjustRadarForGunTurn(true);
}
}