LuminariousDuo/Code

From Robowiki
Jump to navigation Jump to search
LuminariousDuo Sub-pages:
LuminariousDuoVersion History - Code

This is the code for LuminariousDuo 1.0591. The teammate just extends Luminarious with no changes.


package voidious.team;

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

import java.util.HashMap;
import java.util.ArrayList;
import java.awt.geom.Point2D;
import java.awt.Color;
import java.io.Serializable;
import java.util.Random;

public class Luminarious extends TeamRobot {
    protected static final double RADAR_TRACK_AMOUNT = Math.PI/4;

    protected static Point2D.Double _myLocation;
    protected static HashMap _enemyLocationsByName = new HashMap();

    protected static Point2D.Double _teammateLocation;
    protected ArrayList _recentLocations;
    protected static Random _rand = new Random();
    
    protected String _lastEnemySeen;
    protected static long _scanReversalTick;
    protected static int _radarDirection = 1;
    protected static double _radarRangeTracker;
    protected static double _lastRadarRangeTracker;
    protected static java.awt.geom.Rectangle2D.Double _fieldRect;
    protected int _teammatesAlive = 1;

    /* For now, we are assuming our enemies will use the same or similar
     * movement, which is probably pretty likely.
     */

    protected static final double WAVE_BULLET_POWER = 1.9;
    protected static final double WAVE_BULLET_VELOCITY = 14.3;
    protected static final double WAVE_MAX_ESCAPE_ANGLE = 0.62;
    protected static double _bulletPower;
    static final int GF_ZERO = 18;
    static final int GF_ONE = 36;
    static long[][][][][] _gunStats = new long[2][3][4][5][GF_ONE+1];

    protected double _targetDistance = Double.POSITIVE_INFINITY;
    protected static String _targetName = "";
    protected static double _randomDirChangeAmount;
    protected long _timeSinceDirChangeCounter;
    protected static double _lastHeading;
    protected static double _enemyAbsoluteBearing;
    protected static int _lastGunOrientation;
    protected static double _lastDistance;
    protected static double _lastBulletPower = 1;
    protected static int _resumeRadarDirection = 1;
    protected static boolean _tempRadarLock = false;
    
    public void run() {
    	_fieldRect = new java.awt.geom.Rectangle2D.Double(30, 30, 
            getBattleFieldWidth() - 60, getBattleFieldHeight() - 60);
        _recentLocations = new ArrayList();
        setAdjustGunForRobotTurn(true);
        setAdjustRadarForGunTurn(true);
        setColors(Color.black, Color.black, new Color(80, 150, 80));
        
        do {
            try {
                broadcastMessage(new LuminariLocation(getX(), getY()));;
            } catch (Exception ex) { }

            setTurnRadarRightRadians(RADAR_TRACK_AMOUNT * _radarDirection);
            _radarRangeTracker += RADAR_TRACK_AMOUNT;

            if (Math.abs(getGunTurnRemaining()) < 4) {
            	if (setFireBullet(_bulletPower) != null) {
            		_radarDirection = _resumeRadarDirection;
            		_tempRadarLock = false;
            	}
            }

            move();
            execute();
        } while (true);
    }
    
