|
|
Line 3: |
Line 3: |
| | parent = Basilisk | | | parent = Basilisk |
| | page1 = Version History | | | page1 = Version History |
| + | | page2 = Code |
| }} | | }} |
| | | |
Line 75: |
Line 76: |
| Special thanks to Dsekercioglu for help identifying bugs and beating bullet shielders =) | | Special thanks to Dsekercioglu for help identifying bugs and beating bullet shielders =) |
| | | |
− | == Code ==
| |
− |
| |
− | '''Version 2.35'''
| |
− |
| |
− | <syntaxhighlight>
| |
− | 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));
| |
− | }
| |
− | }
| |
− | </syntaxhighlight>
| |
| [[Category:MiniBots]] | | [[Category:MiniBots]] |
| [[Category:Bots]] | | [[Category:Bots]] |
| [[Category:1-vs-1 Bots]] | | [[Category:1-vs-1 Bots]] |