Smoke/Code

From Robowiki
Jump to navigation Jump to search
Smoke Sub-pages:
SmokeVersion History - Code

package cx.micro;
import java.awt.geom.Point2D;
import java.util.ArrayList;

import robocode.AdvancedRobot;
import robocode.Condition;
import robocode.DeathEvent;
import robocode.ScannedRobotEvent;
import robocode.util.Utils;
/**
 *-----------------------------------------------------------------
 * @author:iiley (iiley@hotmail.com)
 * http://www.robochina.org
 * Smoke:use MicroWave to do pattern analyzer and random movement
 *--------------------version 0.5 2003.1.5--------------
 * 0.5:Can only fire 3 power because MicroWave,so may west much power.(codesize 737)
 *--------------------version 0.55 2003.1.5--------------               
 * 0.55:improved movement a little.(codesize 749)
 *--------------------version 0.60 2003.1.8--------------
 * 0.60:changed a movement.it does better.(codesize 748)
 *--------------------version 0.70 2003.1.25-------------
 * 0.70:changed a movement similar to the new verion of Cigaret. (codesize 742)
 *--------------------version 0.80 2003.2.3-------------
 * 0.80:Squeezed much(MicroWave squeezed too) so added some in aim. (codesize 749)
 *--------------------version 0.82 2003.2.5-------------
 * 0.82:Squeezed again,added a judge to aim prediction points only in battle feild.
 *      and can set one color now(but have not set).(codesize 740)
  *--------------------version 0.91 2003.7.12-------------
 * 0.91:Squeezed again,tweaked movement as experience from Spark.(codesize 742)
  *--------------------version 0.95 2003.9.12-------------
 * 0.95:Squeezed again,can fire different power bullet and can fight in different battle fileds now.(codesize 748)
  *--------------------version 0.96 2004.10.24-------------
 * 0.96:Squeezed again,then add a trick to HOT bot, tweaked a little.(codesize 748)
 *-------------------------------------------------------
 * future:Squeeze so that i can do more and get my whole colors back.
 */
public class Smoke extends AdvancedRobot {
	
	private static final double BATTLE_WIDTH = 800;
	private static final double BATTLE_HEIGHT = 600;

	/**
	 * my usual fire power
	 */
	private static final double POWER = 3d;
	private static final double BULLET_VELOCITY = 20d - 3d * POWER;

	/**
	 * ESCPAE_ANGLE should be Math.asin(8/(enemy_bullet_velocity))*2; if enemy
	 * fire 3 power bullet, it should be 1.6286798842530508 but here i use 1.5
	 */
	private static final double ESCPAE_ANGLE = 1.5;

	private static ArrayList waves = new ArrayList();
	
	private static double enemyEnergy;

	/**
	 * a trick to HOT, first it be 0, see the movement, it just move + dirction
	 * It is not very useful i am thinking to remove it next version
	 */
	private static double HOT_Trick;

	/**
	 * enemy's current position
	 */
	private static Point2D.Double enemyPosition;

	public void run() {

		setAdjustGunForRobotTurn(true);
		setAdjustRadarForGunTurn(true);

		do {
			turnRadarRightRadians(1);
		} while (true);
	}

	/**
	 * when i am dead, i think enemy is not a HOT bot, so i will only move one
	 * direction
	 */
	public void onDeath(DeathEvent event) {
		HOT_Trick = ESCPAE_ANGLE / 2;
	}

