package ry; //imports import robocode.*; import robocode.util.Utils; import java.awt.geom.*; // for Point2D's import java.awt.Color; /*Released under the RoboWiki Public Code License Author: Robert Ying Do NOT COPY WITHOUT GIVING CREDIT! Note: Certain lines are commented out in order to save codesize, and can be put back in to improve the algorithms. */ public class LightningBug extends AdvancedRobot { // Variables private static final double BULLET_POWER = 1.9; private static double lateralDirection; private static double lastEnemyVelocity; static double prevEnergy = 100.0; static double enemyEnergy; // static double turnFactor = 0.2; // static int favDistance = 200; static int moveFactor = 20; static int vel; static int lastVel; static int[][] hitData = new int[16][4]; public void run() { // Colors // setColors(Color.BLACK, Color.BLUE, Color.GRAY); // Settings lateralDirection = 1; lastEnemyVelocity = 0; setAdjustRadarForGunTurn(true); setAdjustGunForRobotTurn(true); // Infinity Lock Radar turnRadarRightRadians(Double.POSITIVE_INFINITY); } public void onScannedRobot(ScannedRobotEvent e) { // GuessFactor Targeting. RWPCL! double enemyAbsoluteBearing = getHeadingRadians() + e.getBearingRadians(); double enemyDistance = e.getDistance(); double enemyVelocity = e.getVelocity(); if (enemyVelocity != 0) { lateralDirection = RYUtils.sign(enemyVelocity * Math.sin(e.getHeadingRadians() - enemyAbsoluteBearing)); } Wave wave = new Wave(this); wave.gunLocation = new Point2D.Double(getX(), getY()); Wave.targetLocation = RYUtils .project(wave.gunLocation, enemyAbsoluteBearing, enemyDistance); wave.lateralDirection = lateralDirection; wave.bulletPower = BULLET_POWER; wave.setSegmentations(enemyDistance, enemyVelocity, lastEnemyVelocity); lastEnemyVelocity = enemyVelocity; wave.bearing = enemyAbsoluteBearing; setTurnGunRightRadians(Utils.normalRelativeAngle(enemyAbsoluteBearing - getGunHeadingRadians() + wave.mostVisitedBearingOffset())); setFire(wave.bulletPower); // VelocitySurfing, Version 2 if (getEnergy() >= BULLET_POWER) { addCustomEvent(wave); } if (enemyEnergy > (enemyEnergy = e.getEnergy())) { lastVel = vel + (4 * (int) (e.getDistance() / 267)); int testVel = 3; do { if (hitData[lastVel][testVel] < hitData[lastVel][vel]) { vel = testVel; } } while (testVel-- > 0); if (vel < 2) { onHitWall(null); } } setMaxVelocity(8 * (vel - 1.5)); setAhead(moveFactor); /* * double smoothedDirection = getHeadingRadians() + * e.getBearingRadians() - 1.48 * moveFactor; Rectangle2D fieldRect = * new Rectangle2D.Double(18, 18, 800 - 36, 600 - 36); while * (!fieldRect.contains(getX() + Math.sin(smoothedDirection) * 120, * getY() + Math.cos(smoothedDirection) * 120)) { smoothedDirection += * moveFactor * turnFactor; } double turn = * Utils.normalRelativeAngle(smoothedDirection - getHeadingRadians()); * if (Math.abs(turn) > Math.PI / 2) { turn = * Utils.normalRelativeAngle(turn + Math.PI); setBack(20); } else * setAhead(20); setTurnRightRadians(turn); */ // For example, this line replaces // setTurnRightRadians(e.getBearingRadians() + Math.PI / 2 - Math.PI / 2 // * Math.random() // * (e.getDistance() > favDistance ? 1 : -1)); // this line in order to allow for randomization in the movement // routine. Of course, you will need to uncomment favDistance above. setTurnRightRadians(e.getBearingRadians() + Math.PI / 2); // Infinity Lock Radar setTurnRadarLeftRadians(getRadarTurnRemainingRadians()); } // Some Events, for movement. I need to find space for WallSmoothing public void onBulletHit(BulletHitEvent e) { enemyEnergy -= 11.4; } public void onHitByBullet(HitByBulletEvent e) { hitData[lastVel][vel]++; } public void onHitWall(HitWallEvent e) { moveFactor *= -1; } } class Wave extends Condition { static Point2D targetLocation; double bulletPower; Point2D gunLocation; double bearing; double lateralDirection; private static final double MAX_DISTANCE = 1000; private static final int dist_index = 5; private static final int vel_index = 5; private static final int BINS = 47; private static final int MIDDLE_BIN = (BINS - 1) / 2; private static final double MAX_ESCAPE_ANGLE = 0.7; private static final double BIN_WIDTH = MAX_ESCAPE_ANGLE / (double) MIDDLE_BIN; private static int[][][][] statBuffers = new int[dist_index][vel_index][vel_index][BINS]; private int[] buffer; private AdvancedRobot robot; private double distanceTraveled; Wave(AdvancedRobot _robot) { this.robot = _robot; } public boolean test() { advance(); if (hasArrived()) { buffer[currentBin()]++; robot.removeCustomEvent(this); } return false; } double mostVisitedBearingOffset() { return (lateralDirection * BIN_WIDTH) * (mostVisitedBin() - MIDDLE_BIN); } void setSegmentations(double distance, double velocity, double lastVelocity) { int distanceIndex = (int) (distance / (MAX_DISTANCE / dist_index)); int velocityIndex = (int) Math.abs(velocity / 2); int lastVelocityIndex = (int) Math.abs(lastVelocity / 2); buffer = statBuffers[distanceIndex][velocityIndex][lastVelocityIndex]; } private void advance() { distanceTraveled += RYUtils.bulletVelocity(bulletPower); } private boolean hasArrived() { return distanceTraveled > gunLocation.distance(targetLocation) - 18; } private int currentBin() { int bin = (int) Math.round(((Utils.normalRelativeAngle(RYUtils .absoluteBearing(gunLocation, targetLocation) - bearing)) / (lateralDirection * BIN_WIDTH)) + MIDDLE_BIN); return RYUtils.minMax(bin, 0, BINS - 1); } private int mostVisitedBin() { int mostVisited = MIDDLE_BIN; for (int i = 0; i < BINS; i++) { if (buffer[i] > buffer[mostVisited]) { mostVisited = i; } } return mostVisited; } } class RYUtils { 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()); } static int sign(double v) { return v < 0 ? -1 : 1; } static int minMax(int v, int min, int max) { return Math.max(min, Math.min(max, v)); } }