Difference between revisions of "GFTargetingBot"

From Robowiki
Jump to navigation Jump to search
m (formatting)
m (Using <syntaxhighlight>.)
(10 intermediate revisions by 5 users not shown)
Line 1: Line 1:
I'm new to java, and my lack of understanding Java has me hung up on this key peice of code:
+
{{Infobox Robot
  buffer = statBuffers[distanceIndex][velocityIndex][lastVelocityIndex];
+
| author          = [[PEZ]]
from my understanding;  buffer is an array of 25 (ints), each bin being a counter of times visted.
+
| extends        = [[AdvancedRobot]]
And statBuffers is a 4dimesional array of size: 5(int),  5(int), 5(int),and  25(int) :
+
| targeting      = [[GuessFactor Targeting]]
private static int[][][][] statBuffers = new int[DISTANCE_INDEXES][VELOCITY_INDEXES][VELOCITY_INDEXES][BINS];
+
| movement        = [[RandomMovement|Random Movement]], Orbit movement
so back to the problem code :
+
| current_version = 1.02
buffer = statBuffers[distanceIndex][velocityIndex][lastVelocityIndex];
+
| license        = None
 +
| download_link  = http://www.robocoderepository.com/BotDetail.jsp?id=2913
 +
| isOneOnOne      = true
 +
| isMelee        = false
 +
| isOpenSource    = true
 +
}}
 +
__NOTOC__ __NOEDITSECTION__
 +
=== GFTargetingBot, by [[PEZ]] ===
  
so the above "indexes" (0-4) should retrieve  the values in thoses locations in the statBuffers arrays..
+
==== What's special about it? ====
Am I wrong so Far ?
+
It's a simple StatisticalTargeting bot using GuessFactors, if not literal so the general idea. My goal is that people who want to start out with StatisticalTargeting can do so with this bot without having to figure it all out first. This bot is quite competetive out-of-the-box, but with just some little work it can be made to kick ass.
It seems to me were  assigning apples to oranges here? How does it work ? ..
 
- Justin
 
  
<code>int single[] = new int[ 5 ];</code>
+
It features:
<br><i>single</i> is "an array of integers".
+
* [[Wave]]s, to collect the data
<br><code>int double[][] = new int[ 5 ][ 5 ];</code>
+
* [[VisitCountStats]], accumulating data into simple int arrays
<br><i>double</i> is "an array of 5 arrays of 5 integers".
+
* [[Segmentation]] (really simple, just to show how it can be done)
 +
It lacks:
 +
* [[EnergyManagement]]
 +
* Advanced [[Segmentation]]
 +
* Gun alignment nitty-gritty.
 +
* [[RollingAverage]]s
 +
* [[DataSaving]]
 +
* Anything advanced really.
  
This means that each element in double[ n ] is itself "an array of 5 integers".
+
==== Great, I want to try it. Where can I download it? ====
 +
http://www.robocoderepository.com/BotDetail.jsp?id=2913
 +
* Note: It would be good to update this bot on the repository with MAX_DISTANCE = 1000 or calculated based on battle field width and height. I've updated it in the code on this page. -- [[Voidious]]
  
<br>Let's change <i>int</i> to <i>apple</i>.
+
==== How competitive is it? ====
<br><code>apple double[][] = new apple[ 5 ][ 5 ];</code>
+
Quite so for something this simple
<br><i>double</i> is now "an array of 5 arrays of 5 apples."
 
  
This means that every double[ n ] is a container, and each container holds 5 apples. The container is not an apple.  It is 'a container of one or more apples'.  You can visualize it as a paper bag if you like.
+
==== How does it [[Movement|move]]? ====
 +
Random, fluid, orbit movement. Almost verbatim [[Aristocles]] movement. (Minus MusashiTrick)
  
<br><code>apple triple[][][] = new apple[ 5 ][ 5 ][ 5 ];</code>
+
==== How does it fire? ====
<br><i>triple</i> is "an array of 5 arrays of 5 arrays of apples" or perhaps "5 containers of 'containers of apples'".
+
A GuessFactorTargeting gun segmented on distance, velocity, last-scan-velocity.  
  
