[Home]BlackPearl/Code

Robo Home | BlackPearl | Changes | Preferences | AllPages

Difference (from prior author revision) (major diff, minor diff)

Changed: 1c1
Code for version .83
Code for version .90

Removed: 14,21d13
/**
* 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
*/

Changed: 23,34c15,19
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

Changed: 38c23
private static int statBuffer[][][][];
private static int statBuffer[][][][][][];

Removed: 40d24
private static boolean save;

Changed: 44,45c28,29
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;

Changed: 48,49c32,33
private long lastReverseTime?;

private static int ticksSinceReverse? = 0;
int lastLatVelIndex? = 0;

Removed: 56d39
save = (getOthers() == 1); //Only? save data if we are in a 1-v-1 engagement, otherwise the data will be polluted

Changed: 65c48,52
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?()))));

Removed: 68,69d54
double accelDiff = Math.round(Math.abs(eVelocity) - Math.abs(eLastVelocity?));
eDirection = (latVel >= 0 ? 1 : -1);

Changed: 71,72c56,59
//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);
}

Changed: 75,82c62,63
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);


Changed: 84c65
if ((eDelta = eLastEnergy? - eEnergy) > 0 && eDelta <= 3) {
if ((eDelta = eEnergy - (eEnergy = e.getEnergy())) > 0 && eDelta <= 3) {

Changed: 87,92c68,80
//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;

Changed: 96,97c84
setAhead(Math.cos(turnTo)*100*direction);
//setAhead(MOVEMENT_DISTANCE * direction);
goTo(getDestination(new Point2D.Double(getX(), getY()),direction));

Changed: 105c92
statBuffer = (int[][][][]) readObject(targetName);
statBuffer = (int[][][][][][]) readObject(targetName);

Changed: 109c96
int stats[] = statBuffer[accellIndex][latVelIndex?][distanceIndex];
int stats[] = statBuffer[getOutIndex?()][lastLatVelIndex?][(lastLatVelIndex? = ((int)Math.abs(latVel) / 2))][Math.min(4, ++ticksSinceReverse?/10)][distanceIndex];

Changed: 112c99
int bestIndex = (int)((GUESS_FACTORS -1) / 2);
int bestIndex = (int)MIDDLE_FACTOR;

Added: 116a104


Changed: 120c108
setTurnGunRightRadians?(robocode.util.Utils.normalRelativeAngle(eAbsBearing? - getGunHeadingRadians?() + (getGuessAngle?(bestIndex, firePower))));
setTurnGunRightRadians?(Utils.normalRelativeAngle(eAbsBearing? - getGunHeadingRadians?() + (getGuessAngle?(bestIndex, firePower))));

Changed: 122,123c110
//If? the gun is cool, fire and shoot a Wave
if (getGunHeat() == 0 && firePower > 0) {
if (firePower > 0) {

Changed: 128c115,116
w.eventTime = getTime();
w.bulletVel=bulletV(firePower);
w.dist+=w.bulletVel;

Removed: 130d117
w.shotPower = firePower;

Changed: 132c119
w.maxAnglePossible? = Math.asin(8D / bulletV(firePower));
w.maxAnglePossible? = Math.asin(8.0 / w.bulletVel);

Changed: 135,138c122

//Housekeeping?
eLastVelocity? = eVelocity;
eLastEnergy? = eEnergy;
//lastLatVelIndex? = latVelIndex?;

Removed: 141,146d124
// public void onHitByBullet?(HitByBulletEvent? e) {
// if (!flatten)
// hits++;
// flatten = true;
// }


Changed: 150,151c128,130
if (lastReverseTime? > (eDistance + 50) / e.getVelocity() && !flatten) {
flatten = (++hits > 1);
//if (ticksSinceReverse? > (eDistance / e.getVelocity()) && !flatten) {
if (!flatten) {
flatten = (++hits > 0);

Removed: 155,180d133
//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;
}


Changed: 197c150
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;

Changed: 208c161,162
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];

Changed: 219,222c173,207
//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);

Removed: 225,236d209
//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));
//}


Changed: 240c213,214
public double shotPower;
public double bulletVel;
public double dist;

Removed: 243d216
public long eventTime;

Changed: 248c221
if (((getTime() - eventTime) * bulletV(shotPower)) >= shotOrigin.distance(eX,eY)) {
if ((dist+=bulletVel) >= shotOrigin.distance(eX,eY) - 18) {

Changed: 250c223
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))))]++;

Removed: 258,259d230

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.

Code for version .90
/*
 * 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
}

Robo Home | BlackPearl | Changes | Preferences | AllPages
Edit text of this page | View other revisions
Last edited May 25, 2004 23:04 EST by Sparafucil3 (diff)
Search: