CS Bot
Hello. The name is Ray Mark, and I'm new to robocode. I've taken an AP Java course and all, so I'm pretty good with the Java aspect of robocoding. But the Robocode api is slightly confusing and I was wondering if anyone could help me out.
Basically, I made a basic robot and followed the guess factor guide and the wave surfing guide and put those code segments together to see what would happen. After debugging it all, I compiled the code to find this result: Alone, the guess factor targeting works If the wave surfing is enabled, the robot moves... but the GFT doesn't work anymore. Instead the bot just fires like a crazy flailing fish. If the wave surfing is commented out, then the GFT code works again.
Can anyone take a look at the code and see what I need to fix? (the code is directly from the tutorials, i'm using the code to get a better idea of robocode)
package sd;
import robocode.*;
import java.util.ArrayList;
import java.util.List;
import robocode.util.Utils;
import java.awt.geom.*;
import java.util.ArrayList;
import java.lang.*;
import sd.EnemyWave;
//import java.awt.Color;
/**
* ProjectBot - a robot by me
*/
public class ProjectBot extends AdvancedRobot
{
/**
* All defined Variables go here:
*/
List waves = new ArrayList();
static int[][] stats = new int[13][31]; //31 is the number of unique guessfactors to be used
int direction = 1;
//private int timeSinceLastScan = 10; //radar vars
//static double enemyAbsoluteBearing;
public static int BINS = 47; //Wave Surf vars*
public static double _surfStats[] = new double[BINS];
public Point2D.Double _myLocation; // our bot's location
public Point2D.Double _enemyLocation; // enemy bot's location
public ArrayList _enemyWaves;
public ArrayList _surfDirections;
public ArrayList _surfAbsBearings;
public static double _oppEnergy = 100.0;//*end
/** This rectangle represents an 800x600 battle field, used for a simple, iterative WallSmoothing method
* the wall stick indicates the amount of space to have between wall and bot.
*/
public static Rectangle2D.Double _fieldRect = new java.awt.geom.Rectangle2D.Double(18, 18, 764, 564);
public static double WALL_STICK = 160;
/**
* run: ProjectBot's default behavior
*/
public void run() {
// After trying out your robot, try uncommenting the import at the top,
// and the next line:
//setColors(Color.red,Color.blue,Color.green);
_enemyWaves = new ArrayList(); //surf code
_surfDirections = new ArrayList();
_surfAbsBearings = new ArrayList();
setAdjustGunForRobotTurn(true);
setAdjustRadarForGunTurn(true); //
do {
// doScanner();
// execute();
turnRadarRightRadians(Double.POSITIVE_INFINITY);
/*ahead(100); //re code
turnGunRight(360);
back(100);
turnGunRight(360);*/
} while (true);
/*while(true) {
// Replace the next 4 lines with any behavior you would like
//turnRadarRight(Double.POSITIVE_INFINITY);
ahead(100);
turnGunRight(360);
back(100);
turnGunRight(360);
}*/
}
/**
* onScannedRobot: What to do when you see another robot
*/
public void onScannedRobot(ScannedRobotEvent e) {
//fire(1);
/******************************
*WAVE SURFING STARTS HERE
*******************************/
_myLocation = new Point2D.Double(getX(), getY());
double lateralVelocity = getVelocity()*Math.sin(e.getBearingRadians());
double absBearingWS = e.getBearingRadians() + getHeadingRadians();
setTurnRadarRightRadians(Utils.normalRelativeAngle(absBearingWS
- getRadarHeadingRadians()) * 2);
_surfDirections.add(0,
new Integer((lateralVelocity >= 0) ? 1 : -1));
_surfAbsBearings.add(0, new Double(absBearingWS + Math.PI));
double bulletPower = _oppEnergy - e.getEnergy();
if (bulletPower < 3.01 && bulletPower > 0.09
&& _surfDirections.size() > 2) {
EnemyWave ew = new EnemyWave();
ew.fireTime = getTime() - 1;
ew.bulletVelocity = EnemyWave.bulletVelocityMethod(bulletPower);
ew.distanceTraveled = EnemyWave.bulletVelocityMethod(bulletPower);
ew.direction = ((Integer)_surfDirections.get(2)).intValue();
ew.directAngle = ((Double)_surfAbsBearings.get(2)).doubleValue();
ew.fireLocation = (Point2D.Double)_enemyLocation.clone(); // last tick
_enemyWaves.add(ew);
}
_oppEnergy = e.getEnergy();
// update after EnemyWave detection, because that needs the previous
// enemy location as the source of the wave
_enemyLocation = EnemyWave.project(_myLocation, absBearingWS, e.getDistance());
updateWaves();
doSurfing();
/************************************************
*GUESSFACTOR STARTS HERE
************************************************/
double absBearing = getHeadingRadians() + e.getBearingRadians();
//find the enemy's location:
double ex = getX() + Math.sin(absBearing)*e.getDistance();
double ey = getY() + Math.cos(absBearing)*e.getDistance();
//process the waves:
for (int i=0; i<waves.size(); i++)
{
WaveBullet currentWave = (WaveBullet)waves.get(i);
if (currentWave.checkHit(ex, ey, getTime()))
{
waves.remove(currentWave);
i--;
}
}
double power = Math.min(3, Math.max(.1, 10/* some function */));
//don't try to figure out the direction they're moving if they're not moving, just use the direction we had before
if (e.getVelocity() != 0)
if (Math.sin(e.getHeadingRadians()-absBearing)*e.getVelocity() < 0)
direction = -1;
else
direction = 1;
int[] currentStats = stats[(int)(e.getDistance()/100)];
WaveBullet newWave = new WaveBullet(getX(), getY(), absBearing, power, direction, getTime(), currentStats);
int bestindex = 15; //initialize it in the middle, guessfactor 0.
for (int i=0; i<31; i++)
if (currentStats[bestindex] < currentStats[i])
bestindex = i;
//this should do the opposite of the math in the WaveBullet:
double guessfactor = (double)(bestindex-(stats.length-1)/2)/((stats.length-1)/2);
double angleOffset = direction*guessfactor*newWave.maxEscapeAngle();
setTurnGunRightRadians(robocode.util.Utils.normalRelativeAngle(absBearing-getGunHeadingRadians()+angleOffset));
//fire(1);
if (setFireBullet(1) != null)
fire(1);
waves.add(newWave);
//setTurnRadarRightRadians(Utils.normalRelativeAngle(e.getBearingRadians() + getHeadingRadians() - getRadarHeadingRadians()));
//enemyAbsoluteBearing = getHeadingRadians() + e.getBearingRadians(); //radar code
//timeSinceLastScan = 0;
}
/**
* onHitByBullet: What to do when you're hit by a bullet
*/
public void onHitByBullet(HitByBulletEvent e) { //WAVE SURF METHOD
//turnLeft(90 - e.getBearing()); //default code
// If the _enemyWaves collection is empty, scan must have missed the
// detection of this wave somehow.
if (!_enemyWaves.isEmpty()) {
Point2D.Double hitBulletLocation = new Point2D.Double(
e.getBullet().getX(), e.getBullet().getY());
EnemyWave hitWave = null;
// look through the EnemyWaves, and find one that could've hit the bot.
for (int x = 0; x < _enemyWaves.size(); x++) {
EnemyWave ew = (EnemyWave)_enemyWaves.get(x);
if (Math.abs(ew.distanceTraveled -
_myLocation.distance(ew.fireLocation)) < 50
&& Math.round(EnemyWave.bulletVelocityMethod(e.getBullet().getPower()) * 10)
== Math.round(ew.bulletVelocity * 10)) {
hitWave = ew;
break;
}
}
if (hitWave != null) {
logHit(hitWave, hitBulletLocation);
//remove this wave now
_enemyWaves.remove(_enemyWaves.lastIndexOf(hitWave));
}
}
}
/* private void doScanner() { //radar scanner
timeSinceLastScan++;
double radarOffset = Double.POSITIVE_INFINITY;
if(timeSinceLastScan < 3) {
radarOffset = robocode.util.Utils.normalRelativeAngle(getRadarHeadingRadians() - enemyAbsoluteBearing);
radarOffset += sign(radarOffset) * 0.02;
}
setTurnRadarLeftRadians(radarOffset);
}
int sign(double v) {
return v > 0 ? 1 : -1;
}*/
/*************************
*Wave Surf algo-methods
**************************/
public void updateWaves() { //update distance of wave and source, delete waves behind bot.
for (int x = 0; x < _enemyWaves.size(); x++) {
EnemyWave ew = (EnemyWave)_enemyWaves.get(x);
ew.distanceTraveled = (getTime() - ew.fireTime) * ew.bulletVelocity;
if (ew.distanceTraveled >
_myLocation.distance(ew.fireLocation) + 50) {
_enemyWaves.remove(x);
x--;
}
}
}
public EnemyWave getClosestSurfableWave() { //finds closest wave in front of bot
double closestDistance = 50000; // just use some very big number here
EnemyWave surfWave = null;
for (int x = 0; x < _enemyWaves.size(); x++) {
EnemyWave ew = (EnemyWave)_enemyWaves.get(x);
double distance = _myLocation.distance(ew.fireLocation)
- ew.distanceTraveled;
if (distance > ew.bulletVelocity && distance < closestDistance) {
surfWave = ew;
closestDistance = distance;
}
}
return surfWave;
}
// Given the EnemyWave that the bullet was on, and the point where we
// were hit, calculate the index into our stat array for that factor.
public static int getFactorIndex(EnemyWave ew, Point2D.Double targetLocation) {
double offsetAngle = (EnemyWave.absoluteBearing(ew.fireLocation, targetLocation)- ew.directAngle);
double factor = Utils.normalRelativeAngle(offsetAngle) / EnemyWave.maxEscapeAngle(ew.bulletVelocity) * ew.direction;
return (int)EnemyWave.limit(0,(factor * ((BINS - 1) / 2)) + ((BINS - 1) / 2),BINS - 1);
}
// Given the EnemyWave that the bullet was on, and the point where we
// were hit, update our stat array to reflect the danger in that area.
public void logHit(EnemyWave ew, Point2D.Double targetLocation) {
int index = getFactorIndex(ew, targetLocation);
for (int x = 0; x < BINS; x++) {
// for the spot bin that we were hit on, add 1;
// for the bins next to it, add 1 / 2;
// the next one, add 1 / 5; and so on...
_surfStats[x] += 1.0 / (Math.pow(index - x, 2) + 1);
}
}
public Point2D.Double predictPosition(EnemyWave surfWave, int direction) {
//This code predictions the positions for angle of movement based on enemy waves, ticks, and directions and tries to orbit angle
Point2D.Double predictedPosition = (Point2D.Double)_myLocation.clone();
double predictedVelocity = getVelocity();
double predictedHeading = getHeadingRadians();
double maxTurning, moveAngle, moveDir;
int counter = 0; // number of ticks in the future
boolean intercepted = false;
do {
moveAngle =
EnemyWave.wallSmoothing(predictedPosition, EnemyWave.absoluteBearing(surfWave.fireLocation,
predictedPosition) + (direction * (Math.PI/2)), direction)
- predictedHeading;
moveDir = 1;
if(Math.cos(moveAngle) < 0) {
moveAngle += Math.PI;
moveDir = -1;
}
moveAngle = Utils.normalRelativeAngle(moveAngle);
// maxTurning is built in like this, you can't turn more then this in one tick
maxTurning = Math.PI/720d*(40d - 3d*Math.abs(predictedVelocity));
predictedHeading = Utils.normalRelativeAngle(predictedHeading + EnemyWave.limit(-maxTurning, moveAngle, maxTurning));
//if predictedVelocity and moveDir have
// different signs you want to breack down
// otherwise you want to accelerate (look at the factor "2")
predictedVelocity += (predictedVelocity * moveDir < 0 ? 2*moveDir : moveDir);
predictedVelocity = EnemyWave.limit(-8, predictedVelocity, 8);
// calculate the new predicted position
predictedPosition = EnemyWave.project(predictedPosition, predictedHeading, predictedVelocity);
counter++;
if (predictedPosition.distance(surfWave.fireLocation) <
surfWave.distanceTraveled + (counter * surfWave.bulletVelocity)
+ surfWave.bulletVelocity) {
intercepted = true;
}
} while(!intercepted && counter < 500);
return predictedPosition;
}
public double checkDanger(EnemyWave surfWave, int direction) {
int index = getFactorIndex(surfWave,
predictPosition(surfWave, direction));
return _surfStats[index];
}
public void doSurfing() {
EnemyWave surfWave = getClosestSurfableWave();
if (surfWave == null) { return; }
double dangerLeft = checkDanger(surfWave, -1);
double dangerRight = checkDanger(surfWave, 1);
double goAngle = EnemyWave.absoluteBearing(surfWave.fireLocation, _myLocation);
if (dangerLeft < dangerRight) {
goAngle = EnemyWave.wallSmoothing(_myLocation, goAngle - (Math.PI/2), -1);
} else {
goAngle = EnemyWave.wallSmoothing(_myLocation, goAngle + (Math.PI/2), 1);
}
EnemyWave.setBackAsFront(this, goAngle);
}
}
package sd;
import robocode.*;
import robocode.util.Utils;
import java.awt.geom.*; // for Point2D's
import java.lang.*; // for Double and Integer objects
import java.util.ArrayList; // for collection of waves
/********************
* EnemyWave Class
* Helps Wave Surfing
*********************/
public class EnemyWave {
Point2D.Double fireLocation;
long fireTime;
double bulletVelocity, directAngle, distanceTraveled;
int direction;
public static double WALL_STICK = 160;
public static Rectangle2D.Double _fieldRect = new java.awt.geom.Rectangle2D.Double(18, 18, 764, 564);
public EnemyWave() { }
// }
public static double wallSmoothing(Point2D.Double botLocation, double angle, int orientation) {
while (!_fieldRect.contains(project(botLocation, angle, WALL_STICK))) {
angle += orientation*0.05;
}
return angle;
}
public static Point2D.Double project(Point2D.Double sourceLocation,
double angle, double length) {
return new Point2D.Double(sourceLocation.x + Math.sin(angle) * length,
sourceLocation.y + Math.cos(angle) * length);
}
public static double absoluteBearing(Point2D.Double source, Point2D.Double target) {
return Math.atan2(target.x - source.x, target.y - source.y);
}
public static double limit(double min, double value, double max) {
return Math.max(min, Math.min(value, max));
}
public static double bulletVelocityMethod(double power) {
return (20.0 - (3.0*power));
}
public static double maxEscapeAngle(double velocity) {
return Math.asin(8.0/velocity);
}
public static void setBackAsFront(AdvancedRobot robot, double goAngle) {
double angle =
Utils.normalRelativeAngle(goAngle - robot.getHeadingRadians());
if (Math.abs(angle) > (Math.PI/2)) {
if (angle < 0) {
robot.setTurnRightRadians(Math.PI + angle);
} else {
robot.setTurnLeftRadians(Math.PI - angle);
}
robot.setBack(100);
} else {
if (angle < 0) {
robot.setTurnLeftRadians(-1*angle);
} else {
robot.setTurnRightRadians(angle);
}
robot.setAhead(100);
}
}
}
package sd;
import java.awt.geom.*;
import robocode.util.Utils;
/**
* MyClass - a class by (your name here)
*/
public class WaveBullet
{
private double startx, starty, startBearing, power;
private long fireTime;
private int direction;
private int[] returnSegment;
public WaveBullet(double x, double y, double bearing, double power, int direction, long time, int[] segment)
{
startx = x;
starty = y;
startBearing = bearing;
this.power = power;
this.direction = direction;
fireTime = time;
returnSegment = segment;
}
public double getBulletSpeed()
{
return 20-power*3;
}
public double maxEscapeAngle()
{
return Math.asin(8/getBulletSpeed());
}
public boolean checkHit(double enemyX, double enemyY, long currentTime)
{
//if the distance from the wave origin to our enemy has passed the distance the bullet would have traveled...
if (Point2D.distance(startx, starty, enemyX, enemyY) <= (currentTime-fireTime)*getBulletSpeed())
{
double desiredDirection = Math.atan2(enemyX-startx, enemyY-starty);
double angleOffset = Utils.normalRelativeAngle(desiredDirection-startBearing);
double guessFactor = Math.max(-1, Math.min(1, angleOffset/maxEscapeAngle()))*direction;
int index = (int)Math.round((returnSegment.length-1)/2*(guessFactor+1));
returnSegment[index]++;
return true;
}
return false;
}
}
--
Any input would be really really helpful! Thanks!