Going back to your original question, here is the situation:  <i>buffer</I> is 'an array of integers'.  (I deliberately did not state the size, because <i>buffer</i> can be assigned an array of any size of the same dimensions.)  <i>statBuffers</i> is 'an array of arrays of arrays of arrays of integers'.  Each element in statBuffers[][][] is itself an 'array of integers', and that is why the assignment works.
+
==== How does it [[DodgingBullets|dodge bullets]]? ====
 +
It tries to create a flat MovementProfile.
  
I hope that helped. If not, best thing is to just practice with arrays it until it sinks in. -- [[User:Pedersen|Martin]]
+
==== How does the [[Melee|melee]] strategy differ from [[OneOnOne|one-on-one]]  strategy? ====
 +
This bot doesn't know about [[Melee]] battles.
 +
 
 +
==== What does it save between rounds and matches? ====
 +
The visit counts are saved between rounds. Nothing is saved between matches.
 +
 
 +
==== Where did you get the name? ====
 +
Duh... It's a GuessFactorTargeting tutorial bot.
 +
 
 +
==== Can I use your code? ====
 +
Sure. That's the whole idea. It's included in the jar. Use it as you see fit. Of course if I do not mind credits. And here's the code for version 1.0 (meaning it might not always be up to date.):
 +
<syntaxhighlight>
 +
package wiki.tutorial;
 +
import robocode.*;
 +
import robocode.util.Utils;
 +
import java.awt.Color;
 +
import java.awt.geom.*;
 +
 
 +
// GFTargetingBot, by PEZ. A simple GuessFactorTargeting bot for tutorial purposes.
 +
// Use the code as you see fit. Of course if I do not mind credits.
 +
 
 +
public class GFTargetingBot extends AdvancedRobot {
 +
private static final double BULLET_POWER = 1.9;
 +
 +
private static double lateralDirection;
 +
private static double lastEnemyVelocity;
 +
private static GFTMovement movement;
 +
 +
public GFTargetingBot() {
 +
movement = new GFTMovement(this);
 +
}
 +
 +
public void run() {
 +
setColors(Color.BLUE, Color.BLACK, Color.YELLOW);
 +
lateralDirection = 1;
 +
lastEnemyVelocity = 0;
 +
setAdjustRadarForGunTurn(true);
 +
setAdjustGunForRobotTurn(true);
 +
do {
 +
turnRadarRightRadians(Double.POSITIVE_INFINITY);
 +
} while (true);
 +
}
 +
 +
public void onScannedRobot(ScannedRobotEvent e) {
 +
double enemyAbsoluteBearing = getHeadingRadians() + e.getBearingRadians();
 +
double enemyDistance = e.getDistance();
 +
double enemyVelocity = e.getVelocity();
 +
if (enemyVelocity != 0) {
 +
lateralDirection = GFTUtils.sign(enemyVelocity * Math.sin(e.getHeadingRadians() - enemyAbsoluteBearing));
 +
}
 +
GFTWave wave = new GFTWave(this);
 +
wave.gunLocation = new Point2D.Double(getX(), getY());
 +
GFTWave.targetLocation = GFTUtils.project(wave.gunLocation, enemyAbsoluteBearing, enemyDistance);
 +
wave.lateralDirection = lateralDirection;
 +
wave.bulletPower = BULLET_POWER;
 +
wave.setSegmentations(enemyDistance, enemyVelocity, lastEnemyVelocity);
 +
lastEnemyVelocity = enemyVelocity;
 +
wave.bearing = enemyAbsoluteBearing;
 +
setTurnGunRightRadians(Utils.normalRelativeAngle(enemyAbsoluteBearing - getGunHeadingRadians() + wave.mostVisitedBearingOffset()));
 +
setFire(wave.bulletPower);
 +
if (getEnergy() >= BULLET_POWER) {
 +
addCustomEvent(wave);
 +
}
 +
movement.onScannedRobot(e);
 +
setTurnRadarRightRadians(Utils.normalRelativeAngle(enemyAbsoluteBearing - getRadarHeadingRadians()) * 2);
 +
}
 +
}
 +
 
 +
class GFTWave extends Condition {
 +
static Point2D targetLocation;
 +
 
 +
double bulletPower;
 +
Point2D gunLocation;
 +
double bearing;
 +
double lateralDirection;
 +
 
