Excession/DiveBomber

From Robowiki
< Excession
Revision as of 13:22, 13 June 2008 by Excession (talk | contribs) (Excession:SpiralCircle moved to Excession:DiveBomber: SpiralCircle drone renamed to DiveBomber)
Jump to navigation Jump to search

A Drone by User:Excession

package excession.drones;

import static java.lang.Math.E;
import static java.lang.Math.PI;
import static java.lang.Math.atan;
import static java.lang.Math.atan2;
import static java.lang.Math.min;
import static java.lang.Math.pow;
import static java.lang.Math.sqrt;
import static robocode.util.Utils.normalRelativeAngle;
import robocode.AdvancedRobot;
import robocode.ScannedRobotEvent;

/**
 * A drone that spirals in towards and then circles its enemy and fires pot
 * shots.
 * 
 * @author Excession
 * @version 1.0, 2008-06-04, released as SpiralCircle
 * @version 1.1, 2008-06-09, better spiraling with Gumpertz function, renamed to
 *          DiveBomber
 */
public class DiveBomber extends AdvancedRobot {

    private static final double DISTANCE = 200;
    private static final double SPEED = 20.0;
    private int direction = 1;

    private void init() {
        setAdjustRadarForRobotTurn(true);
        setAdjustGunForRobotTurn(true);
        setAdjustRadarForGunTurn(true);
    }

    @Override
    public void run() {
        init();
        setTurnRadarRightRadians(2 * PI);
        while (true) {
            execute();
        }
    }

    @Override
    public void onScannedRobot(ScannedRobotEvent event) {
        lockOnTarget(event);
        aimAndFire(event);
        move(event);
    }

    private void move(ScannedRobotEvent event) {
        double bearing = event.getBearingRadians();
        double range = event.getDistance();

        if (stopped()) {
            switchDirection();
        }

        double delta = range - DISTANCE;
        double spiral = gompertz(delta);

        double d = SPEED;
        double b = sqrt(range * range - (d * d) / 4);
        double alpha = atan2(b, (d / 2));
        double tankTurn = bearing - alpha + spiral * direction;

        setTurnRightRadians(tankTurn);
        setAhead(d * direction);
    }

    /**
     * Calculate Gompertz function with the following values.
     * 
     * <ul>
     * <li> a = PI/2 (90 degrees).
     * <li> b = -PI
     * <li> c = -0.01
     * </ul>
     * 
     * This allows us to sprial in nicely and then stabilize in a circular
     * orbit.
     * 
     * @param x
     * @return Gompertz function value for x
     * @see http://en.wikipedia.org/wiki/Gompertz_function
     */
    private double gompertz(double x) {
        double spiral = PI / 2 * (pow(E, (-PI * pow(E, -x * 0.01))));
        return spiral;
    }

    private boolean stopped() {
        return getVelocity() == 0.0;
    }

    private void switchDirection() {
        direction *= -1;
    }

    /**
     * @see http://testwiki.roborumble.org/w/index.php?title=Radar#Wide_lock
     */
    private void lockOnTarget(ScannedRobotEvent event) {
        double absoluteBearing = getHeadingRadians() + event.getBearingRadians();
        double radarTurn = normalRelativeAngle(absoluteBearing - getRadarHeadingRadians());
        double arcToScan = min(atan(36.0 / event.getDistance()), PI / 4.0);
        radarTurn += (radarTurn < 0) ? -arcToScan : arcToScan;
        setTurnRadarRightRadians(radarTurn);
    }

    private void aimAndFire(ScannedRobotEvent event) {
        double absoluteBearing = getHeadingRadians() + event.getBearingRadians();
        double gunTurn = normalRelativeAngle(absoluteBearing - getGunHeadingRadians());
        setTurnGunRightRadians(gunTurn);

        final double power = 3.0;
        if (getGunHeat() == 0.0) {
            setFire(power);
        }
    }
}