import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.Iterator;
import java.util.Vector;
import robocode.AdvancedRobot;
import robocode.Bullet;
import robocode.DeathEvent;
import robocode.ScannedRobotEvent;
import robocode.WinEvent;
public class VirtualGunsSampleBot extends AdvancedRobot {
static final double BULLET_POWER = 3.0;
RobotState me, target; // these aren't static, so they will be reset every round
static Vector guns; // this Vector (and all its contents) will persist from round to round
static Vector virtualBullets = new Vector();
Rectangle2D.Double battlefield;
public void run(){
setAdjustGunForRobotTurn(true);
setAdjustRadarForGunTurn(true);
setAdjustRadarForRobotTurn(true);
battlefield = new Rectangle2D.Double(0,0,getBattleFieldWidth(), getBattleFieldHeight());
if(guns == null){
guns = new Vector();
Gun defaultGun = new ReallyBadGun();
defaultGun.hits = 1;
guns.add(defaultGun);
guns.add(new HeadOnGun());
guns.add(new RandomGun());
}
virtualBullets.clear();
while(true){
//Update our position, heading, and velocity
me = new RobotState();
me.name = getName();
me.velocity = getVelocity();
me.heading = getHeadingRadians();
me.x = getX();
me.y = getY();
//Turn our radar
if(target == null)
setTurnRadarRightRadians(Math.toRadians(45));
else {
double radarTurnAngle = normalizeRelativeAngle(me.absoluteAngleTo(target) - getRadarHeadingRadians());
if(radarTurnAngle > 0)
radarTurnAngle += .4;
else
radarTurnAngle -= .4;
setTurnRadarRightRadians(radarTurnAngle);
}
//Move each virtual bullet forward one tick. After moving, check if they are off the field or near the target.
Iterator i = virtualBullets.iterator();
while(i.hasNext()){
VirtualBullet virtualBullet = (VirtualBullet) i.next();
virtualBullet.setLocation(virtualBullet.project(virtualBullet.heading, virtualBullet.velocity));
if(virtualBullet.distance(target) < 25){ //check if the virtual bullet "hit" the enemy
virtualBullet.gunUsed.hits += 1;
i.remove();
} else if(!battlefield.contains(virtualBullet)){ //check if the virtual bullet is off the field
i.remove();
}
}
if(target != null) gun();
execute();
}
}
public void gun(){
//Select the best gun
long bestScore = -1;
Gun bestGun = null;
Iterator i = guns.iterator();
while(i.hasNext()){
Gun gun = (Gun) i.next();
if(gun.hits > bestScore){
bestScore = gun.hits;
bestGun = gun;
}
}
//Aim with the best gun
setTurnGunRightRadians(normalizeRelativeAngle(bestGun.getFiringAngle(me, target, BULLET_POWER) - getGunHeadingRadians()));
// create new virtual bullets only if we actually fired this turn
Bullet b = setFireBullet(BULLET_POWER);
if(b != null){
i = guns.iterator();
while(i.hasNext()){
Gun gun = (Gun) i.next();
VirtualBullet newVirtualBullet = new VirtualBullet();
newVirtualBullet.setLocation(me);
newVirtualBullet.heading = gun.getFiringAngle(me, target, BULLET_POWER);
newVirtualBullet.velocity = 20.0 - 3.0 * BULLET_POWER;
newVirtualBullet.gunUsed = gun;
virtualBullets.add(newVirtualBullet);
}
}
}
public void onScannedRobot(ScannedRobotEvent e){
// Create a new RobotState object to represent the enemy's current state
target = new RobotState();
target.setLocation(me.project(e.getBearingRadians() + getHeadingRadians(), e.getDistance()));
target.heading = e.getHeadingRadians();
target.velocity = e.getVelocity();
target.name = e.getName();
}
public void onDeath(DeathEvent e){
endRound();
}
public void onWin(WinEvent e){
endRound();
}
public void endRound(){
Iterator i = guns.iterator();
out.println();
out.println("Virtual bullet hit table");
out.println("------------------------");
while(i.hasNext()){
Gun gun = (Gun) i.next();
out.println(gun.getName() + ": " + gun.hits);
}
out.println();
//So we don't keep firing
target = null;
}
//Draw the virtual bullets on screen - this will only work with a recent version of robocode and "Paint" turned on in the robot's console
public void onPaint(Graphics2D g){
Iterator i = virtualBullets.iterator();
while(i.hasNext()){
VirtualBullet virtualBullet = (VirtualBullet) i.next();
g.setColor(virtualBullet.gunUsed.getColor());
g.fillOval((int)virtualBullet.x - 3, (int)virtualBullet.y -3, 6, 6);
}
int numberOfGuns = guns.size();
for(int j = 0; j < numberOfGuns; j++){
Gun gun = (Gun) guns.elementAt(j);
g.setColor(Color.WHITE);
g.drawString(gun.getName() + ": " + gun.hits, 20, 5 + j*15);
g.setColor(gun.getColor());
g.fillOval(5, 5 + j * 15, 10, 10);
}
}
//This method ensures that angles are between -180 and 180 degrees, for turning radar / gun
public static double normalizeRelativeAngle(double angle){
while(angle <= -Math.PI){
angle += 2.0 * Math.PI;
}
while(angle > Math.PI){
angle -= 2.0 * Math.PI;
}
return angle;
}
}
class ReallyBadGun extends Gun{
public String getName(){return "Really bad gun - fires away from the enemy";}
public Color getColor(){return Color.RED;}
public double getFiringAngle(RobotState shooter, RobotState target, double bulletPower) {
return target.absoluteAngleTo(shooter);
}
}
class RandomGun extends Gun {
public String getName(){return "Simple linear gun";}
public Color getColor(){return Color.BLUE;}
public double getFiringAngle(RobotState shooter, RobotState target, double bulletPower) {
//double maxAngle = Math.asin(8.0 / (20.0 - 3.0 * bulletPower));
double directAngle = shooter.absoluteAngleTo(target);
return directAngle - target.velocity * Math.sin(directAngle - target.heading) / (20.0 - 3.0 * bulletPower);
}
}
class HeadOnGun extends Gun {
public String getName(){return "Head on";}
public Color getColor(){return Color.GREEN;}
public double getFiringAngle(RobotState shooter, RobotState target, double bulletPower) {
return shooter.absoluteAngleTo(target);
}
}
abstract class Gun {
public long hits;
public abstract Color getColor();
public abstract String getName();
public abstract double getFiringAngle(RobotState shooter, RobotState target, double bulletPower);
}
class FieldPoint extends Point2D.Double{
public FieldPoint(){}
public FieldPoint(double x, double y){
super(x,y);
}
public double absoluteAngleTo(FieldPoint p){
double angle = Math.atan2(p.x - x, p.y - y);
while(angle < 0.0){
angle += 2.0 * Math.PI;
}
while(angle >= 2.0 * Math.PI){
angle -= 2.0 * Math.PI;
}
return angle;
}
public FieldPoint project(double angle, double distance) {
return new FieldPoint(x + Math.sin(angle) * distance, y + Math.cos(angle) * distance);
}
}
class MotionState extends FieldPoint{
public double velocity, heading;
}
class VirtualBullet extends MotionState{
public Gun gunUsed;
}
class RobotState extends MotionState{
public String name;
}