[Home]VertiLeach/Code

Robo Home | VertiLeach | Changes | Preferences | AllPages

Showing revision 2
Source code for VertiLeach V 0.3, released under the RoboWiki Public Code Licence (RWPCL).

This source code is also included in the bot jar file: http://www.robocoderepository.com/Controller.jsp?submitAction=downloadClass&id=1744

package pez.mini;
import robocode.*;
import robocode.util.Utils;
import java.awt.geom.*;
import java.awt.Color;
import java.util.*;
import java.util.zip.*;
import java.io.*;

// VertiLeach, by PEZ. Stays close to you and follows your vertical movements
//
// This code is released under the RoboWiki Public Code Licence (RWPCL), datailed on:
// http://robowiki.dyndns.org/?RWPCL
//
// Code home page: http://robowiki.dyndns.org/?VertiLeach/Code
//
// $Id: VertiLeach.java,v 1.5 2003/10/26 14:32:37 peter Exp $

public class VertiLeach extends AdvancedRobot {
    private static final double MAX_VELOCITY = 8;
    private static final double DEFAULT_DISTANCE = 300;
    private static final double DEFAULT_BULLET_POWER = 3.0;
    private static final double WALL_MARGIN = 50;
    private static final int MAX_FACTOR_VISITS = 255;
    private static final int DIRECTION_SEGMENTS = 3;
    private static final int VERTICAL_SEGMENTS = 11;
    private static final int AIM_FACTORS = 17;
    private static Point2D robotLocation = new Point2D.Double();
    private static Point2D oldRobotLocation = new Point2D.Double();
    private static Point2D oldEnemyLocation = new Point2D.Double();
    private static Point2D enemyLocation = new Point2D.Double();
    private static Rectangle2D fieldRectangle;
    private static double robotEnergy;
    private static String enemyName = "";
    private static double enemyDistance;
    private static double enemyEnergy;
    private static double enemyAbsoluteBearing;
    private static double maxEnemyBearing;
    private static double deltaBearing;
    private static double yOffset;
    private static int[][][] aimFactors;
    private int[] currentAimFactors;
    private Point2D robotDestination = null;
    private boolean shouldRam;

    public void run() {
        fieldRectangle = new Rectangle2D.Double(0, 0 , getBattleFieldWidth(), getBattleFieldHeight());
        setColors(Color.red.darker().darker(), Color.green.darker().darker(), Color.gray.darker().darker());
        setAdjustGunForRobotTurn(true);
        setAdjustRadarForGunTurn(true);

        do {
            turnRadarRightRadians(Double.POSITIVE_INFINITY); 
        } while (true);
    }

    public void onScannedRobot(ScannedRobotEvent e) {
        if (enemyName == "") {
            enemyName = e.getName();
            restoreFactors();
        }
        oldRobotLocation.setLocation(robotLocation);
        robotLocation.setLocation(getX(), getY());
        enemyAbsoluteBearing = getHeadingRadians() + e.getBearingRadians();
        enemyDistance = e.getDistance();
        oldEnemyLocation.setLocation(enemyLocation);
        toLocation(enemyAbsoluteBearing, enemyDistance, robotLocation, enemyLocation);

	double delta = enemyEnergy - e.getEnergy();
	if (delta >= 0.1 && delta <= 3.0) {
	    yOffset = 150 * Math.random() - 75;
	}
        enemyEnergy = e.getEnergy();
        robotEnergy = getEnergy();
        shouldRam = enemyEnergy == 0 || (enemyEnergy < 0.3 && robotEnergy > enemyEnergy * 11);

        move();

        deltaBearing = Utils.normalRelativeAngle(absoluteBearing(oldRobotLocation, enemyLocation) -
            absoluteBearing(oldRobotLocation, oldEnemyLocation));
        double bulletPower = Math.min(robotEnergy / 5, Math.min(enemyEnergy / 4, DEFAULT_BULLET_POWER));
        maxEnemyBearing = Math.abs(Math.asin(MAX_VELOCITY / (bulletVelocity(bulletPower))));

        currentAimFactors = aimFactors[aimDirectionSegment()]
            [Math.min((int)(enemyLocation.getY() / (getBattleFieldHeight() / VERTICAL_SEGMENTS)), VERTICAL_SEGMENTS - 1)];

        setTurnGunRightRadians(Utils.normalRelativeAngle(
            enemyAbsoluteBearing + maxEnemyBearing * sign(deltaBearing) * mostVisitedFactor() - getGunHeadingRadians()));

        if (!shouldRam && (robotEnergy > 1.5 || enemyDistance < 200)) {
            if (setFireBullet(bulletPower) != null && bulletPower > 0.9) {
                addCustomEvent(new Wave(bulletVelocity(bulletPower)));
            }
        }

        setTurnRadarRightRadians(Utils.normalRelativeAngle(enemyAbsoluteBearing - getRadarHeadingRadians()) * 2);
    }

    public void onWin(WinEvent e) {
        saveFactors();
    }