 +
private static final double MAX_DISTANCE = 1000;
 +
private static final int DISTANCE_INDEXES = 5;
 +
private static final int VELOCITY_INDEXES = 5;
 +
private static final int BINS = 25;
 +
private static final int MIDDLE_BIN = (BINS - 1) / 2;
 +
private static final double MAX_ESCAPE_ANGLE = 0.7;
 +
private static final double BIN_WIDTH = MAX_ESCAPE_ANGLE / (double)MIDDLE_BIN;
 +
 +
private static int[][][][] statBuffers = new int[DISTANCE_INDEXES][VELOCITY_INDEXES][VELOCITY_INDEXES][BINS];
 +
 
 +
private int[] buffer;
 +
private AdvancedRobot robot;
 +
private double distanceTraveled;
 +
 +
GFTWave(AdvancedRobot _robot) {
 +
this.robot = _robot;
 +
}
 +
 +
public boolean test() {
 +
advance();
 +
if (hasArrived()) {
 +
buffer[currentBin()]++;
 +
robot.removeCustomEvent(this);
 +
}
 +
return false;
 +
}
 +
 
 +
double mostVisitedBearingOffset() {
 +
return (lateralDirection * BIN_WIDTH) * (mostVisitedBin() - MIDDLE_BIN);
 +
}
 +
 +
void setSegmentations(double distance, double velocity, double lastVelocity) {
 +
int distanceIndex = (int)(distance / (MAX_DISTANCE / DISTANCE_INDEXES));
 +
int velocityIndex = (int)Math.abs(velocity / 2);
 +
int lastVelocityIndex = (int)Math.abs(lastVelocity / 2);
 +
buffer = statBuffers[distanceIndex][velocityIndex][lastVelocityIndex];
 +
}
 +
 
 +
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;
 +
}
 +
}
 +
 
 +
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));
 +
}
 +
}
 +
 
 +
class GFTMovement {
 +
private static final double BATTLE_FIELD_WIDTH = 800;
 +
private static final double BATTLE_FIELD_HEIGHT = 600;
 +
private static final double WALL_MARGIN = 18;
 +
private static final double MAX_TRIES = 125;
 +
private static final double REVERSE_TUNER = 0.421075;
 +
private static final double DEFAULT_EVASION = 1.2;
 +
private static final double WALL_BOUNCE_TUNER = 0.699484;
 +
 
 +
private AdvancedRobot robot;
 +
private Rectangle2D fieldRectangle = new Rectangle2D.Double(WALL_MARGIN, WALL_MARGIN,
 +
BATTLE_FIELD_WIDTH - WALL_MARGIN * 2, BATTLE_FIELD_HEIGHT - WALL_MARGIN * 2);
 +
private double enemyFirePower = 3;
 +
private double direction = 0.4;
 +
 
 +
GFTMovement(AdvancedRobot _robot) {
 +
this.robot = _robot;
 +
}
 +
 +
public void onScannedRobot(ScannedRobotEvent e) {
 +
double enemyAbsoluteBearing = robot.getHeadingRadians() + e.getBearingRadians();
 +
double enemyDistance = e.getDistance();
 +
Point2D robotLocation = new Point2D.Double(robot.getX(), robot.getY());
 +
Point2D enemyLocation = GFTUtils.project(robotLocation, enemyAbsoluteBearing, enemyDistance);
 +
Point2D robotDestination;
 +
double tries = 0;
 +
while (!fieldRectangle.contains(robotDestination = GFTUtils.project(enemyLocation, enemyAbsoluteBearing + Math.PI + direction,
 +
enemyDistance * (DEFAULT_EVASION - tries / 100.0))) && tries < MAX_TRIES) {
 +
tries++;
 +
}
 +
if ((Math.random() < (GFTUtils.bulletVelocity(enemyFirePower) / REVERSE_TUNER) / enemyDistance ||
 +
tries > (enemyDistance / GFTUtils.bulletVelocity(enemyFirePower) / WALL_BOUNCE_TUNER))) {
 +
direction = -direction;
 +
}
 +
// Jamougha's cool way
 +
double angle = GFTUtils.absoluteBearing(robotLocation, robotDestination) - robot.getHeadingRadians();
 +
robot.setAhead(Math.cos(angle) * 100);
 +
robot.setTurnRightRadians(Math.tan(angle));
 +
}
 +
}
 +
</syntaxhighlight>
 +
 
 +
==== What's next for your robot? ====
 +
