[Home]GouldingiHT/Code

Robo Home | GouldingiHT | Changes | Preferences | AllPages

No diff available--this is the first major revision. (no other diffs)
OK. So here's the full source of GouldingiHT. It's a minibot as it is, but with an additional movement system and a system to choose the best of these movements against a given enemy this could very well become a top-5 bot on EternalRumble.
package wiki.mini;
import robocode.*;
import java.awt.geom.*;
import java.awt.Color;
import java.util.*;

// GouldingiHT - Small, hard to catch and with sharp teeth.
// Targeting, from Gouldingi, by PEZ
// Movement, from FloodMicro, by Kawigi
//
// GouldingiHT is open source under GPL-like conditions. Meaning you can use
// the code. Meaning you should feel obliged to share any improvements you do
// to the code. Meaning you must release your bots code if you directly use this
// code.
//
// Home page of this bot is: http://robowiki.dyndns.org/?GouldingiHT
// The code should be available there and it is also the place for you to share any
// code improvements.
//
// $Id: GouldingiHT.java,v 1.2 2003/04/21 19:54:06 peter Exp $

public class GouldingiHT extends AdvancedRobot {
    private static Point2D location = new Point2D.Double();
    private static Point2D oldLocation = new Point2D.Double();
    private static Point2D enemyLocation = new Point2D.Double();
    private static Point2D oldEnemyLocation = new Point2D.Double();
    private static Rectangle2D fieldRectangle;
    private static double enemyDistance;
    private static double enemyEnergy;
    private static double deltaBearing;
    private static double meanOffsetFactor;
    private static double meanAimFactorLeft;
    private static double meanAimFactorStraight;
    private static double meanAimFactorRight;
    private static double currentDirection=40;
    private static double currentVBound;
    private static int distanceindex;
    private long nextTime;
    //I'd never need 100 things in these arrays except on an extremely large battlefield.
    //Of course I can't see stuff 5000 away anyways, I suppose a little more than 20 would do...
    private static double[] benefit = new double[100], penalty = new double[100];

    public void run() {
        fieldRectangle = new Rectangle2D.Double(0, 0 , getBattleFieldWidth(), getBattleFieldHeight());
        //setColors(Color.gray, Color.yellow, Color.black);
        setAdjustGunForRobotTurn(true);
        setAdjustRadarForGunTurn(true);

        enemyEnergy = 100;
        setTurnRadarRightRadians(Double.POSITIVE_INFINITY); 

        do {
            initMovement();
            if (getEnergy() > .1 && enemyEnergy > 0) {
                double power = Math.min(getEnergy() / 3, Math.min(enemyEnergy / 4, 3));
                Bullet bullet = setFireBullet(power);
                if (bullet != null) {
                    //penalty for firing because I lose energy:
                    penalty[distanceindex] += power;
                    addCustomEvent(new CheckUpdateFactors(bullet));
                }
            }
            setAhead(currentDirection);
            execute();
        } while (true);
    }

    public void onScannedRobot(ScannedRobotEvent e) {
        oldLocation.setLocation(location);
        location.setLocation(getX(), getY());
        oldEnemyLocation.setLocation(enemyLocation);
        enemyDistance = e.getDistance();
        toLocation(getHeadingRadians() + e.getBearingRadians(), enemyDistance, location, enemyLocation);
        double denergy = enemyEnergy-e.getEnergy();
        if (denergy >= .09 && denergy <= 3) {
            benefit[distanceindex] += denergy;	//my benefit, because he lost energy to fire
            if (getTime() >= nextTime) {
                if (Math.random() < .5)
                    currentDirection = -currentDirection;
                currentVBound = Math.random()*12;
                nextTime = getTime()+(int)(enemyDistance/(30-4.5*denergy));
            }
        }
        enemyEnergy = e.getEnergy();
        move(e);
        aim();
        // Radar from Moebius - http://robowiki.dyndns.org/?Moebius
        setTurnRadarLeftRadians(getRadarTurnRemaining()); 
    }

    //Event handlers to 'keep score'.  Some calculations combined to save space:
    public void onHitByBullet(HitByBulletEvent e) {
        double power = e.getPower();
        penalty[distanceindex] += Math.max(power*7, power*9-2);
    }

    public void onBulletHit(BulletHitEvent e) {
        double power = e.getBullet().getPower();
        double damage = Math.max(4*power, 6*power-2);
        benefit[distanceindex] += damage+power*3;
    }

    private void initMovement() {
        //wall avoidance
        final double maxX = getBattleFieldWidth()-18D;
        final double maxY = getBattleFieldHeight()-18D;

        setMaxVelocity(currentVBound);
        double futureX = currentDirection*Math.sin(getHeadingRadians())+getX();
        double futureY = currentDirection*Math.cos(getHeadingRadians())+getY();
        if (futureX < 18D || futureY < 18D || futureX > maxX || futureY > maxY) {
            currentDirection = -currentDirection;
        }
    }

    //find distance to closest corner - this is trimmed down in codesize quite a bit, and uses some interesting bitwise operations.
    private double distanceFromCorner() {
        double min = Double.POSITIVE_INFINITY;
        for (int i=0; i<4; i++)
            min = Math.min(min, Point2D.distance(getX(), getY(), (i&1)*getBattleFieldWidth(), (i>>1)*getBattleFieldHeight()));
        return min;
    }