    public void onDeath(DeathEvent e) {
        saveFactors();
    }

    private void move() {
        double X = enemyLocation.getX() + sign(getX() - enemyLocation.getX()) * (shouldRam ? 0 : DEFAULT_DISTANCE);;
        robotDestination = new Point2D.Double(X, enemyLocation.getY() + yOffset);
        translateInsideField(robotDestination, WALL_MARGIN);
        goTo(robotDestination);
    }

    void goTo(Point2D destination) {
        double angle = Utils.normalRelativeAngle(absoluteBearing(robotLocation, destination) - getHeadingRadians());
        int direction = 1;
        if (Math.abs(angle) > Math.PI / 2) {
            angle += Math.acos(direction = -1);
        }
        setTurnRightRadians(Utils.normalRelativeAngle(angle));
        setAhead(robotLocation.distance(destination) * direction);
    }

    double mostVisitedFactor() {
        int mostVisited = (AIM_FACTORS - 1) / 2;
        for (int i = 0; i < AIM_FACTORS; i++) {
            if (currentAimFactors[i] > currentAimFactors[mostVisited]) {
                mostVisited = i;
            }
        }
        return (mostVisited - (AIM_FACTORS - 1D) / 2D) / ((AIM_FACTORS - 1D) / 2D);
    }

    void registerFactorVisit(int[] factors, int index) {
        if (factors[index] < MAX_FACTOR_VISITS) {
            factors[index]++;
        }
        else {
            decrementOtherFactors(factors, index);
        }
    }

    void decrementOtherFactors(int[] factors, int index) {
        for (int i = 0, numFactors = factors.length; i < numFactors; i++) {
            if (i != index && factors[i] > 0) {
                factors[i]--;
            }
        }
    }

    private int aimDirectionSegment() {
        double delta = enemyLocation.getY() - oldEnemyLocation.getY();
        if (delta < 0) {
            return 0;
        }
        else if (delta > 0) {
            return 2;
        }
        return 1;
    }

    private void translateInsideField(Point2D point, double margin) {
        point.setLocation(Math.max(margin, Math.min(fieldRectangle.getWidth() - margin, point.getX())),
                          Math.max(margin, Math.min(fieldRectangle.getHeight() - margin, point.getY())));
    }

    private double bulletVelocity(double power) {
        return 20 - 3 * power;
    }

    private int sign(double v) {
        return v > 0 ? 1 : -1;
    }

    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());
    }

    void restoreFactors() {
        try {
            ZipInputStream zipin = new ZipInputStream(new
                FileInputStream(getDataFile(enemyName + ".zip")));
            zipin.getNextEntry();
            ObjectInputStream in = new ObjectInputStream(zipin);
            aimFactors = (int[][][])in.readObject();
            in.close();
        }
        catch (Exception e) {
            aimFactors = new int[DIRECTION_SEGMENTS][VERTICAL_SEGMENTS][AIM_FACTORS];
        }
    }

    void saveFactors() {
        try {
            ZipOutputStream zipout = new ZipOutputStream(new RobocodeFileOutputStream(getDataFile(enemyName + ".zip")));
            zipout.putNextEntry(new ZipEntry("aimFactors"));
            ObjectOutputStream out = new ObjectOutputStream(zipout);
            out.writeObject(aimFactors);
            out.flush();
            zipout.closeEntry();
            out.close();
        }
        catch (IOException e) {
        }
    }

    class Wave extends Condition {
        private long wTime;
        private double bulletVelocity;
        private double bearingDelta;
        private Point2D oldRLocation = new Point2D.Double();
        private Point2D oldELocation = new Point2D.Double();
        private double maxBearing;
        int[] wAimFactors;

        public Wave(double bulletVelocity) {
            this.wTime = getTime();
            this.bulletVelocity = bulletVelocity;
            this.bearingDelta = deltaBearing;
            this.oldRLocation.setLocation(robotLocation);
            this.oldELocation.setLocation(enemyLocation);
            this.maxBearing = maxEnemyBearing;
            this.wAimFactors = currentAimFactors;
        }

        public boolean test() {
            if (bulletVelocity * (getTime() - wTime) > oldRLocation.distance(enemyLocation) - 10) {
                double bearingDiff = Utils.normalRelativeAngle(absoluteBearing(oldRLocation, enemyLocation) -
                    absoluteBearing(oldRLocation, oldELocation));
                registerFactorVisit(wAimFactors, (int)Math.round(Math.max(0D, Math.min(AIM_FACTORS - 1D,
                    ((sign(bearingDelta) * bearingDiff) / maxBearing) * (AIM_FACTORS - 1D) / 2D + (AIM_FACTORS - 1D) / 2D))));
                removeCustomEvent(this);
            }
            return false;
        }
    }
}

Comments, suggestions and questions are welcome


Robo Home | VertiLeach | Changes | Preferences | AllPages
Edit revision 2 of this page | View other revisions | View current revision
Edited October 30, 2003 0:05 EST by PEZ (diff)
Search: