Basilisk/Code
Jump to navigation
Jump to search
Version 2.35
package slugzilla;
import robocode.*;
import java.awt.geom.*;
import robocode.util.*;
import java.awt.*;
import static robocode.util.Utils.normalRelativeAngleDegrees;
import robocode.BulletHitEvent;
import robocode.HitByBulletEvent;
public class Basilisk extends AdvancedRobot {
private static double lateralDirection;
private static double lastEnemyVelocity;
static double enemyFirePower;
static double enemyBulletVelocity;
double enemyDistance;
double enemyAbsoluteBearing;
double enemyVelocity;
static double direction = 1;
static int movementMode;
static double hits;
private static double enemyEnergy;
static double deltaT;
static double lastDeltaT;
static double lastReverseTime;
static double firePower;
public void run() {
setAdjustRadarForGunTurn(true);
setAdjustGunForRobotTurn(true);
setBodyColor(new Color(40, 100, 100));
setGunColor(new Color(34, 50, 50));
setRadarColor(new Color(0, 255, 0));
setScanColor(new Color(0, 255, 0));
turnRadarRightRadians(Double.POSITIVE_INFINITY);
do {
scan();
} while (true);
}
public void onScannedRobot(ScannedRobotEvent e) {
//radar ↓
double radarTurn = getHeadingRadians() + e.getBearingRadians() - getRadarHeadingRadians();
setTurnRadarRightRadians(Utils.normalRelativeAngle(radarTurn));
//movement ↓
double v2;
double offset;
double theta = 0.5952*(20D - 3D*enemyFirePower)/enemyDistance;
if (movementMode >= 1) {
offset = 2 + 100/e.getDistance();
} else {
//offset = 1.5 + 100/e.getDistance();
offset = 2 + (int)(100/e.getDistance());
}
enemyAbsoluteBearing = getHeadingRadians() + e.getBearingRadians();
double v1 = enemyAbsoluteBearing;
enemyDistance = e.getDistance();
enemyVelocity = e.getVelocity();
enemyBulletVelocity = 20 - 3 * enemyFirePower;
if (enemyEnergy > e.getEnergy() && enemyEnergy - 3 <= e.getEnergy()) {
enemyFirePower = enemyEnergy - e.getEnergy();
}
while(!new Rectangle2D.Double(18, 18, 764, 564).
contains(getX() + 160 * Math.sin(v2 = v1 + direction * (offset -= .02)), getY() + 160 * Math.cos(v2)));
if (offset < 0.75) {
direction = -direction;
lastDeltaT = deltaT;
lastReverseTime = getTime();
}
setTurnRightRadians(Math.tan(v2 -= getHeadingRadians()));
deltaT = getTime() - lastReverseTime;
if(movementMode >= 1) {
setAhead(1000 * Math.cos(v2));
if (Math.random() > Math.pow(theta, theta) && enemyDistance > 100) {
if (deltaT >= lastDeltaT +2 || deltaT <= lastDeltaT -2) {
direction = -direction;
lastDeltaT = deltaT;
lastReverseTime = getTime();
}
}
} else {
double energyDrop = enemyEnergy - e.getEnergy();
if ((int)(100/enemyDistance) + energyDrop > 0) {
setAhead(((3 + (int)(energyDrop * 1.999999)) << 3 ) * Math.signum(Math.cos(v2)));
}
}
enemyEnergy = e.getEnergy();
//gun ↓
double enemyLateralVelocity = e.getVelocity() * Math.sin(e.getHeadingRadians() - enemyAbsoluteBearing);
if (enemyVelocity != 0) {
lateralDirection = GFTUtils.sign(enemyVelocity * Math.sin(e.getHeadingRadians() - enemyAbsoluteBearing));
}
GFTWave wave = new GFTWave(this);
wave.bulletPower = Math.min(Math.min(e.getEnergy()/4, getEnergy()/8), Math.min(0.05 * Math.round((1.8+100/enemyDistance)/0.05), 3));
firePower = wave.bulletPower;
wave.MAX_ESCAPE_ANGLE = (Math.asin(8/(20 - 3 * wave.bulletPower)));
wave.BIN_WIDTH = wave.MAX_ESCAPE_ANGLE / wave.MIDDLE_BIN;
wave.gunLocation = new Point2D.Double(getX(), getY());
GFTWave.targetLocation = GFTUtils.project(wave.gunLocation, enemyAbsoluteBearing, enemyDistance);
wave.lateralDirection = lateralDirection;
wave.setSegmentations(enemyDistance, enemyVelocity, lastEnemyVelocity, enemyLateralVelocity);
lastEnemyVelocity = enemyVelocity;
wave.bearing = enemyAbsoluteBearing;
setTurnGunRightRadians(Utils.normalRelativeAngle(enemyAbsoluteBearing - getGunHeadingRadians() + wave.mostVisitedBearingOffset()) + ((Math.random()/500)-0.002));
if (getEnergy() > 0.4) {
//fire at will! ↓
setFire(wave.bulletPower);
}
if (getEnergy() >= wave.bulletPower) {
addCustomEvent(wave);
}
}
//movement ↓
public void onHitByBullet(HitByBulletEvent e) {
//enemyEnergy += 3 * enemyFirePower;
enemyEnergy -= Rules.getBulletDamage(e.getBullet().getPower());
if ((hits += (4.25 / enemyBulletVelocity)) > getRoundNum() + 1) {
movementMode++;
}
}
public void onBulletHit(BulletHitEvent e) {
//enemyEnergy -= 4 * firePower + firePower > 1 ? 2 * firePower - 1 : 0;
enemyEnergy -= Rules.getBulletDamage(e.getBullet().getPower());
}
}
//gun ↓
class GFTWave extends Condition {
static Point2D targetLocation;
double bulletPower;
Point2D gunLocation;
double bearing;
double lateralDirection;
// 1000 is the maximum space away in a 800 by 600 battlefield
private static final double MAX_DISTANCE = 1000;
//segment into 5 sections ↓
private static final int DISTANCE_INDEXES = 5;
private static final int VELOCITY_INDEXES = 5;
private static final int ACCELERATION_INDEXES = 3;
private static final int LATERAL_VELOCITY_INDEXES = 5;
static final int BINS = 25;
static final int MIDDLE_BIN = (BINS - 1) / 2;
static double MAX_ESCAPE_ANGLE;
static double BIN_WIDTH;
private static double[][][][][][] statBuffers = new double[DISTANCE_INDEXES][VELOCITY_INDEXES][VELOCITY_INDEXES][ACCELERATION_INDEXES][LATERAL_VELOCITY_INDEXES][BINS];
private double[] buffer;
private AdvancedRobot robot;
private double distanceTraveled;
GFTWave(AdvancedRobot _robot) {
this.robot = _robot;
}
public boolean test() {
advance();
//remove passed waves
if (hasArrived()) {
//buffer[currentBin()]++;
// value = buffer[currentBin()]
// newValue = .9*value +1
// buffer[currentBin()] = newValue
for (int i = 0; i < BINS; i++) {
buffer[i] = 0.95 * buffer[i];
}
buffer[currentBin()] += 1;
robot.removeCustomEvent(this);
}
return false;
}
double mostVisitedBearingOffset() {
return (lateralDirection * BIN_WIDTH) * (mostVisitedBin() - MIDDLE_BIN);
}
void setSegmentations(double distance, double velocity, double lastVelocity, double lateralVelocity) {
int distanceIndex = (int)(distance / (MAX_DISTANCE / DISTANCE_INDEXES));
int velocityIndex = (int)Math.abs(velocity / 2);
int lastVelocityIndex = (int)Math.abs(lastVelocity / 2);
int deltaTime;
if (velocityIndex < lastVelocityIndex) {
deltaTime = 0;
} else if (velocityIndex > lastVelocityIndex) {
deltaTime = 1;
} else {
deltaTime = 2;
}
int accelerationIndex = deltaTime;
int lateralVelocityIndex = (int)Math.abs(lateralVelocity / 2);
buffer = statBuffers[distanceIndex][velocityIndex][lastVelocityIndex][accelerationIndex][lateralVelocityIndex];
}
private void advance() {
distanceTraveled += GFTUtils.bulletVelocity(bulletPower);
}
private boolean hasArrived() {
return distanceTraveled > gunLocation.distance(targetLocation) - 18;
}
private int currentBin() {
int bin = (int)Math.round((
(Utils.normalRelativeAngle(GFTUtils.absoluteBearing(gunLocation, targetLocation) - bearing))
/ (lateralDirection * BIN_WIDTH)
) + MIDDLE_BIN);
return GFTUtils.minMax(bin, 0, BINS - 1);
}
private int mostVisitedBin() {
int mostVisited = MIDDLE_BIN;
for (int i = 0; i < BINS; i++) {
if (buffer[i] > buffer[mostVisited]) {
mostVisited = i;
}
}
return mostVisited;
}
}
//helpful utilities ↓
class GFTUtils {
static double bulletVelocity(double power) {
return 20 - 3 * power;
}
static Point2D project(Point2D sourceLocation, double angle, double length) {
return new Point2D.Double(sourceLocation.getX() + Math.sin(angle) * length,
sourceLocation.getY() + Math.cos(angle) * length);
}
static double absoluteBearing(Point2D source, Point2D target) {
return Math.atan2(target.getX() - source.getX(), target.getY() - source.getY());
}
static int sign(double v) {
return v < 0 ? -1 : 1;
}
static int minMax(int v, int min, int max) {
return Math.max(min, Math.min(max, v));
}
}