* I must document the code to make this tutorial thing to really work. You're more than welcome to help in this.
 +
 
 +
==== What other robot(s) is it based on? ====
 +
[[Aristocles]] - both gun and movement
 +
 
 +
 
 +
[[Category:Source Code]] [[Category:Bots]]

Revision as of 09:27, 1 July 2010

GFTargetingBot
Author(s) PEZ
Extends AdvancedRobot
Targeting GuessFactor Targeting
Movement Random Movement, Orbit movement
Current Version 1.02
Code License None
Download

GFTargetingBot, by PEZ

What's special about it?

It's a simple StatisticalTargeting bot using GuessFactors, if not literal so the general idea. My goal is that people who want to start out with StatisticalTargeting can do so with this bot without having to figure it all out first. This bot is quite competetive out-of-the-box, but with just some little work it can be made to kick ass.

It features:

It lacks:

Great, I want to try it. Where can I download it?

http://www.robocoderepository.com/BotDetail.jsp?id=2913

  • Note: It would be good to update this bot on the repository with MAX_DISTANCE = 1000 or calculated based on battle field width and height. I've updated it in the code on this page. -- Voidious

How competitive is it?

Quite so for something this simple

How does it move?

Random, fluid, orbit movement. Almost verbatim Aristocles movement. (Minus MusashiTrick)

How does it fire?

A GuessFactorTargeting gun segmented on distance, velocity, last-scan-velocity.

How does it dodge bullets?

It tries to create a flat MovementProfile.

How does the melee strategy differ from one-on-one strategy?

This bot doesn't know about Melee battles.

What does it save between rounds and matches?

The visit counts are saved between rounds. Nothing is saved between matches.

Where did you get the name?

Duh... It's a GuessFactorTargeting tutorial bot.

Can I use your code?

Sure. That's the whole idea. It's included in the jar. Use it as you see fit. Of course if I do not mind credits. And here's the code for version 1.0 (meaning it might not always be up to date.):

package wiki.tutorial;
import robocode.*;
import robocode.util.Utils;
import java.awt.Color;
import java.awt.geom.*;

// GFTargetingBot, by PEZ. A simple GuessFactorTargeting bot for tutorial purposes.
// Use the code as you see fit. Of course if I do not mind credits.

public class GFTargetingBot extends AdvancedRobot {
	private static final double BULLET_POWER = 1.9;
	
	private static double lateralDirection;
	private static double lastEnemyVelocity;
	private static GFTMovement movement;
	
	public GFTargetingBot() {
		movement = new GFTMovement(this);	
	}
	
	public void run() {
		setColors(Color.BLUE, Color.BLACK, Color.YELLOW);
		lateralDirection = 1;
		lastEnemyVelocity = 0;
		setAdjustRadarForGunTurn(true);
		setAdjustGunForRobotTurn(true);
		do {
			turnRadarRightRadians(Double.POSITIVE_INFINITY); 
		} while (true);
	}
	
	public void onScannedRobot(ScannedRobotEvent e) {
		double enemyAbsoluteBearing = getHeadingRadians() + e.getBearingRadians();
		double enemyDistance = e.getDistance();
		double enemyVelocity = e.getVelocity();
		if (enemyVelocity != 0) {
			lateralDirection = GFTUtils.sign(enemyVelocity * Math.sin(e.getHeadingRadians() - enemyAbsoluteBearing));
		}
		GFTWave wave = new GFTWave(this);
		wave.gunLocation = new Point2D.Double(getX(), getY());
		GFTWave.targetLocation = GFTUtils.project(wave.gunLocation, enemyAbsoluteBearing, enemyDistance);
		wave.lateralDirection = lateralDirection;
		wave.bulletPower = BULLET_POWER;
		wave.setSegmentations(enemyDistance, enemyVelocity, lastEnemyVelocity);
		lastEnemyVelocity = enemyVelocity;
		wave.bearing = enemyAbsoluteBearing;
		setTurnGunRightRadians(Utils.normalRelativeAngle(enemyAbsoluteBearing - getGunHeadingRadians() + wave.mostVisitedBearingOffset()));
		setFire(wave.bulletPower);
		if (getEnergy() >= BULLET_POWER) {
			addCustomEvent(wave);
		}
		movement.onScannedRobot(e);
		setTurnRadarRightRadians(Utils.normalRelativeAngle(enemyAbsoluteBearing - getRadarHeadingRadians()) * 2);
	}
}

