User:Chase-san/BasicTracker

From Robowiki
< User:Chase-san
Revision as of 03:31, 30 November 2011 by Chase-san (talk | contribs) (whoops)
Jump to navigation Jump to search

A basic tracker that accurately tracks enemy energy drop information. This also requires it to track a whole bunch of other stuff (at least for the wall collision). It is only for one on one at the moment. The melee version is obviously much more complex, and relies a great deal on the radar.

//'naive' is used to keep versions of my custom classes
//that do not extensively use internal code structures
package cs.naive;

import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

import robocode.BulletHitEvent;
import robocode.HitByBulletEvent;
import robocode.HitRobotEvent;
import robocode.RobotStatus;
import robocode.Rules;
import robocode.ScannedRobotEvent;
import robocode.StatusEvent;

import static java.lang.Math.*;

/**
 * Tracks some basic changes in an enemy.
 * Mainly everything in here is enough to precisely track enemy energy drop.
 * It is a handful, so I decided to separate it out.
 * 
 * @author Chase
 */
public class BasicTracker {
	//not always correct, use at your own risk
	private boolean enemyIsNormalRobot = false;
	public Point2D enemyPosition = new Point2D.Double();
	public double enemyEnergy = 100;
	public double enemyEnergyDelta = 0;
	public double enemyVelocity = 0;
	public double enemyVelocityDelta = 0;
	public double enemyHeading = 0;
	public double enemyHeadingDelta = 0;
	public final Rectangle2D battlefield;

	public BasicTracker(double fieldWidth, double fieldHeight) {
		battlefield = new Rectangle2D.Double(18,18,fieldWidth-36,fieldHeight-36);
	}

	public Point2D myPosition = new Point2D.Double();
	public double myHeading = 0;
	
	public void onStatus(StatusEvent e) {
		RobotStatus status = e.getStatus();
		myPosition = new Point2D.Double(status.getX(),status.getY());
		myHeading = status.getHeadingRadians();
	}

	public void onScannedRobot(ScannedRobotEvent e) {
		double angleToEnemy = e.getBearingRadians() + myHeading;
		
		double newEnemyEnergy = e.getEnergy();
		double newEnemyVelocity = e.getVelocity();
		double newEnemyHeading = e.getHeadingRadians();
		double newEnemyVelocityDelta = newEnemyVelocity - enemyVelocity;
		double newEnemyHeadingDelta = newEnemyHeading - enemyHeading;
		Point2D newEnemyPosition = project(myPosition, angleToEnemy, e.getDistance());
		
		/*
		 * Enemy wall collision correction.
		 * This is the part that requires so much more information to handle.
		 */
		if(abs(newEnemyVelocity) == 0.0 && !enemyIsNormalRobot) {
			double fullSpeed = limit(-Rules.MAX_VELOCITY,
					enemyVelocity + enemyVelocityDelta,
					Rules.MAX_VELOCITY);
			/*
			 * Can we determine if they decided to slow down
			 * the very exact instant before they hit the wall?
			 * No, but if they did hit the wall (as is likely here),
			 * then it is unlikely they suddenly changed their mind
			 * so shortly before collision.
			 */
			Point2D target = project(enemyPosition, enemyHeading, fullSpeed);

			if(!battlefield.contains(target)) {
				double wallDamage = Rules.getWallHitDamage(abs(fullSpeed));

				if(wallDamage == 0 || enemyEnergy == newEnemyEnergy) {
					if(wallDamage > 0.2)
						enemyIsNormalRobot = true;
				} else {
					/*
					 * Detected wall collision
					 */
					enemyEnergy -= wallDamage;
				}
			}
		}
		
		enemyEnergyDelta = enemyEnergy - newEnemyEnergy;
		
		/*
		 * Reset the energy to track
		 */
		enemyEnergy = newEnemyEnergy;
		enemyVelocity = newEnemyVelocity;
		enemyHeading = newEnemyHeading;
		enemyVelocityDelta = newEnemyVelocityDelta;
		enemyHeadingDelta = newEnemyHeadingDelta;
		enemyPosition = newEnemyPosition;
	}
	
	public void onBulletHit(BulletHitEvent e) {
		/* 
		 * Determine how much damage our bullet does to the enemy
		 * and adjust our stored copy to reflect the amount lost
		 */
		enemyEnergy -= Rules.getBulletDamage(e.getBullet().getPower());
	}
	
	public void onHitByBullet(HitByBulletEvent e) {
		/*
		 * Increase the enemy energy based on how powerful the bullet that
		 * hit us was this is so we can get reliable energy drop detection
		 */
		enemyEnergy += Rules.getBulletHitBonus(e.getPower());
	}
	
	private long lastRobotHitTime = 0;
	public void onHitRobot(HitRobotEvent e) {
		long time = e.getTime();
		/*
		 * Correct enemy energy based on robot collision
		 */
		if(time != lastRobotHitTime) {
			lastRobotHitTime = time;
			enemyEnergy -= 0.6;
		}
	}
	
	public static final double limit(double min, double value, double max) {
		if (value > max) return max;
		if (value < min) return min;
		return value;
	}
	
	public static final Point2D project(Point2D p, double angle, double distance) {
		return new Point2D.Double(p.getX() + sin(angle) * distance, p.getY() + cos(angle) * distance);
	}
}