    public void onScannedRobot(ScannedRobotEvent e) {
        String eName = e.getName();
        double eDistance = _lastDistance = e.getDistance();
        double eEnergy = e.getEnergy();
        double eVelocity = e.getVelocity();
        
        if (isTeammate(eName)) { return; }


        ////////////////////////////////////////////////
        // General data stuff
        ////////////////////////////////////////////////
        
        _enemyAbsoluteBearing = e.getBearingRadians() + getHeadingRadians();
        double enemyLatVel = (e.getVelocity()) * 
        	Math.sin(e.getHeadingRadians() - _enemyAbsoluteBearing);
        if (!_enemyLocationsByName.containsKey(eName)) {
        	_enemyLocationsByName.put(eName, new EnemyData());
        }
        EnemyData eData = (EnemyData)_enemyLocationsByName.get(eName);
        eData.name = eName;
        eData.setLocation(project(_myLocation, _enemyAbsoluteBearing, eDistance));
        double absSinRelativeHeading =
            Math.abs(Math.sin(e.getHeadingRadians() - _enemyAbsoluteBearing));
        eData.energy = eEnergy;
        eData.heading = e.getHeadingRadians();
        eData.velocity = eVelocity;


        ////////////////////////////////////////////////
        // Radar
        ////////////////////////////////////////////////

        if (_lastEnemySeen == null) {
            _lastEnemySeen = eName;
        }
        
        if (getOthers() - _teammatesAlive == 1) {	
        	_resumeRadarDirection = (_radarDirection *= -1);
        } else if (
        	getGunHeat() <= (Math.min(Math.PI, _lastRadarRangeTracker) / 5) / 
           	RADAR_TRACK_AMOUNT && _targetName.equals(eName)) {
        	
        	_radarDirection *= -1;
        	if (!_tempRadarLock) {
        		_resumeRadarDirection = _radarDirection;
        		if (_radarRangeTracker > Math.PI) {
        			_resumeRadarDirection *= -1;
        		}
        	}
        	_tempRadarLock = true;
            _radarRangeTracker = 0;
        } else if (!_lastEnemySeen.equals(eName)) {
        	if (_radarRangeTracker <= Math.PI && 
        		_scanReversalTick != e.getTime()) {
        		
        		_scanReversalTick = e.getTime();
        		_radarDirection *= -1;
                _lastRadarRangeTracker = _radarRangeTracker;
        	}
            _radarRangeTracker = 0;
        }
        _lastEnemySeen = eName;
        
        
        ////////////////////////////////////////////////
        // Gun wave creation
        ////////////////////////////////////////////////

        MicroWave w;
        addCustomEvent(w = new MicroWave());
        w.targetName = eName;
        w.sourceLocation = _myLocation;
        w.directAngle = _enemyAbsoluteBearing;
        w.orientation = _lastGunOrientation = sign((eVelocity)
            * Math.sin(e.getHeadingRadians() - _enemyAbsoluteBearing));

        w.waveGuessFactors =
            _gunStats[gunWallDistance(0.38591195687) ? 1 : 0]
                     [(int)Math.min(2, 3 * Math.asin(absSinRelativeHeading) / (Math.PI / 2))]
                     [(int)(eDistance / 275)][(int)((Math.abs(enemyLatVel)+1) / 2)];

        
        ////////////////////////////////////////////////
        // Target selection and actual firing.
        ////////////////////////////////////////////////

        if (eDistance < _targetDistance || _targetName.equals(eName)) {
            _targetName = eName;
            _targetDistance = eDistance;
        }

        if (!_targetName.equals(eName)) {
            return; 
        } 
        
        int bestGF = GF_ZERO;
        double bestGFRank = 0;
        for (int x = 0; x < GF_ONE; x++) {
        	if (w.waveGuessFactors[x] > bestGFRank) {
        		bestGFRank = w.waveGuessFactors[x];
        		bestGF = x;
        	}
        }
        
         _bulletPower = 1.9;

        if (eDistance > 750) {
        	_bulletPower = 1.59;
        }

        if (eDistance < 300) {
            _bulletPower = 2.39;
        }
        
        if (eDistance < 150) {
            _bulletPower = 3;
        }

        if ((getEnergy() < eEnergy && _teammatesAlive == 0) ||
        	(getEnergy() < 25)) {
        	_bulletPower = Math.min(_bulletPower,
                1.9 - Math.max(0, (35 - getEnergy()) / 18));
        }

        setTurnGunRightRadians(Utils.normalRelativeAngle(
        		_enemyAbsoluteBearing - getGunHeadingRadians() +
        		(e.getEnergy() > 0 ?
        			(w.orientation 
        			* (maxEscapeAngle(bulletVelocity(_bulletPower)) / GF_ZERO)
        			* (bestGF - GF_ZERO)) : 0)));        
    }

    public void onMessageReceived(MessageEvent e) {
    	LuminariLocation loc = (LuminariLocation)e.getMessage();
        _teammateLocation = new Point2D.Double(loc.x, loc.y);
    }
    
    public void onRobotDeath(RobotDeathEvent e) {
    	String eName = e.getName();
    	
        if (isTeammate(eName)) {
            _teammatesAlive--;
        }
        
        if (_targetName.equals(eName)) {
            _targetName = "";
            _targetDistance = Double.POSITIVE_INFINITY;
        }
        
        _enemyLocationsByName.remove(eName);
    }
    
    public void onHitByBullet(HitByBulletEvent e) {
        _lastBulletPower = e.getPower();
    }
    
    public void onHitWall(HitWallEvent e) {
    	_timeSinceDirChangeCounter = 0;
    }
    