	// -------------------- function for event handle ---------------
	public void onScannedRobot(ScannedRobotEvent e) {
		double absBearing;
		double distanceToEnemy;
		double moveDistance;
		double moveAngle;
		Point2D.Double myPosition;

		enemyPosition = nextPoint(myPosition = new Point2D.Double(getX(),
				getY()), absBearing = e.getBearingRadians()
				+ getHeadingRadians(), moveDistance = distanceToEnemy = e
				.getDistance());
		// Radar turn grabed from David Alves.
		setTurnRadarRightRadians(Math
				.sin(absBearing - getRadarHeadingRadians()));

		//fire
		double power = Math.min(POWER, enemyEnergy / 5d);
		if (getEnergy() > power)
			setFire(power);

		//--------------movement---------------------

		//if enemy fired, and my last move will finish, start a new move
		if (enemyEnergy != (enemyEnergy = e.getEnergy())
				&& Math.abs(getDistanceRemaining()) < 53d) {
			Point2D.Double destination;

			//random find a destination, random for the hit angle
			while (distanceToWall(destination = nextPoint(enemyPosition,
					absBearing
							+ (moveAngle = Math.random() * ESCPAE_ANGLE
									- HOT_Trick), -(moveDistance -= 10d)
							/ Math.cos(moveAngle))) < 24d);
			//thanks to David Alves and Dummy for this small code to find which
			// direction is shortest to our next destination
			//Thanx DrLoco of this usage
			//set move to the destination
			setAhead(((moveAngle = Utils.normalRelativeAngle(getAngle(
					destination, myPosition)
					- getHeadingRadians())) == (moveDistance = Math.atan(Math
					.tan(moveAngle))) ? 1 : -1)
					* myPosition.distance(destination)); //move towards point
			setTurnRightRadians(moveDistance);
		}

		//-----------------pattern analyser--------------------
		int size;
		size = waves.size();

		MicroWave wave;
		waves.add(wave = new MicroWave());
		wave.absBearing = moveDistance = absBearing;
		
		//patterns into compareValue, compareValue.x be the distance,
		// compareValue.y be the lateralVelocity
		wave.compareValue = new Point2D.Double(distanceToEnemy / 64d, e
				.getVelocity()
				* Math.sin(e.getHeadingRadians() - absBearing));
		wave.startPosition = myPosition;

		addCustomEvent(wave);

		if (getGunHeat() < 0.4d) {
			//pattern analyser, find the most matching pattern
			//seach rang is from 4500 before to current
			for (int i = Math.max(71, size - 4500); i < size; i++) {
				//is a hitted wave
				if ((wave = (MicroWave) waves.get(i)).startPosition.x < 10) {
					int j = 0;
					double div = 0;
					double comVal = 0;
					//compare 10 waves step 7.
					do {
						comVal += ((MicroWave) waves.get(size - j)).compareValue
								.distanceSq(((MicroWave) waves.get(i - j)).compareValue)
								/ (div = div * 2 + 1);
					} while ((j += 7) < 71);

					//find the most matched wave,distanceToEnemy is matchValue now
					if (comVal <= distanceToEnemy 
							&& distanceToWall(nextPoint(
									myPosition,
									moveAngle = absBearing
											+ Math.asin(Math.sin(wave.startPosition.x) / ((20d - power * 3d) / BULLET_VELOCITY)),
									wave.startPosition.y)) > 17) {
						//record the hit angle
						//moveDistance is shoot bearing now,distanceToEnemy is matchValue now
						moveDistance = moveAngle;
						distanceToEnemy = comVal;
					}
				}
			}
		}
		//turn gun
		setTurnGunLeftRadians(Utils.normalRelativeAngle(getGunHeadingRadians()
				- moveDistance));

		scan();
	}

	/**
	 * return the next point from originPoint's certain angle certan distance
	 */
	public static Point2D.Double nextPoint(Point2D.Double originPoint, double angle, double distance) {
		return new Point2D.Double(originPoint.x + Math.sin(angle) * distance,
				originPoint.y + Math.cos(angle) * distance);
	}

	/**
	 * return the angle from p1 to p2
	 */
	public static double getAngle(Point2D.Double p2, Point2D.Double p1) {
		return Math.atan2(p2.x - p1.x, p2.y - p1.y);
	}

	public static double distanceToWall(Point2D.Double p) {
		return Math.min(Math.min(p.x, BATTLE_WIDTH - p.x), Math.min(p.y, BATTLE_HEIGHT - p.y));
	}

	class MicroWave extends Condition {
		//-------comparable varialbles
		Point2D.Double compareValue;

		/**
		 * when wave started, this is the start position but after the wave hit
		 * enemy, this is the hit angle and hit distance
		 */
		Point2D.Double startPosition;

		double absBearing;

		double traveledDistance;

		public boolean test() {
			traveledDistance += BULLET_VELOCITY;

			//if the wave hit the enemy
			//when the wave hit enemy, record the angle and the distance into
			// startPosition
			if (traveledDistance > enemyPosition.distance(startPosition) - 18) {
				startPosition = new Point2D.Double(getAngle(enemyPosition, startPosition) - absBearing,
						traveledDistance);
				removeCustomEvent(this);
			}
			return false;
		}
	}

}