package opulus;

import robocode.*;
import java.util.ArrayList;
import java.awt.Color;
import java.awt.geom.Point2D;

public class Opulus extends AdvancedRobot {
	
	static double x = 0;
	static double y = 0;
	
	static double radarturn = 1;
	
	static double heading;
	
	static int accountedfor;
	
	static String target;
	
	double closest = Double.POSITIVE_INFINITY;
	
	static ArrayList enemies = new ArrayList();
	
	static double bp;
	
	static double stime;
	
	static double timer;
	
	static double pX, pX1;
	static double pY, pY1;
	
	static double grav;

	public static double angle_180(double ang) {
		return Math.atan2(Math.sin(ang), Math.cos(ang));
	}

	public void addGravity(double force, double angle) {
		x += force * Math.sin(angle);
		y += force * Math.cos(angle);
	}

	public double wallGrav(double d) {
		return (1.0 / d) * 20.0 / Math.max((d - 40), 20);
	}

	public void run() {
		
		timer = 0;
		
		accountedfor = 1000;

		setBodyColor(Color.white);
		setGunColor(Color.black);
		setRadarColor(Color.red);
		setBulletColor(Color.yellow);
		setScanColor(Color.green);
		
		setAdjustGunForRobotTurn(true);
		setAdjustRadarForGunTurn(true);
		setAdjustRadarForRobotTurn(true);
		
		do {
			
			setTurnRadarRightRadians(radarturn);
			
			double robotturn = angle_180(heading - getHeadingRadians());

			int forward = 60;
			double t = Math.atan(Math.tan(robotturn));
			if (Math.abs(robotturn - t) > 1)
				forward = -60;
			setAhead(forward);

			setTurnRightRadians(t);
			if (Math.abs(getGunTurnRemaining()) < 10 && getOthers() > 0)
				setFire(bp);
			execute();
		} while (true);
	}

	public void onScannedRobot(ScannedRobotEvent e) {

		double myX = getX();
		double myY = getY();
		double time = getTime();
		
		String enemyName = e.getName();
		double enemyDist = e.getDistance();

		if (time > timer) {
			pX = pX1;
			pY = pY1;
			pX1 = myX;
			pY1 = myY;
			grav = 0;
		}
		
		if (time - timer > 12) {
			timer += 20 + (Math.random() * 48);
			grav = 1;
		}
		
		double absbearing = e.getBearingRadians() + getHeadingRadians();
		
		double angle = e.getHeadingRadians() - absbearing;
		
		if (!enemies.contains(enemyName)) {
			enemies.add(enemyName);
			accountedfor++;
			addGravity(-1 / enemyDist, absbearing);

			if (getOthers() < 2) {
				addGravity(.0025, absbearing);
			}

		}

		if ((accountedfor >= getOthers()) || (time > stime)) {
			stime = time + 9;

			angle = Math.atan2(myX - pX, myY - pY);
			addGravity(.3 * grav/ Math.max(Point2D.distance(myX, myY, pX, pY), 10), angle);

			addGravity((.004) * Math.sin(.09 * time),(Math.atan2(x, y) + .5 * Math.PI)); // try to move perpendicular
			
			x += wallGrav(myX) - wallGrav(getBattleFieldWidth() - myX);
			y += wallGrav(myY) - wallGrav(getBattleFieldHeight() - myY);

			heading = Math.atan2(x, y);

			accountedfor = 0;
			enemies.clear();
			x = 0;
			y = 0;
			radarturn = -radarturn;
		}

		if ((enemyName.equals(target)) || (enemyDist - closest < -100)) {
			target = enemyName;
			closest = enemyDist;
			bp = Math.min(Math.min(3, getEnergy() / 10), e.getEnergy() / 4);

			double gr = 1.3 * Math.random() - .3;
			double aim = Math.asin(gr * e.getVelocity() / (20 - 3 * bp)* Math.sin(e.getHeadingRadians() - absbearing));

			setTurnGunRightRadians(angle_180(aim + absbearing - getGunHeadingRadians()));

		}
	}

	public void onRobotDeath(RobotDeathEvent e) {
		if (e.getName().equals(target)) {
			closest = Double.POSITIVE_INFINITY;
		}
	}
}