class GFTWave extends Condition {
	static Point2D targetLocation;

	double bulletPower;
	Point2D gunLocation;
	double bearing;
	double lateralDirection;

	private static final double MAX_DISTANCE = 1000;
	private static final int DISTANCE_INDEXES = 5;
	private static final int VELOCITY_INDEXES = 5;
	private static final int BINS = 25;
	private static final int MIDDLE_BIN = (BINS - 1) / 2;
	private static final double MAX_ESCAPE_ANGLE = 0.7;
	private static final double BIN_WIDTH = MAX_ESCAPE_ANGLE / (double)MIDDLE_BIN;
	
	private static int[][][][] statBuffers = new int[DISTANCE_INDEXES][VELOCITY_INDEXES][VELOCITY_INDEXES][BINS];

	private int[] buffer;
	private AdvancedRobot robot;
	private double distanceTraveled;
	
	GFTWave(AdvancedRobot _robot) {
		this.robot = _robot;
	}
	
	public boolean test() {
		advance();
		if (hasArrived()) {
			buffer[currentBin()]++;
			robot.removeCustomEvent(this);
		}
		return false;
	}

	double mostVisitedBearingOffset() {
		return (lateralDirection * BIN_WIDTH) * (mostVisitedBin() - MIDDLE_BIN);
	}
	
	void setSegmentations(double distance, double velocity, double lastVelocity) {
		int distanceIndex = (int)(distance / (MAX_DISTANCE / DISTANCE_INDEXES));
		int velocityIndex = (int)Math.abs(velocity / 2);
		int lastVelocityIndex = (int)Math.abs(lastVelocity / 2);
		buffer = statBuffers[distanceIndex][velocityIndex][lastVelocityIndex];
	}

	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;
	}	
}

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));
	}
}

class GFTMovement {
	private static final double BATTLE_FIELD_WIDTH = 800;
	private static final double BATTLE_FIELD_HEIGHT = 600;
	private static final double WALL_MARGIN = 18;
	private static final double MAX_TRIES = 125;
	private static final double REVERSE_TUNER = 0.421075;
	private static final double DEFAULT_EVASION = 1.2;
	private static final double WALL_BOUNCE_TUNER = 0.699484;

	private AdvancedRobot robot;
	private Rectangle2D fieldRectangle = new Rectangle2D.Double(WALL_MARGIN, WALL_MARGIN,
		BATTLE_FIELD_WIDTH - WALL_MARGIN * 2, BATTLE_FIELD_HEIGHT - WALL_MARGIN * 2);
	private double enemyFirePower = 3;
	private double direction = 0.4;

	GFTMovement(AdvancedRobot _robot) {
		this.robot = _robot;
	}
	
	public void onScannedRobot(ScannedRobotEvent e) {
		double enemyAbsoluteBearing = robot.getHeadingRadians() + e.getBearingRadians();
		double enemyDistance = e.getDistance();
		Point2D robotLocation = new Point2D.Double(robot.getX(), robot.getY());
		Point2D enemyLocation = GFTUtils.project(robotLocation, enemyAbsoluteBearing, enemyDistance);
		Point2D robotDestination;
		double tries = 0;
		while (!fieldRectangle.contains(robotDestination = GFTUtils.project(enemyLocation, enemyAbsoluteBearing + Math.PI + direction,
				enemyDistance * (DEFAULT_EVASION - tries / 100.0))) && tries < MAX_TRIES) {
			tries++;
		}
		if ((Math.random() < (GFTUtils.bulletVelocity(enemyFirePower) / REVERSE_TUNER) / enemyDistance ||
				tries > (enemyDistance / GFTUtils.bulletVelocity(enemyFirePower) / WALL_BOUNCE_TUNER))) {
			direction = -direction;
		}
		// Jamougha's cool way
		double angle = GFTUtils.absoluteBearing(robotLocation, robotDestination) - robot.getHeadingRadians();
		robot.setAhead(Math.cos(angle) * 100);
		robot.setTurnRightRadians(Math.tan(angle));
	}
}

What's next for your robot?

  • I must document the code to make this tutorial thing to really work. You're more than welcome to help in this.

What other robot(s) is it based on?

Aristocles - both gun and movement