package pez.mini; import robocode.*; import java.awt.geom.*; import java.awt.Color; import java.util.*; // Gouldingi, by PEZ. Small, hard to catch and sharp teeth. // $Id: Gouldingi.java,v 1.9 2003/04/18 10:08:30 peter Exp $ public class Gouldingi extends AdvancedRobot { private static Point2D location = new Point2D.Double(); private static Point2D oldLocation = new Point2D.Double(); private static Point2D enemyLocation = new Point2D.Double(); private static Point2D oldEnemyLocation = new Point2D.Double(); private static Rectangle2D fieldRectangle; private static double guessedHeading; private static double enemyDistance; private static double enemyEnergy; private static double absoluteBearing; private static double deltaBearing; private static double meanOffsetFactor; private static double meanAimFactorLeft; private static double meanAimFactorStraight; private static double meanAimFactorRight; private static double velocity; public void run() { fieldRectangle = new Rectangle2D.Double(0, 0 , getBattleFieldWidth(), getBattleFieldHeight()); setColors(Color.gray, Color.yellow, Color.black); setAdjustGunForRobotTurn(true); setAdjustRadarForGunTurn(true); turnRadarRightRadians(Double.POSITIVE_INFINITY); while (true) { if (Math.random() < 0.05) { velocity = Math.min(8, Math.random() * 24); } setMaxVelocity(Math.abs(getTurnRemaining()) > 45 ? 0.1 : velocity); if (getOthers() == 0) { moveRandomly(); } execute(); } } public void onScannedRobot(ScannedRobotEvent e) { oldLocation.setLocation(location); location.setLocation(getX(), getY()); oldEnemyLocation.setLocation(enemyLocation); absoluteBearing = getHeading() + e.getBearing(); enemyEnergy = e.getEnergy(); enemyDistance = e.getDistance(); toLocation(absoluteBearing, enemyDistance, location, enemyLocation); deltaBearing = normalRelativeAngle(absoluteBearing(oldLocation, enemyLocation) - absoluteBearing(oldLocation, oldEnemyLocation)); aimGun(); moveRandomly(); if (enemyEnergy > 0 && (getEnergy() > 0.2 || enemyDistance < 150)) { Bullet bullet = setFireBullet(bulletPower(enemyEnergy)); if (bullet != null) { addCustomEvent(new CheckUpdateFactors(bullet)); } } setTurnRadarLeftRadians(getRadarTurnRemaining()); } private void moveRandomly() { if (Math.abs(getDistanceRemaining()) < Math.random() * 50) { Point2D dLocation = new Point2D.Double(); double relativeAngle = -36 + 72 * Math.random(); double distanceExtra = 3; double angle = absoluteBearing + 180 + relativeAngle; if (isCornered() || enemyDistance > 600) { distanceExtra = -1; } if (enemyEnergy == 0 && getOthers() == 1) { distanceExtra = -10; } distanceExtra *= Math.abs(relativeAngle); toLocation(angle, enemyDistance + distanceExtra, enemyLocation, dLocation); if (!fieldRectangle.contains(dLocation)) { angle = absoluteBearing + 180 - relativeAngle; toLocation(angle, enemyDistance + distanceExtra, enemyLocation, dLocation); } translateInsideField(dLocation, 35); goTo(dLocation); } } private double bulletPower(double enemyEnergy) { double power = 3; power = Math.min(enemyEnergy / 4, power); power = Math.min(getEnergy() / 3, power); return power; } private void aimGun() { double guessedDistance = location.distance(enemyLocation); double meanAimFactor = meanAimFactorStraight; if (deltaBearing < -0.3) { meanAimFactor = meanAimFactorLeft; } else if (deltaBearing > 0.3) { meanAimFactor = meanAimFactorRight; } guessedHeading = absoluteBearing(location, enemyLocation); if (Math.abs(deltaBearing) > 0.05) { guessedHeading += deltaBearing * meanAimFactor; } else { guessedHeading += meanOffsetFactor; } Point2D impactLocation = new Point2D.Double(); toLocation(guessedHeading, guessedDistance, location, impactLocation); translateInsideField(impactLocation, 1); guessedHeading = absoluteBearing(location, impactLocation); setTurnGunRight(normalRelativeAngle(guessedHeading - getGunHeading())); } private void goTo(Point2D point) { double distance = location.distance(point); double angle = normalRelativeAngle(absoluteBearing(location, point) - getHeading()); if (Math.abs(angle) > 90) { distance *= -1; if (angle > 0) { angle -= 180; } else { angle += 180; } } setTurnRight(angle); setAhead(distance); } private boolean isCornered() { double m = 100; double mnX = m; double mnY = m; double mxX = fieldRectangle.getWidth() - m; double mxY = fieldRectangle.getHeight() - m; double x = location.getX(); double y = location.getY(); return ((x < mnX && (y < mnY || y > mxY)) || (x > mxX && (y < mnY || y > mxY))); } private void translateInsideField(Point2D point, double margin) { point.setLocation(Math.max(margin, Math.min(fieldRectangle.getWidth() - margin, point.getX())), Math.max(margin, Math.min(fieldRectangle.getHeight() - margin, point.getY()))); } private void toLocation(double angle, double length, Point2D sourceLocation, Point2D targetLocation) { targetLocation.setLocation(sourceLocation.getX() + Math.sin(Math.toRadians(angle)) * length, sourceLocation.getY() + Math.cos(Math.toRadians(angle)) * length); } private double absoluteBearing(Point2D source, Point2D target) { return Math.toDegrees(Math.atan2(target.getX() - source.getX(), target.getY() - source.getY())); } private double normalRelativeAngle(double angle) { angle = Math.toRadians(angle); return Math.toDegrees(Math.atan2(Math.sin(angle), Math.cos(angle))); } public double rollingAvg(double value, double newEntry, double n, double weighting ) { return (value * n + newEntry * weighting)/(n + weighting); } class CheckUpdateFactors extends Condition { private long time; private double bulletVelocity; private double bulletPower; private double bearingDelta; private Point2D oldRLocation = new Point2D.Double(); private Point2D oldELocation = new Point2D.Double(); private double oldBearing; public CheckUpdateFactors(Bullet bullet) { this.time = getTime(); this.bulletVelocity = bullet.getVelocity(); this.bulletPower = bullet.getPower(); this.bearingDelta = deltaBearing; this.oldRLocation.setLocation(location); this.oldELocation.setLocation(enemyLocation); this.oldBearing = absoluteBearing(oldRLocation, oldELocation); } public boolean test() { if (bulletVelocity * (getTime() - time) > oldRLocation.distance(enemyLocation) - 10) { double impactBearing = absoluteBearing(oldRLocation, enemyLocation); double bearingDiff = normalRelativeAngle(impactBearing - oldBearing); meanOffsetFactor = rollingAvg(meanOffsetFactor, bearingDiff, 20, bulletPower); if (Math.abs(bearingDelta) > 0.05) { double factor = bearingDiff / bearingDelta; if (bearingDelta < -0.3) { meanAimFactorLeft = rollingAvg(meanAimFactorLeft, factor, 75, bulletPower); } else if (bearingDelta > 0.3) { meanAimFactorRight = rollingAvg(meanAimFactorRight, factor, 75, bulletPower); } else { meanAimFactorStraight = rollingAvg(meanAimFactorStraight, factor, 75, bulletPower); } } removeCustomEvent(this); } return false; } } }