    private void move(ScannedRobotEvent e) {
        //index for benefit stats:
        distanceindex = (int)(enemyDistance/50);
        Point2D backwall = new Point2D.Double();
        //backwall is the point 30 behind me relative to the enemy- this 
        //is to detect if I've backed up against a wall.
        toLocation(absoluteBearing(enemyLocation, location), 30, location, backwall);
        double mindist = findDistanceBracket()+85;
        double rel;		//offset angle - move laterally, toward, or away?
        //addition - if backwall is outside the field, stay lateral.  This could have some side effects
        //if I wanted to go toward him, but I figure I'll move away from the wall a little soon and then
        //I can move toward him.
        if ((e.getDistance() < mindist && enemyDistance > mindist-120 && distanceFromCorner()>200 && distanceFromCorner() > enemyDistance) |! fieldRectangle.contains(backwall))
            rel = Math.PI/2;
        //the == in boolean expressions is essentially a logical xnor.
        else if ((e.getDistance() > mindist || distanceFromCorner() < 200) == currentDirection > 0)
            rel = Math.PI/3;
        else
            rel = 2*Math.PI/3;
        setTurnRightRadians(normalRelativeAngle(e.getBearingRadians()-rel));
    }

    //methods to find optimal search bracket.  Trimmed down a bit from how MakoHT does it, to save space:
    private double findDistanceBracket() {
        int bestindex = 4;
        for (int i=5; i <= 14; i++)
            if (findBenefit(i) > findBenefit(bestindex))
                bestindex = i;
        if (enemyEnergy == 0) {
            bestindex = -1;
        }
        return bestindex*50;
    }

    private double findBenefit(int index) {
        return (benefit[index]-penalty[index])/(benefit[index]+penalty[index]);
    }

    private void aim() {
        double meanAimFactor = meanAimFactorStraight;
        deltaBearing = normalRelativeAngle(absoluteBearing(oldLocation, enemyLocation) -
            absoluteBearing(oldLocation, oldEnemyLocation));
        if (deltaBearing < -0.005) {
            meanAimFactor = meanAimFactorLeft;
        }
        else if (deltaBearing > 0.005) {
            meanAimFactor = meanAimFactorRight;
        }
        double absoluteBearing = absoluteBearing(location, enemyLocation);
        double guessedHeading = absoluteBearing + meanOffsetFactor;
        if (Math.abs(deltaBearing) > 0.001) {
            guessedHeading = absoluteBearing + deltaBearing * meanAimFactor;
        }
        Point2D impactLocation = new Point2D.Double();
        toLocation(guessedHeading, enemyDistance, location, impactLocation);
        guessedHeading = absoluteBearing(location, impactLocation);
        setTurnGunRightRadians(normalRelativeAngle(guessedHeading - getGunHeadingRadians()));
    }

    private void toLocation(double angle, double length, Point2D sourceLocation, Point2D targetLocation) {
        targetLocation.setLocation(sourceLocation.getX() + Math.sin(angle) * length,
            sourceLocation.getY() + Math.cos(angle) * length);
    }

    private double absoluteBearing(Point2D source, Point2D target) {
        return Math.atan2(target.getX() - source.getX(), target.getY() - source.getY());
    }

    private double normalRelativeAngle(double angle) {
        return Math.atan2(Math.sin(angle), Math.cos(angle));
    }

    public double rollingAvg(double value, double newEntry, double n, double weighting ) {
        return (value * n + newEntry * weighting) / (n + weighting);
    } 

    class CheckUpdateFactors extends Condition {
        private long time;
        private double bulletVelocity;
        private double bulletPower;
        private double bearingDelta;
        private Point2D oldRLocation = new Point2D.Double();
        private Point2D oldELocation = new Point2D.Double();

        public CheckUpdateFactors(Bullet bullet) {
            this.time = getTime();
            this.bulletVelocity = bullet.getVelocity();
            this.bulletPower = bullet.getPower();
            this.bearingDelta = deltaBearing;
            this.oldRLocation.setLocation(location);
            this.oldELocation.setLocation(enemyLocation);
        }

        public boolean test() {
            double bulletDistance = bulletVelocity * (getTime() - time);
            if (getOthers() > 0 && bulletDistance > oldRLocation.distance(enemyLocation)) {
                double bearingDiff = normalRelativeAngle(absoluteBearing(oldRLocation, enemyLocation) -
                    absoluteBearing(oldRLocation, oldELocation));
                meanOffsetFactor = rollingAvg(meanOffsetFactor, bearingDiff, 20, bulletPower);
                if (Math.abs(bearingDelta) > 0.001) {
                    double factor = bearingDiff / bearingDelta;
                    if (bearingDelta < -0.05) {
                        meanAimFactorLeft = rollingAvg(meanAimFactorLeft, factor, 75, bulletPower);
                    }
                    else if (bearingDelta > 0.05) {
                        meanAimFactorRight = rollingAvg(meanAimFactorRight, factor, 75, bulletPower);
                    }
                    else {
                        meanAimFactorStraight = rollingAvg(meanAimFactorStraight, factor, 75, bulletPower);
                    }
                }
                removeCustomEvent(this);
            }
            return false;
        }
    }
}

Robo Home | GouldingiHT | Changes | Preferences | AllPages
Edit text of this page | View other revisions
Last edited April 24, 2003 23:07 EST by PEZ (diff)
Search: