Code for version .83 |
Code for version .90 |
/** * BlackPearl is derived from Jekyl in many ways. It also serves as a proving ground for new concepts * that may one day find thier way into Jekyl. It is a pretty complete robot. If you use any of the code * contained in this bot I only ask that you let me see what it is you changed to make it better. Seeing * your whole bot would be nice but is not a requirement. I would also appreciate it if you would help me * to learn from your experiences in return as well. If you use this please take the time to send me an * email or an IM. -- jim */ |
private static final double MAX_STAND_OFF_DISTANCE = 500D; private static final double MIN_STAND_OFF_DISTANCE = 400D; private static final double MOVEMENT_DISTANCE = 21D; private static final double GUESS_FACTORS = 25D; private static final double MAX_SHOT_POWER = 3D; private static final double FIRE_POWER_NUMERATOR = 1000D; private static final double WALL_CURVE_DISTANCE = 117D; //pixels private static final double MIN_GRAZE_ANGLE = 0.52359; //30 private static final double MAX_GRAZE_ANGLE = 2.61799; //150 //private static final double MIN_GRAZE_ANGLE = 1.0479D; //60 degrees in radians //private static final double MAX_GRAZE_ANGLE = 2.0943D; //120 degrees in radians private static final double BEND_ANGLE = 0.0698D; //4 degrees in radians |
private static final double MAX_STAND_OFF_DISTANCE = 600D; private static final double MIN_STAND_OFF_DISTANCE = 500D; private static final double GUESS_FACTORS = 23D; private static final double MIDDLE_FACTOR = (GUESS_FACTORS -1) / 2; private static final double WALL_CURVE_DISTANCE = 180D; //pixels |
private static int statBuffer[][][][]; |
private static int statBuffer[][][][][][]; |
private static boolean save; |
private double eEnergy, eLastEnergy? = 100D; private double eX, eY, eDelta, eAbsBearing?, eVelocity, eDistance, eBearing, eLastVelocity?; |
private double eEnergy = 100D; private double eX, eY, eDelta, eAbsBearing?, eVelocity, eDistance, eHeading; |
private long lastReverseTime?; |
private static int ticksSinceReverse? = 0; int lastLatVelIndex? = 0; |
save = (getOthers() == 1); //Only? save data if we are in a 1-v-1 engagement, otherwise the data will be polluted |
double latVel = (eVelocity = e.getVelocity()) * Math.sin(e.getHeadingRadians() - (eAbsBearing? = Utils.normalRelativeAngle(getHeadingRadians() + (eBearing = e.getBearingRadians?())))); |
if (Math.abs(eVelocity) > Math.abs(eVelocity = e.getVelocity())) { ticksSinceReverse? = 0; } double latVel = (eVelocity) * Math.sin(eHeading = e.getHeadingRadians() - (eAbsBearing? = Utils.normalRelativeAngle(getHeadingRadians() + (e.getBearingRadians?())))); |
double accelDiff = Math.round(Math.abs(eVelocity) - Math.abs(eLastVelocity?)); eDirection = (latVel >= 0 ? 1 : -1); |
//Set? the firePower double firePower = Math.max(Math.min(Math.min(Math.min(getEnergy() * .2, (eEnergy = e.getEnergy()) * .25), FIRE_POWER_NUMERATOR/eDistance), MAX_SHOT_POWER), .1); |
//Keep? the sign of the direction last used if latVel is zero if (latVel != 0) { eDirection = (int)(Math.abs(latVel) / latVel); } |
int latVelIndex? = (int) (Math.abs(latVel) / 3); int accellIndex = (accelDiff == 0 ? 0 : (accelDiff > 0 ? 2 : 1)); int distanceIndex = (int)(Math.min(11, (eDistance / 100D))); //Movement? double turnTo = getTurnAngle?(); setTurnRightRadians?(Utils.normalRelativeAngle(turnTo)); |
int distanceIndex = (int)Math.min(4, eDistance / 180D); |
if ((eDelta = eLastEnergy? - eEnergy) > 0 && eDelta <= 3) { |
if ((eDelta = eEnergy - (eEnergy = e.getEnergy())) > 0 && eDelta <= 3) { |
//This? is an adaptation from Raiko. If you can't beat 'em, join 'em double theta = .64 * bulletV(eLastShot?)/eDistance; if ((Math.random() > Math.pow(theta, theta) && flatten)) { reverse(); } else if (out(MOVEMENT_DISTANCE * direction, turnTo)) { reverse(); |
//Set? the firePower double firePower = (distanceIndex <=1 ? 3.0 : 1.9); //double firePower = (getEnergy() > 0 ? 3.0 : 0); //Movement? //This? is an adaptation from Raiko. If you can't beat 'em, join 'em double distDelta = 0.02 + Math.PI/2 + (e.getDistance() > 400 ? -.1 : .5); double theta = 0.5952*bulletV(eLastShot?)/eDistance; if ( (Math.random() > Math.pow(theta, theta) && flatten)|| distDelta < Math.PI/4 || (distDelta < Math.PI/3 && eDistance < 400)){ //double theta = .64 * bulletV(eLastShot?)/eDistance; //if ((Math.random() > Math.pow(theta, theta) && flatten)) { direction = -direction; |
setAhead(Math.cos(turnTo)*100*direction); //setAhead(MOVEMENT_DISTANCE * direction); |
goTo(getDestination(new Point2D.Double(getX(), getY()),direction)); |
statBuffer = (int[][][][]) readObject(targetName); |
statBuffer = (int[][][][][][]) readObject(targetName); |
int stats[] = statBuffer[accellIndex][latVelIndex?][distanceIndex]; |
int stats[] = statBuffer[getOutIndex?()][lastLatVelIndex?][(lastLatVelIndex? = ((int)Math.abs(latVel) / 2))][Math.min(4, ++ticksSinceReverse?/10)][distanceIndex]; |
int bestIndex = (int)((GUESS_FACTORS -1) / 2); |
int bestIndex = (int)MIDDLE_FACTOR; |
|
setTurnGunRightRadians?(robocode.util.Utils.normalRelativeAngle(eAbsBearing? - getGunHeadingRadians?() + (getGuessAngle?(bestIndex, firePower)))); |
setTurnGunRightRadians?(Utils.normalRelativeAngle(eAbsBearing? - getGunHeadingRadians?() + (getGuessAngle?(bestIndex, firePower)))); |
//If? the gun is cool, fire and shoot a Wave if (getGunHeat() == 0 && firePower > 0) { |
if (firePower > 0) { |
w.eventTime = getTime(); |
w.bulletVel=bulletV(firePower); w.dist+=w.bulletVel; |
w.shotPower = firePower; |
w.maxAnglePossible? = Math.asin(8D / bulletV(firePower)); |
w.maxAnglePossible? = Math.asin(8.0 / w.bulletVel); |
//Housekeeping? eLastVelocity? = eVelocity; eLastEnergy? = eEnergy; |
//lastLatVelIndex? = latVelIndex?; |
// public void onHitByBullet?(HitByBulletEvent? e) { // if (!flatten) // hits++; // flatten = true; // } |
if (lastReverseTime? > (eDistance + 50) / e.getVelocity() && !flatten) { flatten = (++hits > 1); |
//if (ticksSinceReverse? > (eDistance / e.getVelocity()) && !flatten) { if (!flatten) { flatten = (++hits > 0); |
//Method? to determine if I should wall smooth or not. private double getTurnAngle?() { double turnTo = eBearing + (Math.PI / 2) + (.2618 * direction * (eDistance > MAX_STAND_OFF_DISTANCE ? CLOSE_IN : (eDistance < MIN_STAND_OFF_DISTANCE ? BACK_OFF : 0))); if (out(WALL_CURVE_DISTANCE * direction, turnTo) && eDistance > 200) { //Start? smoothing //int cDirection = ((getVelocity() * Math.sin(getHeadingRadians() - Math.atan2(getX() - getBattleFieldWidth?() / 2, getY() - getBattleFieldHeight?() / 2))) > 0 ? 1 : -1); double test; //No? "diving" in if (Math.abs(Math.sin(eBearing)) < .500 && flatten) { //.500 == sin 30 degrees reverse(); //Hug? the wall. } else if (!out(WALL_CURVE_DISTANCE * direction, getHeadingRadians())) { return 0; //Moving? along the wall //Smooth? into it } else { return (BEND_ANGLE * -direction); } } //End? smoothing return turnTo; } //Reverse? my direction public void reverse() { lastReverseTime? = getTime(); direction = -direction; } |
return (guessIndex - ((GUESS_FACTORS - 1) / 2)) / ((GUESS_FACTORS - 1) / 2) * Math.asin(8.0 / bulletV(firePower)) * eDirection; |
return (guessIndex - MIDDLE_FACTOR) / MIDDLE_FACTOR * Math.asin(8.0 / bulletV(firePower)) * eDirection; |
return new int[3][3][11][(int)GUESS_FACTORS]; |
//int stats[] = statBuffer[getOutIndex?()][lastLatVelIndex?][latVelIndex?][Math.min(4, ++ticksSinceReverse?/5)][distanceIndex]; return new int[5][5][5][5][5][(int)GUESS_FACTORS]; |
//Stolen? from kawigi and modified to make it smaller public boolean out(double c, double angle) { //double angle; return !(field.contains(Math.sin(angle = getHeadingRadians())*c+getX(), Math.cos(angle)*c+getY())); |
//Gets? the point we are going to aim for in the next tick private Point2D.Double getDestination(Point2D.Double startFrom, int direct) { double fudge = 0; //Adjustment? to rotate the heading by Point2D.Double dest = new Point2D.Double(); //If? we are in the "sweet spot" no need to move in or out double dir = eAbsBearing? + (Math.PI / 2) + (.2618 * direct * (eDistance > MAX_STAND_OFF_DISTANCE ? CLOSE_IN : (eDistance < MIN_STAND_OFF_DISTANCE ? BACK_OFF : 0))); int counter = 0; //Rotate? the position we are heading for until it is in the field do { dest.setLocation(startFrom.x + Math.sin(dir + (fudge * direct)) * WALL_CURVE_DISTANCE * direct, startFrom.y + Math.cos(dir + (fudge * direct)) * (WALL_CURVE_DISTANCE * direct)); fudge-=.0085; //.5 degrees radians } while (!field.contains(dest) && ++counter < 180); if (counter >= 55 && flatten) { direction = -direction; } return dest; } //This? moves me about the field private void goTo(Point2D destination) { ticksSinceReverse?++; double angle = Utils.normalRelativeAngle(Math.atan2((destination.getX() - getX()), (destination.getY()- getY())) - getHeadingRadians()); double turnAngle = Math.atan(Math.tan(angle)); setTurnRightRadians?(turnAngle); setAhead(destination.distance(getX(), getY()) * (angle == turnAngle ? 1 : -1) * Math.cos(turnAngle)); } //Return? the wall index private int getOutIndex?() { int i = 0; do { } while (++i < 4 && field.contains((eX + (Math.sin(eHeading)* (45.0 * i) * eDirection)), (eY + (Math.cos(eHeading) * (45.0 * i) * eDirection)))); return (i); |
//Stolen? from kawigi //private double distanceFromCorner?() { //private boolean cornered() { // double x, y; // return Point2D.distance(0, 0, Math.min((x = getX()), getBattleFieldWidth?()-x), Math.min((y = getY()), getBattleFieldHeight?()-y)) < 180; //} //Test? for closeness to wall //public double wallDist(double x, double y) { // return Math.min(Math.min(x - 18D, getBattleFieldWidth?() - 18D - x), Math.min(y - 18D, getBattleFieldHeight?() -18D - y)); //} |
public double shotPower; |
public double bulletVel; public double dist; |
public long eventTime; |
if (((getTime() - eventTime) * bulletV(shotPower)) >= shotOrigin.distance(eX,eY)) { |
if ((dist+=bulletVel) >= shotOrigin.distance(eX,eY) - 18) { |
guessFactors[(int)Math.max(0, Math.min((GUESS_FACTORS - 1),(int) Math.round(((((Utils.normalRelativeAngle(currentAbsBearingFromShotOrigin? - startingAbsTargetBearing?) * wDirection) / maxAnglePossible?) * ((GUESS_FACTORS - 1) / 2)) + ((GUESS_FACTORS - 1) / 2)))))]++; |
guessFactors[(int)Math.max(0, Math.min((GUESS_FACTORS - 1),(int) Math.round(((((Utils.normalRelativeAngle(currentAbsBearingFromShotOrigin? - startingAbsTargetBearing?) * wDirection) / maxAnglePossible?) * MIDDLE_FACTOR) + MIDDLE_FACTOR))))]++; |
As you can see there is quite a bit of code commented out and you can see some of the variables I am monkeying around with. As always, questions, comments, and feedback are always appreciated. |
/* * Created on Aug 4, 2003 * */ package jekl.mini; import java.awt.geom.*; import java.io.*; import java.util.zip.*; import robocode.*; import robocode.util.Utils; public class BlackPearl extends AdvancedRobot { private static final double MAX_STAND_OFF_DISTANCE = 600D; private static final double MIN_STAND_OFF_DISTANCE = 500D; private static final double GUESS_FACTORS = 23D; private static final double MIDDLE_FACTOR = (GUESS_FACTORS -1) / 2; private static final double WALL_CURVE_DISTANCE = 180D; //pixels private static final int CLOSE_IN = -1; private static final int BACK_OFF = 1; private static Rectangle2D.Double field; private static int statBuffer[][][][][][]; private static String targetName; private static int hits; private int direction = 1; private int eDirection; private double eEnergy = 100D; private double eX, eY, eDelta, eAbsBearing, eVelocity, eDistance, eHeading; private boolean flatten = (hits > 2); private double eLastShot = 3; private static int ticksSinceReverse = 0; int lastLatVelIndex = 0; public void run() { //setColors(java.awt.Color.MAGENTA, java.awt.Color.LIGHT_GRAY, java.awt.Color.RED); field = new Rectangle2D.Double(18, 18, getBattleFieldWidth() - 36, getBattleFieldHeight() - 36); setAdjustGunForRobotTurn(true); setAdjustRadarForGunTurn(true); do { turnRadarRightRadians(Double.POSITIVE_INFINITY); } while(true); } public void onScannedRobot(ScannedRobotEvent e) { //Gather target information targetName = e.getName(); if (Math.abs(eVelocity) > Math.abs(eVelocity = e.getVelocity())) { ticksSinceReverse = 0; } double latVel = (eVelocity) * Math.sin(eHeading = e.getHeadingRadians() - (eAbsBearing = Utils.normalRelativeAngle(getHeadingRadians() + (e.getBearingRadians())))); eX = getX() + Math.sin(eAbsBearing) * (eDistance = e.getDistance()); eY = getY() + Math.cos(eAbsBearing) * eDistance; //Keep the sign of the direction last used if latVel is zero if (latVel != 0) { eDirection = (int)(Math.abs(latVel) / latVel); } //Set the indicies for shooting int distanceIndex = (int)Math.min(4, eDistance / 180D); //Reverse chance if ((eDelta = eEnergy - (eEnergy = e.getEnergy())) > 0 && eDelta <= 3) { eLastShot = eDelta; } //Set the firePower double firePower = (distanceIndex <=1 ? 3.0 : 1.9); //double firePower = (getEnergy() > 0 ? 3.0 : 0); //Movement //This is an adaptation from Raiko. If you can't beat 'em, join 'em double distDelta = 0.02 + Math.PI/2 + (e.getDistance() > 400 ? -.1 : .5); double theta = 0.5952*bulletV(eLastShot)/eDistance; if ( (Math.random() > Math.pow(theta, theta) && flatten)|| distDelta < Math.PI/4 || (distDelta < Math.PI/3 && eDistance < 400)){ //double theta = .64 * bulletV(eLastShot)/eDistance; //if ((Math.random() > Math.pow(theta, theta) && flatten)) { direction = -direction; } //Finally move goTo(getDestination(new Point2D.Double(getX(), getY()),direction)); //Radar setTurnRadarRightRadians(Math.sin(eAbsBearing - getRadarHeadingRadians())); //Gun //Initialize the statbuffer if (statBuffer == null) { statBuffer = (int[][][][][][]) readObject(targetName); } //Retrieve the current stat segment to use int stats[] = statBuffer[getOutIndex()][lastLatVelIndex][(lastLatVelIndex = ((int)Math.abs(latVel) / 2))][Math.min(4, ++ticksSinceReverse/10)][distanceIndex]; //Get the current best Guess Factor to shoot at int bestIndex = (int)MIDDLE_FACTOR; for (int i = 0; i < stats.length ; i++) { if (stats[i] > stats[bestIndex]) bestIndex = i; } //Aim the gun //Original setTurnGunRightRadians(Utils.normalRelativeAngle(eAbsBearing - getGunHeadingRadians() + (getGuessAngle(bestIndex, firePower)))); if (firePower > 0) { setFire(firePower); Wave w = new Wave(); w.guessFactors = stats; w.wDirection = eDirection; w.bulletVel=bulletV(firePower); w.dist+=w.bulletVel; w.shotOrigin = new Point2D.Double(getX(), getY()); w.startingAbsTargetBearing = eAbsBearing; w.maxAnglePossible = Math.asin(8.0 / w.bulletVel); addCustomEvent(w); } //lastLatVelIndex = latVelIndex; } // Check if we are hit with full lead aim // Adapted from Axe's Musashi: http://robowiki.net/?Musashi public void onHitByBullet(HitByBulletEvent e) { //if (ticksSinceReverse > (eDistance / e.getVelocity()) && !flatten) { if (!flatten) { flatten = (++hits > 0); } } // Save the data if I win the round public void onWin(WinEvent e) { try { ObjectOutputStream oos = new ObjectOutputStream(new GZIPOutputStream(new RobocodeFileOutputStream(getDataFile(targetName)))); oos.writeObject(statBuffer); oos.close(); } catch (IOException ex) { //Should do something here but alas it is too big //e.printStackTrace(); } } // Figures the Guess Angle Radians to offset the gun by private double getGuessAngle(int guessIndex, double firePower) { if (eEnergy == 0.0) //If the enemy bot is disabled, fire directly at it. return 0.0; return (guessIndex - MIDDLE_FACTOR) / MIDDLE_FACTOR * Math.asin(8.0 / bulletV(firePower)) * eDirection; } // Method to read data from disc. Taken from SandboxMini Object readObject(String fileName) { try { ObjectInputStream ois = new ObjectInputStream(new GZIPInputStream(new FileInputStream(getDataFile(fileName)))); Object o = ois.readObject(); ois.close(); return o; } catch (Exception e) { //int stats[] = statBuffer[getOutIndex()][lastLatVelIndex][latVelIndex][Math.min(4, ++ticksSinceReverse/5)][distanceIndex]; return new int[5][5][5][5][5][(int)GUESS_FACTORS]; //Should do something here but alas it is too big //e.printStackTrace(); } } //Retrieve the bullets velocity private double bulletV (double shotPower) { return (20 - (3 * shotPower)); } //Gets the point we are going to aim for in the next tick private Point2D.Double getDestination(Point2D.Double startFrom, int direct) { double fudge = 0; //Adjustment to rotate the heading by Point2D.Double dest = new Point2D.Double(); //If we are in the "sweet spot" no need to move in or out double dir = eAbsBearing + (Math.PI / 2) + (.2618 * direct * (eDistance > MAX_STAND_OFF_DISTANCE ? CLOSE_IN : (eDistance < MIN_STAND_OFF_DISTANCE ? BACK_OFF : 0))); int counter = 0; //Rotate the position we are heading for until it is in the field do { dest.setLocation(startFrom.x + Math.sin(dir + (fudge * direct)) * WALL_CURVE_DISTANCE * direct, startFrom.y + Math.cos(dir + (fudge * direct)) * (WALL_CURVE_DISTANCE * direct)); fudge-=.0085; //.5 degrees radians } while (!field.contains(dest) && ++counter < 180); if (counter >= 55 && flatten) { direction = -direction; } return dest; } //This moves me about the field private void goTo(Point2D destination) { ticksSinceReverse++; double angle = Utils.normalRelativeAngle(Math.atan2((destination.getX() - getX()), (destination.getY()- getY())) - getHeadingRadians()); double turnAngle = Math.atan(Math.tan(angle)); setTurnRightRadians(turnAngle); setAhead(destination.distance(getX(), getY()) * (angle == turnAngle ? 1 : -1) * Math.cos(turnAngle)); } //Return the wall index private int getOutIndex() { int i = 0; do { } while (++i < 4 && field.contains((eX + (Math.sin(eHeading)* (45.0 * i) * eDirection)), (eY + (Math.cos(eHeading) * (45.0 * i) * eDirection)))); return (i); } // Jekyl's implementation of a Wave (mostly) public class Wave extends Condition { public Point2D.Double shotOrigin; public double bulletVel; public double dist; public double startingAbsTargetBearing; public double maxAnglePossible; public int[] guessFactors; public int wDirection; public boolean test() { if ((dist+=bulletVel) >= shotOrigin.distance(eX,eY) - 18) { double currentAbsBearingFromShotOrigin = Math.atan2(eX - shotOrigin.getX(), eY - shotOrigin.getY()); guessFactors[(int)Math.max(0, Math.min((GUESS_FACTORS - 1),(int) Math.round(((((Utils.normalRelativeAngle(currentAbsBearingFromShotOrigin - startingAbsTargetBearing) * wDirection) / maxAnglePossible) * MIDDLE_FACTOR) + MIDDLE_FACTOR))))]++; removeCustomEvent(this); } return false; } } //End Wave }