package cslib;
import robocode.*;
import java.awt.Color;
/**
* SnippetBot - a robot by Alisdair Owens
* This bot includes all sorts of useful snippets. It is not
* designed to be a good fighter (although it does well 1v1),
* just to show how certain things are done
* Bits of code lifted from Nicator and Chrisbot
* Conventions in this bot include: Use of radians throughout
* Storing absolute positions of enemy bots rather than relative ones
* Very little code in events
* These are all good programming practices for robocode
* There may also be methods that arent used; these might just be useful for you.
*/
public class SnippetBot extends AdvancedRobot
{
/**
* run: SnippetBot's default behavior
*/
Enemy target; //our current enemy
final double PI = Math.PI; //just a constant
int direction = 1; //direction we are heading...1 = forward, -1 = backwards
double firePower; //the power of the shot we will be using - set by do firePower()
public void run() {
target = new Enemy();
target.distance = 100000; //initialise the distance so that we can select a target
setColors(Color.red,Color.blue,Color.green); //sets the colours of the robot
//the next two lines mean that the turns of the robot, gun and radar are independant
setAdjustGunForRobotTurn(true);
setAdjustRadarForGunTurn(true);
turnRadarRightRadians(2*PI); //turns the radar right around to get a view of the field
while(true) {
doMovement(); //Move the bot
doFirePower(); //select the fire power to use
doScanner(); //Oscillate the scanner over the bot
doGun();
out.println(target.distance); //move the gun to predict where the enemy will be
fire(firePower);
execute(); //execute all commands
}
}
void doFirePower() {
firePower = 400/target.distance;//selects a bullet power based on our distance away from the target
}
void doMovement() {
if (getTime()%20 == 0) { //every twenty 'ticks'
direction *= -1; //reverse direction
setAhead(direction*300); //move in that direction
}
setTurnRightRadians(target.bearing + (PI/2)); //every turn move to circle strafe the enemy
}
void doScanner() {
double radarOffset;
if (getTime() - target.ctime > 4) { //if we haven't seen anybody for a bit....
radarOffset = 360; //rotate the radar to find a target
} else {
//next is the amount we need to rotate the radar by to scan where the target is now
radarOffset = getRadarHeadingRadians() - absbearing(getX(),getY(),target.x,target.y);
//this adds or subtracts small amounts from the bearing for the radar to produce the wobbling
//and make sure we don't lose the target
if (radarOffset < 0)
radarOffset -= PI/8;
else
radarOffset += PI/8;
}
//turn the radar
setTurnRadarLeftRadians(NormaliseBearing(radarOffset));
}
void doGun() {
//works out how long it would take a bullet to travel to where the enemy is *now*
//this is the best estimation we have
long time = getTime() + (int)(target.distance/(20-(3*firePower)));
//offsets the gun by the angle to the next shot based on linear targeting provided by the enemy class
double gunOffset = getGunHeadingRadians() - absbearing(getX(),getY(),target.guessX(time),target.guessY(time));
setTurnGunLeftRadians(NormaliseBearing(gunOffset));
}
//if a bearing is not within the -pi to pi range, alters it to provide the shortest angle
double NormaliseBearing(double ang) {
if (ang > PI)
ang -= 2*PI;
if (ang < -PI)
ang += 2*PI;
return ang;
}
//if a heading is not within the 0 to 2pi range, alters it to provide the shortest angle
double NormaliseHeading(double ang) {
if (ang > 2*PI)
ang -= 2*PI;
if (ang < 0)
ang += 2*PI;
return ang;
}
//returns the distance between two x,y coordinates
public double getrange( double x1,double y1, double x2,double y2 )
{
double xo = x2-x1;
double yo = y2-y1;
double h = Math.sqrt( xo*xo + yo*yo );
return h;
}
//gets the absolute bearing between to x,y coordinates
public double absbearing( double x1,double y1, double x2,double y2 )
{
double xo = x2-x1;
double yo = y2-y1;
double h = getrange( x1,y1, x2,y2 );
if( xo > 0 && yo > 0 )
{
return Math.asin( xo / h );
}
if( xo > 0 && yo < 0 )
{
return Math.PI - Math.asin( xo / h );
}
if( xo < 0 && yo < 0 )
{
return Math.PI + Math.asin( -xo / h );
}
if( xo < 0 && yo > 0 )
{
return 2.0*Math.PI - Math.asin( -xo / h );
}
return 0;
}
/**
* onScannedRobot: What to do when you see another robot
*/
public void onScannedRobot(ScannedRobotEvent e) {
//if we have found a closer robot....
if ((e.getDistance() < target.distance)||(target.name == e.getName())) {
//the next line gets the absolute bearing to the point where the bot is
double absbearing_rad = (getHeadingRadians()+e.getBearingRadians())%(2*PI);
//this section sets all the information about our target
target.name = e.getName();
target.x = getX()+Math.sin(absbearing_rad)*e.getDistance(); //works out the x coordinate of where the target is
target.y = getY()+Math.cos(absbearing_rad)*e.getDistance(); //works out the y coordinate of where the target is
target.bearing = e.getBearingRadians();
target.head = e.getHeadingRadians();
target.ctime = getTime(); //game time at which this scan was produced
target.speed = e.getVelocity();
target.distance = e.getDistance();
}
}
public void onRobotDeath(RobotDeathEvent e) {
if (e.getName() == target.name)
target.distance = 10000; //this will effectively make it search for a new target
}
}
class Enemy {
/*
* ok, we should really be using accessors and mutators here,
* (i.e getName() and setName()) but life's too short.
*/
String name;
public double bearing;
public double head;
public long ctime; //game time that the scan was produced
public double speed;
public double x,y;
public double distance;
public double guessX(long when)
{
long diff = when - ctime;
return x+Math.sin(head)*speed*diff;
}
public double guessY(long when)
{
long diff = when - ctime;
return y+Math.cos(head)*speed*diff;
}
}