Source code for VertiLeach V 0.3, released under the RoboWiki Public Code Licence (RWPCL). |
Source code for VertiLeach V 0.3.3, released under the RoboWiki Public Code Licence (RWPCL). There are a couple of things that might be interesting with this code: # It's from a top-10 class bot in RoboRumble@Home (and top-2 class in the MiniBots class) # It uses a simple GuessFactorTargeting gun # Rather few lines of code. Even if it has some improvements to ask for in terms of clarity, it isn't as obfuscated as some minibot code out there. |
// http://robowiki.dyndns.org/?RWPCL |
// http://robowiki.net/?RWPCL |
// Code home page: http://robowiki.dyndns.org/?VertiLeach/Code |
// Code home page: http://robowiki.net/?VertiLeach/Code |
// $Id: VertiLeach.java,v 1.5 2003/10/26 14:32:37 peter Exp $ |
// $Id: VertiLeach.java,v 1.9 2003/12/19 00:43:56 peter Exp $ |
private static final double DEFAULT_BULLET_POWER = 3.0; |
private static final double DEFAULT_BULLET_POWER = 2.8; |
private static final int MAX_FACTOR_VISITS = 255; |
private static final int VERTICAL_SEGMENTS = 11; private static final int AIM_FACTORS = 17; |
private static final int VERTICAL_SEGMENTS = 9; private static final int AIM_FACTORS = 23; |
private static Point2D oldRobotLocation? = new Point2D.Double(); private static Point2D oldEnemyLocation? = new Point2D.Double(); |
private static Point2D lastRobotLocation? = new Point2D.Double(); private static Point2D lastEnemyLocation? = new Point2D.Double(); |
private static Rectangle2D fieldRectangle; |
private static double enemyY; private static double enemyYNormal; private static double lastEnemyYNormal?; |
private static int bearingDirection; |
private static double midY; |
private static double bulletPower = DEFAULT_BULLET_POWER; private static int mostVisited; |
private Point2D robotDestination = null; private boolean shouldRam; |
fieldRectangle = new Rectangle2D.Double(0, 0 , getBattleFieldWidth?(), getBattleFieldHeight?()); |
midY = getBattleFieldHeight?() / 2; |
oldRobotLocation?.setLocation(robotLocation); |
lastRobotLocation?.setLocation(robotLocation); |
oldEnemyLocation?.setLocation(enemyLocation); |
lastEnemyLocation?.setLocation(enemyLocation); |
double delta = enemyEnergy - e.getEnergy(); if (delta >= 0.1 && delta <= 3.0) { yOffset = 150 * Math.random() - 75; |
lastEnemyYNormal? = enemyYNormal; enemyYNormal = enemyY = enemyLocation.getY(); if (enemyY > midY) { enemyYNormal = midY - (enemyY - midY); } double eDelta = enemyEnergy - e.getEnergy(); if (eDelta >= 0.1 && eDelta <= 3.0) { double maxOffset = 175 + (DEFAULT_DISTANCE - Math.min(DEFAULT_DISTANCE, enemyDistance)); yOffset = 2 * maxOffset * Math.random() - maxOffset; if (aimVerticalSegment?() < 1) { yOffset *= 0.5 * Math.abs(yOffset) * sign(midY - enemyY); } |
shouldRam = enemyEnergy == 0 || (enemyEnergy < 0.3 && robotEnergy > enemyEnergy * 11); move(); deltaBearing = Utils.normalRelativeAngle(absoluteBearing(oldRobotLocation?, enemyLocation) - absoluteBearing(oldRobotLocation?, oldEnemyLocation?)); double bulletPower = Math.min(robotEnergy / 5, Math.min(enemyEnergy / 4, DEFAULT_BULLET_POWER)); maxEnemyBearing? = Math.abs(Math.asin(MAX_VELOCITY / (bulletVelocity(bulletPower)))); |
currentAimFactors? = aimFactors[aimDirectionSegment?()] [Math.min((int)(enemyLocation.getY() / (getBattleFieldHeight?() / VERTICAL_SEGMENTS)), VERTICAL_SEGMENTS - 1)]; |
if (getTime() > 8) { move(); |
setTurnGunRightRadians?(Utils.normalRelativeAngle( enemyAbsoluteBearing? + maxEnemyBearing? * sign(deltaBearing) * mostVisitedFactor?() - getGunHeadingRadians?())); if (!shouldRam && (robotEnergy > 1.5 || enemyDistance < 200)) { if (setFireBullet(bulletPower) != null && bulletPower > 0.9) { addCustomEvent(new Wave(bulletVelocity(bulletPower))); } } |
deltaBearing = Utils.normalRelativeAngle(absoluteBearing(lastRobotLocation?, enemyLocation) - absoluteBearing(lastRobotLocation?, lastEnemyLocation?)); if (deltaBearing < 0) { bearingDirection = -1; } else if (deltaBearing > 0) { bearingDirection = 1; } bulletPower = (enemyDistance < 2 * DEFAULT_DISTANCE / 3) ? 3.0 : DEFAULT_BULLET_POWER; bulletPower = Math.min(robotEnergy / 5, Math.min(enemyEnergy / 4, bulletPower)); maxEnemyBearing? = Math.abs(Math.asin(MAX_VELOCITY / (bulletVelocity(bulletPower)))); currentAimFactors? = aimFactors[aimDirectionSegment?()][aimVerticalSegment?()]; setTurnGunRightRadians?(Utils.normalRelativeAngle( enemyAbsoluteBearing? + maxEnemyBearing? * bearingDirection * mostVisitedFactor?() - getGunHeadingRadians?())); if (setFireBullet(bulletPower) != null && bulletPower == DEFAULT_BULLET_POWER) { addCustomEvent(new Wave()); } } |
double X = enemyLocation.getX() + sign(getX() - enemyLocation.getX()) * (shouldRam ? 0 : DEFAULT_DISTANCE);; robotDestination = new Point2D.Double(X, enemyLocation.getY() + yOffset); translateInsideField?(robotDestination, WALL_MARGIN); |
Point2D robotDestination = null; double direction = 1; for (int i = 0; i < 2; i++) { double X = enemyLocation.getX() + direction * side() * DEFAULT_DISTANCE; robotDestination = new Point2D.Double(X, enemyLocation.getY() + yOffset); translateInsideField?(robotDestination, WALL_MARGIN); if (Math.abs(X - robotDestination.getX()) < 100) { break; } else { direction *= -1; } } |
int direction = 1; if (Math.abs(angle) > Math.PI / 2) { angle += Math.acos(direction = -1); } setTurnRightRadians?(Utils.normalRelativeAngle(angle)); |
double turnAngle = Math.atan(Math.tan(angle)); int direction = angle == turnAngle ? 1 : - 1; setTurnRightRadians?(turnAngle); |
int side() { return sign(getX() - enemyLocation.getX()); } |
int mostVisited = (AIM_FACTORS - 1) / 2; |
mostVisited = (AIM_FACTORS - 1) / 2; |
return (mostVisited - (AIM_FACTORS - 1D) / 2D) / ((AIM_FACTORS - 1D) / 2D); |
return ((mostVisited + 0.5) / AIM_FACTORS) * 2 - 1; |
if (factors[index] < MAX_FACTOR_VISITS) { factors[index]++; } else { decrementOtherFactors?(factors, index); } |
index = Math.min(Math.max(0, index), AIM_FACTORS - 1); if (factors[mostVisited] > 100) { for (int i = 0; i < AIM_FACTORS; i++) { if (factors[i] > 1) { factors[i] -= 2; } } } factors[index] += 2; if (index < AIM_FACTORS - 1) { factors[index + 1]++; } if (index > 0) { factors[index - 1]++; } |
void decrementOtherFactors?(int[] factors, int index) { for (int i = 0, numFactors = factors.length; i < numFactors; i++) { if (i != index && factors[i] > 0) { factors[i]--; } } |
private int aimVerticalSegment?() { int segment = Math.min((int)(enemyYNormal / (midY / VERTICAL_SEGMENTS)), VERTICAL_SEGMENTS - 1); return segment; |
double delta = enemyLocation.getY() - oldEnemyLocation?.getY(); if (delta < 0) { |
double yDelta = enemyYNormal - lastEnemyYNormal?; if (yDelta < 0) { |
else if (delta > 0) { |
else if (yDelta > 0) { |
point.setLocation(Math.max(margin, Math.min(fieldRectangle.getWidth() - margin, point.getX())), Math.max(margin, Math.min(fieldRectangle.getHeight() - margin, point.getY()))); |
point.setLocation(Math.max(margin, Math.min(getBattleFieldWidth?() - margin, point.getX())), Math.max(margin, Math.min(getBattleFieldHeight?() - margin, point.getY()))); |
FileInputStream?(getDataFile?(enemyName + ".zip"))); |
FileInputStream?(getDataFile?(enemyName))); |
ZipOutputStream? zipout = new ZipOutputStream?(new RobocodeFileOutputStream?(getDataFile?(enemyName + ".zip"))); |
ZipOutputStream? zipout = new ZipOutputStream?(new RobocodeFileOutputStream?(getDataFile?(enemyName))); |
private double bulletVelocity; private double bearingDelta; private Point2D oldRLocation = new Point2D.Double(); private Point2D oldELocation = new Point2D.Double(); private double maxBearing; |
private double wBulletVelocity?; private double wBearingDelta?; private Point2D wRobotLocation? = new Point2D.Double(); private Point2D wEnemyLocation? = new Point2D.Double(); private int wBearingDirection?; private double wMaxBearing?; |
public Wave(double bulletVelocity) { |
public Wave() { |
this.bulletVelocity = bulletVelocity; this.bearingDelta = deltaBearing; this.oldRLocation.setLocation(robotLocation); this.oldELocation.setLocation(enemyLocation); this.maxBearing = maxEnemyBearing?; |
this.wBulletVelocity? = bulletVelocity(bulletPower); this.wBearingDelta? = deltaBearing; this.wRobotLocation?.setLocation(robotLocation); this.wEnemyLocation?.setLocation(enemyLocation); this.wMaxBearing? = maxEnemyBearing?; |
this.wBearingDirection? = bearingDirection; |
if (bulletVelocity * (getTime() - wTime) > oldRLocation.distance(enemyLocation) - 10) { double bearingDiff = Utils.normalRelativeAngle(absoluteBearing(oldRLocation, enemyLocation) - absoluteBearing(oldRLocation, oldELocation)); registerFactorVisit?(wAimFactors?, (int)Math.round(Math.max(0D, Math.min(AIM_FACTORS - 1D, ((sign(bearingDelta) * bearingDiff) / maxBearing) * (AIM_FACTORS - 1D) / 2D + (AIM_FACTORS - 1D) / 2D)))); |
if (wBulletVelocity? * (getTime() - wTime) > wRobotLocation?.distance(enemyLocation) - 10) { double bearingDiff = Utils.normalRelativeAngle(absoluteBearing(wRobotLocation?, enemyLocation) - absoluteBearing(wRobotLocation?, wEnemyLocation?)); registerFactorVisit?(wAimFactors?, (int)Math.round(((((wBearingDirection? * bearingDiff) / wMaxBearing?) + 1) / 2) * wAimFactors?.length)); |
Comments, suggestions and questions are welcome |
Comments, suggestions and questions are welcome |
There are a couple of things that might be interesting with this code:
This source code is also included in the bot jar file: http://www.robocoderepository.com/Controller.jsp?submitAction=downloadClass&id=1744
package pez.mini; import robocode.*; import robocode.util.Utils; import java.awt.geom.*; import java.awt.Color; import java.util.*; import java.util.zip.*; import java.io.*; // VertiLeach, by PEZ. Stays close to you and follows your vertical movements // // This code is released under the RoboWiki Public Code Licence (RWPCL), datailed on: // http://robowiki.net/?RWPCL // // Code home page: http://robowiki.net/?VertiLeach/Code // // $Id: VertiLeach.java,v 1.9 2003/12/19 00:43:56 peter Exp $ public class VertiLeach extends AdvancedRobot { private static final double MAX_VELOCITY = 8; private static final double DEFAULT_DISTANCE = 300; private static final double DEFAULT_BULLET_POWER = 2.8; private static final double WALL_MARGIN = 50; private static final int DIRECTION_SEGMENTS = 3; private static final int VERTICAL_SEGMENTS = 9; private static final int AIM_FACTORS = 23; private static Point2D robotLocation = new Point2D.Double(); private static Point2D lastRobotLocation = new Point2D.Double(); private static Point2D lastEnemyLocation = new Point2D.Double(); private static Point2D enemyLocation = new Point2D.Double(); private static double robotEnergy; private static String enemyName = ""; private static double enemyDistance; private static double enemyEnergy; private static double enemyAbsoluteBearing; private static double enemyY; private static double enemyYNormal; private static double lastEnemyYNormal; private static double maxEnemyBearing; private static double deltaBearing; private static int bearingDirection; private static double yOffset; private static double midY; private static int[][][] aimFactors; private static double bulletPower = DEFAULT_BULLET_POWER; private static int mostVisited; private int[] currentAimFactors; public void run() { setColors(Color.red.darker().darker(), Color.green.darker().darker(), Color.gray.darker().darker()); setAdjustGunForRobotTurn(true); setAdjustRadarForGunTurn(true); midY = getBattleFieldHeight() / 2; do { turnRadarRightRadians(Double.POSITIVE_INFINITY); } while (true); } public void onScannedRobot(ScannedRobotEvent e) { if (enemyName == "") { enemyName = e.getName(); restoreFactors(); } lastRobotLocation.setLocation(robotLocation); robotLocation.setLocation(getX(), getY()); enemyAbsoluteBearing = getHeadingRadians() + e.getBearingRadians(); enemyDistance = e.getDistance(); lastEnemyLocation.setLocation(enemyLocation); toLocation(enemyAbsoluteBearing, enemyDistance, robotLocation, enemyLocation); lastEnemyYNormal = enemyYNormal; enemyYNormal = enemyY = enemyLocation.getY(); if (enemyY > midY) { enemyYNormal = midY - (enemyY - midY); } double eDelta = enemyEnergy - e.getEnergy(); if (eDelta >= 0.1 && eDelta <= 3.0) { double maxOffset = 175 + (DEFAULT_DISTANCE - Math.min(DEFAULT_DISTANCE, enemyDistance)); yOffset = 2 * maxOffset * Math.random() - maxOffset; if (aimVerticalSegment() < 1) { yOffset *= 0.5 * Math.abs(yOffset) * sign(midY - enemyY); } } enemyEnergy = e.getEnergy(); robotEnergy = getEnergy(); if (getTime() > 8) { move(); deltaBearing = Utils.normalRelativeAngle(absoluteBearing(lastRobotLocation, enemyLocation) - absoluteBearing(lastRobotLocation, lastEnemyLocation)); if (deltaBearing < 0) { bearingDirection = -1; } else if (deltaBearing > 0) { bearingDirection = 1; } bulletPower = (enemyDistance < 2 * DEFAULT_DISTANCE / 3) ? 3.0 : DEFAULT_BULLET_POWER; bulletPower = Math.min(robotEnergy / 5, Math.min(enemyEnergy / 4, bulletPower)); maxEnemyBearing = Math.abs(Math.asin(MAX_VELOCITY / (bulletVelocity(bulletPower)))); currentAimFactors = aimFactors[aimDirectionSegment()][aimVerticalSegment()]; setTurnGunRightRadians(Utils.normalRelativeAngle( enemyAbsoluteBearing + maxEnemyBearing * bearingDirection * mostVisitedFactor() - getGunHeadingRadians())); if (setFireBullet(bulletPower) != null && bulletPower == DEFAULT_BULLET_POWER) { addCustomEvent(new Wave()); } } setTurnRadarRightRadians(Utils.normalRelativeAngle(enemyAbsoluteBearing - getRadarHeadingRadians()) * 2); } public void onWin(WinEvent e) { saveFactors(); } public void onDeath(DeathEvent e) { saveFactors(); } private void move() { Point2D robotDestination = null; double direction = 1; for (int i = 0; i < 2; i++) { double X = enemyLocation.getX() + direction * side() * DEFAULT_DISTANCE; robotDestination = new Point2D.Double(X, enemyLocation.getY() + yOffset); translateInsideField(robotDestination, WALL_MARGIN); if (Math.abs(X - robotDestination.getX()) < 100) { break; } else { direction *= -1; } } goTo(robotDestination); } void goTo(Point2D destination) { double angle = Utils.normalRelativeAngle(absoluteBearing(robotLocation, destination) - getHeadingRadians()); double turnAngle = Math.atan(Math.tan(angle)); int direction = angle == turnAngle ? 1 : - 1; setTurnRightRadians(turnAngle); setAhead(robotLocation.distance(destination) * direction); } int side() { return sign(getX() - enemyLocation.getX()); } double mostVisitedFactor() { mostVisited = (AIM_FACTORS - 1) / 2; for (int i = 0; i < AIM_FACTORS; i++) { if (currentAimFactors[i] > currentAimFactors[mostVisited]) { mostVisited = i; } } return ((mostVisited + 0.5) / AIM_FACTORS) * 2 - 1; } void registerFactorVisit(int[] factors, int index) { index = Math.min(Math.max(0, index), AIM_FACTORS - 1); if (factors[mostVisited] > 100) { for (int i = 0; i < AIM_FACTORS; i++) { if (factors[i] > 1) { factors[i] -= 2; } } } factors[index] += 2; if (index < AIM_FACTORS - 1) { factors[index + 1]++; } if (index > 0) { factors[index - 1]++; } } private int aimVerticalSegment() { int segment = Math.min((int)(enemyYNormal / (midY / VERTICAL_SEGMENTS)), VERTICAL_SEGMENTS - 1); return segment; } private int aimDirectionSegment() { double yDelta = enemyYNormal - lastEnemyYNormal; if (yDelta < 0) { return 0; } else if (yDelta > 0) { return 2; } return 1; } private void translateInsideField(Point2D point, double margin) { point.setLocation(Math.max(margin, Math.min(getBattleFieldWidth() - margin, point.getX())), Math.max(margin, Math.min(getBattleFieldHeight() - margin, point.getY()))); } private double bulletVelocity(double power) { return 20 - 3 * power; } private int sign(double v) { return v > 0 ? 1 : -1; } private void toLocation(double angle, double length, Point2D sourceLocation, Point2D targetLocation) { targetLocation.setLocation(sourceLocation.getX() + Math.sin(angle) * length, sourceLocation.getY() + Math.cos(angle) * length); } private double absoluteBearing(Point2D source, Point2D target) { return Math.atan2(target.getX() - source.getX(), target.getY() - source.getY()); } void restoreFactors() { try { ZipInputStream zipin = new ZipInputStream(new FileInputStream(getDataFile(enemyName))); zipin.getNextEntry(); ObjectInputStream in = new ObjectInputStream(zipin); aimFactors = (int[][][])in.readObject(); in.close(); } catch (Exception e) { aimFactors = new int[DIRECTION_SEGMENTS][VERTICAL_SEGMENTS][AIM_FACTORS]; } } void saveFactors() { try { ZipOutputStream zipout = new ZipOutputStream(new RobocodeFileOutputStream(getDataFile(enemyName))); zipout.putNextEntry(new ZipEntry("aimFactors")); ObjectOutputStream out = new ObjectOutputStream(zipout); out.writeObject(aimFactors); out.flush(); zipout.closeEntry(); out.close(); } catch (IOException e) { } } class Wave extends Condition { private long wTime; private double wBulletVelocity; private double wBearingDelta; private Point2D wRobotLocation = new Point2D.Double(); private Point2D wEnemyLocation = new Point2D.Double(); private int wBearingDirection; private double wMaxBearing; int[] wAimFactors; public Wave() { this.wTime = getTime(); this.wBulletVelocity = bulletVelocity(bulletPower); this.wBearingDelta = deltaBearing; this.wRobotLocation.setLocation(robotLocation); this.wEnemyLocation.setLocation(enemyLocation); this.wMaxBearing = maxEnemyBearing; this.wAimFactors = currentAimFactors; this.wBearingDirection = bearingDirection; } public boolean test() { if (wBulletVelocity * (getTime() - wTime) > wRobotLocation.distance(enemyLocation) - 10) { double bearingDiff = Utils.normalRelativeAngle(absoluteBearing(wRobotLocation, enemyLocation) - absoluteBearing(wRobotLocation, wEnemyLocation)); registerFactorVisit(wAimFactors, (int)Math.round(((((wBearingDirection * bearingDiff) / wMaxBearing) + 1) / 2) * wAimFactors.length)); removeCustomEvent(this); } return false; } } }