Robo Home | Changes | Preferences | AllPages


By GrubbmGait and PEZ

What is it?

A MicroBot. The result of using Aristocles's gun on the mean RamBot GrubbmThree

It can be found here: http://www.robocoderepository.com/BotDetail.jsp?id=2864



RWPCL applies.

package wiki.micro;
import robocode.*;
import robocode.util.Utils;
import java.awt.Color;
import java.awt.geom.*;
 * ARAMtocles - ramming with GuessFactors
 * Gunnery of Aristocles by PEZ
 * rest of GrubbmThree by GrubbmGait (but that turns out to be very little)
 * RWPCL applies
 * Revision information:
 * v0.1 20060213 Initial version, shrunk GrubbmThree and GF-gun of Aristocles.
 *               No tuning of segmentation. 726 bytes
 * v0.2 20060213 Added reverse wall segmentation. Lowered the granularity in general to 
 *               accomodate to the short learning times ramming gives you. 732 bytes
 * v0.3 20060217 Removed reverse wall stuff.
 *               Rearranged distance segmentation and bulletpower. 707 bytes
public class ARAMtocles extends AdvancedRobot
    static final double MAX_DISTANCE = 450;
    static final double BULLET_SWITCH_DISTANCE = 180;
    static final double MAX_BULLET_POWER = 3.0;       // first two distance segments
    static final double BULLET_POWER = 1.9;           // third and fourth distance segment
    static final double WALL_MARGIN = 18;

    static final int DISTANCE_INDEXES = 5;
    static final int VELOCITY_INDEXES = 5;
    static final int LAST_VELOCITY_INDEXES = 5;
    static final int WALL_INDEXES = 2;
    static final int DECCEL_TIME_INDEXES = 5;
    static final int AIM_FACTORS = 25;
    static final int MIDDLE_FACTOR = (AIM_FACTORS - 1) / 2;

    static Rectangle2D.Double fireField;    // the shootable battlefield
    static Point2D enemyLocation;
    static double enemyVelocity;
    static int timeSinceDeccel;
    static double bearingDirection;
    static double enemyDistance;

     * run: ARAMtocles default behavior
    public void run() {

        setColors( Color.red, Color.blue, Color.yellow);

        fireField = new Rectangle2D.Double( WALL_MARGIN, WALL_MARGIN, getBattleFieldWidth() - WALL_MARGIN * 2, getBattleFieldHeight() - WALL_MARGIN * 2);

        // Let gun and radar move independently
        setAdjustGunForRobotTurn( true);
        setAdjustRadarForGunTurn( true);

        // mainloop
        do {
            turnRadarRight( Double.NEGATIVE_INFINITY);
        } while(true);

     * onScannedRobot: What to do when you see another robot
    public void onScannedRobot(ScannedRobotEvent e) {

        double tmpbearing = getHeadingRadians() + e.getBearingRadians();
        double turnAngle;

        // Lock target with radar
        setTurnRadarRightRadians( 2.2 * Utils.normalRelativeAngle( tmpbearing - getRadarHeadingRadians()));

        // perform Aristocles targeting
        Wave wave = new Wave();
        double enemyAbsoluteBearing = getHeadingRadians() + e.getBearingRadians();
        enemyLocation = project(wave.wGunLocation = new Point2D.Double(getX(), getY()), enemyAbsoluteBearing, enemyDistance = e.getDistance());

        int lastVelocityIndex = (int)Math.abs(enemyVelocity) / 2;
        int velocityIndex = (int)Math.abs((enemyVelocity = e.getVelocity()) / 2);
        if (velocityIndex < lastVelocityIndex) {
            timeSinceDeccel = 0;

        if (enemyVelocity != 0) {
            bearingDirection = enemyVelocity * Math.sin(e.getHeadingRadians() - enemyAbsoluteBearing) > 0 ?
            0.7 / (double)MIDDLE_FACTOR : -0.7 / (double)MIDDLE_FACTOR;
        wave.wBearingDirection = bearingDirection;

        int distanceIndex = (int)Math.min(DISTANCE_INDEXES - 1, enemyDistance / (MAX_DISTANCE / DISTANCE_INDEXES));
        wave.wBulletPower = enemyDistance > BULLET_SWITCH_DISTANCE ? BULLET_POWER : MAX_BULLET_POWER;
        //wave.wBulletPower = MAX_BULLET_POWER; // TargetingChallenge

        wave.wAimFactors = aimFactors[distanceIndex][velocityIndex][lastVelocityIndex][Math.min(DECCEL_TIME_INDEXES - 1, timeSinceDeccel++ / 13)]
            [fireField.contains(project(wave.wGunLocation, enemyAbsoluteBearing + wave.wBearingDirection * 13, enemyDistance)) ? 1 : 0];

        wave.wBearing = enemyAbsoluteBearing;

        int mostVisited = MIDDLE_FACTOR, i = AIM_FACTORS;
        do  {
            if (wave.wAimFactors[--i] > wave.wAimFactors[mostVisited]) {
                mostVisited = i;
        } while (i > 0);
        // end of Aristocles gun

        // Turn gun (still Aristocles, but keep tmpbearing for movement)
        tmpbearing = enemyAbsoluteBearing + wave.wBearingDirection * (mostVisited - MIDDLE_FACTOR);
        setTurnGunRightRadians( Utils.normalRelativeAngle( tmpbearing - getGunHeadingRadians()));

        if (enemyDistance <= (2 * BULLET_SWITCH_DISTANCE)) {
        // Aristocles
        if (getEnergy() >= BULLET_POWER) {
        // GT: Move towards target
        turnAngle = Utils.normalRelativeAngle( tmpbearing - getHeadingRadians());
        setTurnRightRadians( Math.atan( Math.tan( turnAngle)));
        setAhead( Double.POSITIVE_INFINITY * Math.cos( turnAngle));

     * onWin: Show my private victory dance
    public void onWin(WinEvent e)
        //Victory dance
        setTurnGunRight( Double.POSITIVE_INFINITY);
        setTurnRadarLeft( Double.POSITIVE_INFINITY);
        waitFor(new RadarTurnCompleteCondition(this));

    // Aristocles: helperfunctions and so
    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());

    class Wave extends Condition {
    double wBulletPower;
    Point2D wGunLocation;
    double wBearing;
    double wBearingDirection;
    int[] wAimFactors;
    double wDistance;

    public boolean test() {
        if ((wDistance += bulletVelocity(wBulletPower)) > wGunLocation.distance(enemyLocation) - 18) {
        try {
            wAimFactors[(int)Math.round(((Utils.normalRelativeAngle(absoluteBearing(wGunLocation, enemyLocation) - wBearing)) /
                wBearingDirection) + MIDDLE_FACTOR)]++;
        catch (Exception e) {
        return false;


Grub, I've tried to tune the segmentations some. Mainly it was about narrowing down the distance segmentation and also using less granularity. (There's not much time to learn during a ram fight.) I also added a reverse wall segmentation, which I am not sure it helps much now that I have watched a few fights with this bot. But anyway. Can you pack this up and release on the rumble for test? -- PEZ

Its up, lets see if can do some more damage. -- GrubbmGait

Again it doesn't look too promising. It could be something is buggy with the gun now, but probably it just means the gun just isn't cut for dealing with the extreme fast learning needed here. And at those fighting distances the circular targeting might just be better than bothering with stats. -- PEZ

I think you are right, each battle only lasts between 100 and 200 ticks, so there is almost no time for learning. I expected ARAMtocles to be an improvement against the better anti-rammers as running away seems quite predictable, but it seems that that can not compensate the lesser performance in the first rounds. -- GrubbmGait

This is a bit dissapointing, but I can't make this work even with low segmentation it seems. Poor ARAM seems to be a poor rammer compared to its ancestor and cousin. I say we remove it from the rumble until we have some more ideas on how to make it work. -- PEZ

PEZ, maybe an advancing velocity segment would be useful in this bot? It seems that a rammer might create exploitable behaviour in that dimension (since the enemy will most likely be moving away from you). Just a thought. --wcsv

It might. But to me it looks like most of the fight is carried at point blank. And then the circular prediction is 100% right while even one wrong guess from the learning gun will lower performance. (I've seen ARAMtocles miss while it looks to be ramming the opponent... The guns start heated so during the time it takes for the rammer to close in it can't fire anyway. Mayvbe I even should consider using linear or circular predictions in CassiusClay when I know I am dealing with a rammer. -- PEZ

The newest version basically goes back to v0.1, but with improved distance segmenting and bulletpower. It should at least end up around rating 1615. Further development (if any) will be done with the RambotChallenge2K6. A specialized GF-gun should be able to handle short rammer matches. -- GrubbmGait

I should not fiddle with things I know nothing about. In my tests over 500 rounds ARAMtocles 0.3 humiliates every other rambot, but over 35 rounds it gets kicked in the butt. Till now CircularTargeting seems unbeatable at close ranges. -- GrubbmGait

Robo Home | Changes | Preferences | AllPages
Edit text of this page | View other revisions
Last edited February 20, 2006 10:37 EST by GrubbmGait (diff)