    protected void move() {
        _myLocation = new Point2D.Double(getX(), getY());       

        if (Math.random() > 0.9) {
        	_recentLocations.add(0, _myLocation);
        }
        
        double bestRisk = Double.POSITIVE_INFINITY;
        double bestAngle = 0;
        double currentHeading =
        		getHeadingRadians() + (getVelocity() < 0?Math.PI:0);
        
        Object[] enemies = 
            (_enemyLocationsByName.values().toArray());
        
        if (Math.abs(Utils.normalRelativeAngle(currentHeading - _lastHeading)) 
           	< Math.PI / 3) {
           	_timeSinceDirChangeCounter++;
        } else {
        	_timeSinceDirChangeCounter = 0;
        	_randomDirChangeAmount =
        		Math.max(4, 2 * Math.random() * Math.random()
                    * (_targetDistance) / bulletVelocity(_lastBulletPower));
        }
        
        for (double x = 0; x < 2; x += .04) {
            double testAngle = x * Math.PI;
            Point2D.Double testPoint = project(_myLocation, testAngle, 
                50 + Math.random() * 200);
            
            if (_fieldRect.contains(testPoint)) {
                double testRisk = 0;
                
            	double[] enemyBearings = new double[2];
                for (int y = 0; y < enemies.length; y++) {
                    EnemyData eData = ((EnemyData)enemies[y]);
                    double bearingToTeammate = 
                    	absoluteBearing(eData, _teammateLocation);
                    double bearingToMe = enemyBearings[y] =
                    	absoluteBearing(eData, testPoint);
                    double distSquaredToEnemy = 
                    	testPoint.distanceSq(eData);
//                    double distSquaredTeammateToEnemy = 
//                    	_teammateLocation.distanceSq(eData);
                    
                    testRisk += 
                        ((limit(0.1, (eData.energy / getEnergy()), 2)
                        	/ distSquaredToEnemy)
                        	+ ((2 * _teammatesAlive)
                                / testPoint.distanceSq(_teammateLocation))
                        )
//                        * (_teammatesAlive == 0?1:(
//                        	(Math.max(1, distSquaredToEnemy / distSquaredTeammateToEnemy))))
                        * (1 + square(Math.cos(absoluteBearing(
                            _myLocation, eData) - testAngle)))
//                        * (2 + square(Math.sin(absoluteBearing(
//                        		testPoint, eData) - eData.heading)))
                        * (_teammatesAlive==0?1:(1 +
                            square(Math.cos(bearingToTeammate - bearingToMe))))
                        ;
                }
                
                try {
                	if (getOthers() - _teammatesAlive == 2) {
                		testRisk *= (1 + square(Math.sin(enemyBearings[0]
                            - enemyBearings[1])));
                	}
                } catch (Exception e) { }
                
            	if (Math.abs(Utils.normalRelativeAngle(currentHeading 
                    	- testAngle)) < (Math.PI / 3)) {
            		if (_timeSinceDirChangeCounter > _randomDirChangeAmount) {
                		testRisk *= 10;
                	} else {
                		testRisk /= 2;
                	}
                }
            	
                try {
                    for (int z = 0; z < Math.min(6, _recentLocations.size()); z++) {
                    	testRisk *= (1 + (((1000) - (100 * z))
                            / (testPoint.distanceSq(
                                (Point2D.Double)_recentLocations.get(z)))));
                    }
                } catch (Exception e) { }
                                
                if (testRisk < bestRisk) {
                    bestRisk = testRisk;
                    bestAngle = x * Math.PI;
                }        
            }           
        }

        _lastHeading = currentHeading;

        moveWithBackAsFront(bestAngle);
    }
       
    // CREDIT: code by Iiley,
    // http://robowiki.net?BackAsFront
    void moveWithBackAsFront(double bearing) {
        double angle = Utils.normalRelativeAngle(bearing - getHeadingRadians());
        double turnAngle;
        setTurnRightRadians(turnAngle = Math.atan(Math.tan(angle)));
        setAhead((angle == turnAngle) ? 100 : -100);
    }
     
    protected 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);
    }
        
    private static double absoluteBearing(Point2D.Double source, Point2D.Double target) {
        return Math.atan2(target.x - source.x, target.y - source.y);
    }

    static int sign(double d) {
        if (d >= 0) return 1;
        return-1;
    }

    static double square(double d) {
        return d * d;
    }

    private static double maxEscapeAngle(double velocity) {
        return Math.asin(8.0/velocity);
    }

    protected static double bulletVelocity(double power) {
        return (20.0 - (3.0*power));
    }
    
    protected static double limit(double min, double value, double max) {
        return Math.max(min, Math.min(value, max));
    }

    protected static boolean gunWallDistance(double wallDistance) {
    	return _fieldRect.contains(project(_myLocation, _enemyAbsoluteBearing
            + (_lastGunOrientation*wallDistance), _lastDistance));
    }

    protected static double pythago(double x, double y) {
    	return Math.sqrt(square(x) + square(y));
    }
   
    class MicroWave extends Condition {
        String targetName;
        Point2D.Double sourceLocation;
        long[] waveGuessFactors;
        double bulletVelocity, directAngle, distance;
        int orientation;

        public boolean test(){
        	try {
                Point2D.Double enemyLocation = 
                    ((EnemyData)_enemyLocationsByName.get(targetName));
                if ((enemyLocation).distance(sourceLocation)
                    <= (distance+=WAVE_BULLET_VELOCITY) + (WAVE_BULLET_VELOCITY/2)) {
                	try {
                		double guessFactor = (Utils.normalRelativeAngle(
                				absoluteBearing(sourceLocation, enemyLocation)
                				- directAngle) * orientation) / WAVE_MAX_ESCAPE_ANGLE;
                		int guessFactorIndex = (int)((guessFactor * GF_ZERO) + GF_ZERO);
                		waveGuessFactors[guessFactorIndex]++;
                	} catch (Exception e) { }
                    removeCustomEvent(this);
                }
        	} catch (Exception e) { }
            return false;
        }
    }
}

class EnemyData extends Point2D.Double {
    String name;
    double energy, velocity, heading;
}

class LuminariLocation implements Serializable {
    public double x;
    public double y;
    
    public LuminariLocation(double newX, double newY) {
        x = newX;
        y = newY;
    }
}