BlitzBat/Code

From Robowiki
Jump to navigation Jump to search
BlitzBat Sub-pages:
BlitzBatVersion History - Code

Code for BlitzBat 1.05. Code Size is 741 when compiled with Jikes. (I think 20+ for the colors.)

package voidious.micro;

import robocode.*;
import robocode.util.Utils;

import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.Color;
import java.util.Iterator;
import java.util.HashMap;
import java.util.ArrayList;

/**
 * BlizBat - a robot by Voidious
 *
 * A MicroBot melee specialist. Uses Minimum Risk movement and Head-On
 * Targeting. Initially whipped up one afternoon while working on
 * Diamond and waiting for test beds to run.
 *
 * Code is open source, released under the RoboWiki Public Code License:
 * http://robowiki.net/cgi-bin/robowiki?RWPCL
 */

public class BlitzBat extends AdvancedRobot {
    protected static final double TWO_PI = Math.PI * 2;
    protected static Rectangle2D.Double _fieldRect;
    protected static Point2D.Double _destination;
    protected static String _targetName;
    protected static double _targetDistance;
    protected static HashMap _enemies = new HashMap();
    protected static Point2D.Double _myLocation;
    protected ArrayList _recentLocations;
    
    public void run() {
        setAdjustGunForRobotTurn(true);
        setAdjustRadarForGunTurn(true);
        setColors(new Color(90, 40, 12), Color.black, Color.black);
        
        _fieldRect = new Rectangle2D.Double(50, 50, 
                getBattleFieldWidth() - 100, getBattleFieldHeight() - 100);
        _recentLocations = new ArrayList();
        _targetDistance = Double.POSITIVE_INFINITY;
        _destination = null;
        
        do {
            Point2D.Double myLocation = _myLocation = 
                new Point2D.Double(getX(), getY());
            _recentLocations.add(0, myLocation);
            EnemyData targetData = (EnemyData)_enemies.get(_targetName);
            /////////////////////////////////
            // Gun
            try {
                setTurnGunRightRadians(Utils.normalRelativeAngle(
                    absoluteBearing(myLocation, targetData) - 
                    getGunHeadingRadians()));
            } catch (NullPointerException ex) { }
            setFire(3 - ((20 - getEnergy()) / 6));
            /////////////////////////////////
            // Movement
            double bestRisk;
            try {
                bestRisk = evalDestinationRisk(_destination) * .85;
            } catch (NullPointerException ex) {
                bestRisk = Double.POSITIVE_INFINITY;
            }
            try {
                for (double d = 0; d < TWO_PI; d += 0.1) {
                    Point2D.Double newDest = project(myLocation, d,
                        Math.min(_targetDistance, 100 + Math.random() * 200));
                    double thisRisk = evalDestinationRisk(newDest);
                    if (_fieldRect.contains(newDest) &&
                            thisRisk < bestRisk) {
                        bestRisk = thisRisk;
                        _destination = newDest;
                    }
                }
                
                double angle = Utils.normalRelativeAngle(
                    absoluteBearing(myLocation, _destination) -
                    getHeadingRadians());
                setTurnRightRadians(Math.tan(angle));
                setAhead(Math.cos(angle) * Double.POSITIVE_INFINITY);
            } catch (NullPointerException ex) { }
            
            /////////////////////////////////
            // Radar and execute
            setTurnRadarRightRadians(1);
            execute();
            /////////////////////////////////
        } while (true);        
    }
    
    public void onScannedRobot(ScannedRobotEvent e) {
        double eDistance = e.getDistance();
        
        EnemyData eData = new EnemyData();
        eData.setLocation(project(_myLocation, e.getBearingRadians() + 
            getHeadingRadians(), eDistance));
        eData.energy = e.getEnergy();

        _enemies.put(e.getName(), eData);
        
        if (eDistance < _targetDistance || 
                e.getName().equals(_targetName)) {
            _targetDistance = eDistance;
            _targetName = e.getName();
        }
    }
    
    public void onRobotDeath(RobotDeathEvent e) {
        _enemies.remove(e.getName());
        _targetDistance = Double.POSITIVE_INFINITY;
    }
    
    protected double evalDestinationRisk(Point2D.Double d) {
        double risk = 0;
        
        Iterator enemiesIterator = _enemies.values().iterator();
        while (enemiesIterator.hasNext()) {
            EnemyData ed = (EnemyData)enemiesIterator.next();
            double distSq = ed.distanceSq(d);
            int closer = 0;
            Iterator enemiesIterator2 = _enemies.values().iterator();
            while (enemiesIterator2.hasNext()) {
                if (ed.distanceSq((EnemyData)enemiesIterator2.next()) 
                    < distSq) {
                    
                    closer++;
                }
            }

            risk += Math.max(0.5, Math.min(ed.energy / getEnergy(), 2))
                * (1 + Math.abs(Math.cos(absoluteBearing(_myLocation, d) - 
                        absoluteBearing(_myLocation, ed))))
//                * (12 + Math.sqrt(cornerDistance(d)))
                / closer
                / distSq
                / (200000 + d.distanceSq(
                    getBattleFieldWidth() / 2, getBattleFieldHeight() / 2));
        }
        
        for (int x = 1; x < 6; x++) {
            try {
                risk *= 1 + (500 / x / 
                    ((Point2D.Double)_recentLocations.get(x * 10))
                        .distanceSq(d));
            } catch (Exception ex) { }
        }
        
        return risk;
    }

    protected static double absoluteBearing(Point2D.Double source, Point2D.Double target) {
        return Math.atan2(target.x - source.x, target.y - source.y);
    }
    
    public static Point2D.Double project(Point2D.Double sourceLocation, 
        double angle, double length) {

        return new Point2D.Double(sourceLocation.x + Math.sin(angle) * length,
            sourceLocation.y + Math.cos(angle) * length);
    }
}

class EnemyData extends Point2D.Double{
    double energy;
}