EpeeistDC/Code

From Robowiki
Jump to navigation Jump to search
/*
EpeeistDC v3.0 by Sheldor.  04/08/2025  748 bytes
multimode movement and basic dynamic clustering targeting
v3.0 -- rename, targeting, energy management, movement, radar

Épée is one of the three forms of modern sport fencing,
along with foil and sabre.  https://en.wikipedia.org/wiki/Epee

Previously named FoilistMicro.

Credits:
	Targeting: jk.mini.CunobelinDC, Falcon, pez.micro.Aristocles, voidious.mini.Komarious, kc.micro.Thorn, jk.micro.Connavar, nz.jdc.HedgehogGF, pez.mini.Pugilist, sheldor.micro.Epeeist
	Movement : jk.micro.Cotillion, jk.micro.Toorkild, kc.micro.Thorn, nz.jdc.HedgehogGF, wiki.nano.RaikoNano
Also, a general thanks to all open source bot authors and contributors to the RoboWiki.

EpeeistDC is open source and released under the terms of the RoboWiki Public Code License (RWPCL) - Version 1.1.
see license here:  https://robowiki.net/wiki/RWPCL
*/

package sheldor.micro;

import robocode.*;
import robocode.util.Utils;
import java.awt.geom.*;
import java.util.ArrayList;
import java.util.*;

public class EpeeistDC extends AdvancedRobot
{
	//constants
	static final int    GUESS_FACTORS = 37;
	static final int    MIDDLE_FACTOR = (GUESS_FACTORS - 1) / 2;
	static final double MAXIMUM_ESCAPE_ANGLE = 8.0 / 11;
	static final double FACTOR_ANGLE = MAXIMUM_ESCAPE_ANGLE / MIDDLE_FACTOR;	
	
	//	static final	int RESULT = 0;
		static final	int SITUATION = 0;	
		static final	int A_BEARING = 1;
		static final	int E_DIRECTION = 2;
		static final	int B_OFFSET = 3;
		static final	int E_DISTANCE = 4;
		static final  int WEIGHT = 5;
		static final	int W_DIST_TRAVELED = 6;
		
	static double[][] waves = new double[100000][W_DIST_TRAVELED + 1];
	static int lastLogged;
	static int newest;
	
	public static final char FW1 = 6;
	public static final char FW2 = 12;
	public static final char FW3 = 18;
	public static final char RW1 = (char)-6;
	public static final char RW2 = (char)-12;
	
	public static final char VELOCITY_VALUE = 16;//192;//4096;
	public static final int  WALL_VALUE = 5;//32;
	
	//global variables
	static double direction = 1;
	static double enemyBulletSpeed;
	static double enemyDirection;
	static double enemyEnergy;
	static double    hits;
	static int    movementMode;
	static int ticksSinceHit;
	
	static int ticksSinceVelocityChange;
	static int previousEnemyVelocity;
	
	static double enemyVelocity;
//	static ArrayList<Wave> waves = new ArrayList();

	public void run(){
		newest = lastLogged;
		
		//set the radar and gun to turn independently
		setAdjustRadarForGunTurn(true);
		setAdjustGunForRobotTurn(true);
	}
	
	public void onStatus(StatusEvent e)
	{		
		//turn the radar every tick
		//Putting the code here instead of in a while(true) loop in the run() method saves one byte.
		//I believe Wompi discovered this.
    	setTurnRadarRightRadians(1);
	}
	
	public void onScannedRobot(ScannedRobotEvent e)
	{
		//local variables
		int    i;	
		double absoluteBearing;
		double enemyDistance;	
		double offset;
		double localEnemyDirection;	
		double theta;
		int    integer;
		
		double[] wave;
		
			//energy management based on distance, energy, and enemy energy
		//retreat very heavily when the enemy is ramming	
		if (setFireBullet(Math.min(enemyEnergy / 4, 
(offset = 
			(2 + (integer = ((i = 112) / (int)((wave = waves[++newest])[E_DISTANCE] = enemyDistance = e.getDistance())))))
			- BULLET_POWER_TABLE.charAt((int)getEnergy())))
 != null){
	/*	if (setFireBullet((offset = (2 + (integer = ((i = 112) / (int)((wave = waves[newest++])[E_DISTANCE] = enemyDistance = e.getDistance())) << 5)
				)) - (BULLET_POWER_TABLE
				.charAt((((int)getEnergy() >> 3) * 127) + (int)e.getEnergy()) / 100.01)
			) != null){*/
				wave[WEIGHT] = 12;
			}
				
		/*********************************************
		 *---------------MOVEMENT CODE---------------*
		 *********************************************/				
		
		//wall smoothing based on HedgehogGF's
		while(fieldContains(theta = (wave[A_BEARING] = absoluteBearing = 
			(e.getBearingRadians() + getHeadingRadians())) + direction * (offset -= 0.02), 160) > 0);
		setTurnRightRadians(Math.tan(theta -= getHeadingRadians()));
			
		//stop and go movement
		//move when the enemy fires, or when the robot is moving randomly, or when the enemy is very close
		double energyDrop;
		if ((energyDrop = (enemyEnergy - (enemyEnergy = e.getEnergy()))) > movementMode - integer)
		{
			//credit to Cotilion for stop and go length calculator
			//credit to HedgehogGF for the copySign trick
			setAhead(Math.copySign(((3 + (int)(energyDrop * 1.999999)) << 3), Math.cos(theta)));
		}
				
		//random movement from Toorkild
		//don't move randomly if the enemy is ramming
		//reverse direction if the bot gets too close to a wall
		if (Math.random() + integer < (-0.6 * Math.sqrt(enemyBulletSpeed / enemyDistance) + 0.04)
			* movementMode	|| offset < Math.PI/3.5)
		{
			direction = -direction;
		}
		
		/********************************************
		 *--------------TARGETING CODE--------------*
		 ********************************************/
				
		int temp;	
		double latVel;	
	 double enemyHeading;
	 
		//calculate deceleration and whether or not to reset ticks since velocity change
		if ((temp = Integer.signum((int)(enemyVelocity - (enemyVelocity = e.getVelocity())))) != 0)
		{
			ticksSinceVelocityChange = temp;
		}
		
		//determine enemy wall proximity
		//inspired by Pugilist and HedgehogGF
		do
		{
			integer += fieldContains(absoluteBearing + (
			
					//determine the enemy's lateral movement direction
					//use a simple rolling average to store the previous lateral direction if enemy lateral velocity == 0
					//credit to HedgehogGF
					(wave[E_DIRECTION] = localEnemyDirection = (enemyDirection = Math.signum(0.00000000000001 +
					// ((enemyVelocity) * (Math.sin((enemyHeading = e.getHeadingRadians()) - absoluteBearing)))
					 (latVel = (enemyVelocity) * (Math.sin((enemyHeading = e.getHeadingRadians()) - absoluteBearing)))
					 + (enemyDirection / 100))) * FACTOR_ANGLE)

				 * ((short)WALL_TABLE.charAt(i))), enemyDistance);
		}
		while(--i > 0);		
		
		//determine current situation
		double localSituation = wave[SITUATION] =
			(integer << 5) +
			VELOCITY_HISTORY_TABLE.charAt(ticksSinceVelocityChange += 3) +
			//((int)enemyDistance >> 8) +
			//((int)Math.abs(enemyVelocity) / 3) +
		//	((int)Math.round(Math.abs(latVel) / 2)) +
		(Math.abs(latVel) );
		//	enemyDistance / 250;
		//	enemyDistance / 2000;
			
		double[] scores = new double[GUESS_FACTORS + 1];
			
	//	int j = -MIDDLE_FACTOR;
		int best = 0;//MIDDLE_FACTOR + 4;
		//offset = 0;
	//	do{
			i = newest;
					double relativeHeading;
		//	double angleScore = 0;
			try{
				do
				{
				//	if (Math.abs(j - (wave = waves.get(i++)).result) < 1)
				wave = waves[--i];	
				
			 if (i > lastLogged){
				wave[B_OFFSET] += ((enemyVelocity * Math.sin(relativeHeading = (enemyHeading - wave[A_BEARING]))) / (wave[E_DISTANCE] += (enemyVelocity * Math.cos(relativeHeading))));
			
			//check if the wave has passed the enemy's current location
		    if ((wave[W_DIST_TRAVELED] += 14) > wave[E_DISTANCE])
			{
				//wave[RESULT] = wave[B_OFFSET] / wave[E_DIRECTION];
				lastLogged++;
				//waves.add(this);
				//waveDistanceTraveled = Double.NEGATIVE_INFINITY;
			}
			}
		//calculate angle scores and select aim angle
			else// if ((firstActive - i) < 5000)
			//	if (i < firstActive)
				{				
							if ((scores[temp = ((int)Math.round(wave[B_OFFSET] / wave[E_DIRECTION]) + MIDDLE_FACTOR)]  
								+= ((wave[WEIGHT] + 1) * i) / (1 + Math.abs(wave[SITUATION] - localSituation))) >= scores[best]){
				//best = angle;	
				setTurnGunRightRadians((Math.random() * 0.007)//(theta / localSituation) 
+ Utils.normalRelativeAngle(absoluteBearing
					 - getGunHeadingRadians()	+ (//Math.signum(enemyEnergy) * 
localEnemyDirection * ((best = temp) - MIDDLE_FACTOR))));
				}
			}
			}while (true);
			}catch (Exception ex){}
		
		//radar
		setTurnRadarRightRadians(2 * Utils.normalRelativeAngle(absoluteBearing - getRadarHeadingRadians()));	
	}
	
	public void onBulletHit(BulletHitEvent e)
	{
		//adjust the enemy energy variable when the bot hits the enemy
		//this makes a big difference against linear targeting
		enemyEnergy -= 10;
	}
	
	public void onHitByBullet(HitByBulletEvent e)
	{
			//adjust the enemy energy variable when the bot gets hit
		//store the velocity of the enemy's bullet for the random movement
	//	double damage;
		enemyEnergy += (//damage = 
20 - (enemyBulletSpeed = e.getVelocity()));
		
		//if the bot takes an unacceptable amount of damage relative to the number of rounds
		//that have passed while in stop and go mode, switch to random movement
		if ((hits += (e.getPower() )) >= (getRoundNum() << 3) + 12)
	//	if ((hits += Math.sqrt(e.getPower() / ticksSinceHit)) >= (getRoundNum() + 1) )
		{
			movementMode = -1;
		}
		
		//ticksSinceHit = 0;
    }
	
	//This method returns 1 if a point projected from the bot's location by the 
	//"heading" and "distance" parameters is outside of the battlefield, and 0 if it is not.
	//credit to HedgehogGF
	private int fieldContains(double heading, double distance)
	{
		return Integer.signum(new Rectangle2D.Double(18, 18, 764, 564).outcode(getX() + distance * Math.sin(heading), getY() + distance * Math.cos(heading)));
	}
	
	//table for wall tests
	static final String WALL_TABLE = ""
	+ (char)MIDDLE_FACTOR
	
	+ FW1 + FW1 + FW1 + FW1 + FW1
	+ FW1 + FW1 + FW1 + FW1 + FW1
	+ FW1 + FW1 + FW1 + FW1 + FW1
	+ FW1 + FW1 + FW1 + FW1 + FW1
	+ FW1 + FW1 + FW1 + FW1 + FW1
	+ FW1 + FW1 + FW1 + FW1 + FW1
	+ FW1 + FW1
	
	+ FW2 + FW2 + FW2 + FW2 + FW2
	+ FW2 + FW2 + FW2 + FW2 + FW2
	+ FW2 + FW2 + FW2 + FW2 + FW2
	+ FW2 + FW2 + FW2 + FW2 + FW2
	+ FW2 + FW2 + FW2 + FW2 + FW2
	+ FW2 + FW2 + FW2 + FW2 + FW2
	+ FW2 + FW2
	
	+ FW3 + FW3 + FW3 + FW3 + FW3
	+ FW3 + FW3 + FW3 + FW3 + FW3
	+ FW3 + FW3 + FW3 + FW3 + FW3
	+ FW3 + FW3 + FW3 + FW3 + FW3
	+ FW3 + FW3 + FW3 + FW3 + FW3
	+ FW3 + FW3 + FW3 + FW3 + FW3
	+ FW3 + FW3
	
	+ RW1  + RW1  + RW1  + RW1
	+ RW1  + RW1  + RW1  + RW1
	+ RW2  + RW2  + RW2  + RW2
	+ RW2  + RW2  + RW2  + RW2;
		
	//tables for energy management
	static final String BP0 = ""
	+ (char)0 + (char)0 + (char)0 + (char)0 
	+ (char)0 + (char)0 + (char)0 + (char)0
	+ (char)0 + (char)0 + (char)0 + (char)0 
	+ (char)0 + (char)0 + (char)0 + (char)0
	+ (char)0 + (char)0 + (char)0 + (char)0 
	+ (char)0 + (char)0 + (char)0 + (char)0
	+ (char)0 + (char)0 + (char)0 + (char)0 
	+ (char)0 + (char)0 + (char)0 + (char)0;
	
	static final String	BULLET_POWER_TABLE = ""
	+ (char)2 + (char)2 + (char)2 + (char)2
	+ (char)2 + (char)2 + (char)2 + (char)2 
	+ (char)1 + (char)1 + (char)0 + (char)0
	+ BP0 + BP0 + BP0 + BP0 + BP0 + BP0 + BP0
	+ BP0 + BP0 + BP0 + BP0 + BP0 + BP0 + BP0
	+ BP0 + BP0 + BP0 + BP0 + BP0 + BP0 + BP0
	+ BP0 + BP0 + BP0 + BP0 + BP0 + BP0 + BP0
	+ BP0 + BP0 + BP0 + BP0 + BP0 + BP0 + BP0;	
	
	//velocity history tables
	//substrings for deceleration information	
	static final String D0 = ""
	+ (char)4*VELOCITY_VALUE + (char)4*VELOCITY_VALUE + (char)4*VELOCITY_VALUE;
	
	static final String D1 = ""
	+ (char)3*VELOCITY_VALUE + (char)3*VELOCITY_VALUE + (char)3*VELOCITY_VALUE;
	
	static final String D2 = ""
	+ (char)2*VELOCITY_VALUE + (char)2*VELOCITY_VALUE + (char)2*VELOCITY_VALUE;
	
	static final String D3 = ""
	+ (char)1*VELOCITY_VALUE + (char)1*VELOCITY_VALUE + (char)1*VELOCITY_VALUE;
	
	static final String D4 = ""
	+ (char)0*VELOCITY_VALUE + (char)0*VELOCITY_VALUE + (char)0*VELOCITY_VALUE;
	
	static final String D4_ = ""
		+ D4 + D4 + D4 + D4 + D4 + D4 + D4 
		+ D4 + D4 + D4 + D4 + D4 + D4 + D4 
		+ D4 + D4 + D4 + D4 + D4 + D4 + D4 
		+ D4 + D4 + D4 + D4 + D4 + D4 + D4 
		+ D4 + D4 + D4 + D4 + D4 + D4 + D4 
		+ D4 + D4 + D4 + D4 + D4 + D4 + D4 
		+ D4 + D4 + D4 + D4 + D4 + D4 + D4 
		+ D4 + D4 + D4 + D4 + D4 + D4 + D4 
		+ D4 + D4 + D4 + D4 + D4 + D4 + D4 
		+ D4 + D4 + D4 + D4 + D4 + D4 + D4 
		+ D4 + D4 + D4 + D4 + D4 + D4 + D4 
		+ D4 + D4 + D4 + D4 + D4 + D4 + D4 
		+ D4 + D4 + D4 + D4 + D4 + D4 + D4 
		+ D4 + D4 + D4 + D4 + D4 + D4 + D4 
		+ D4 + D4 + D4 + D4 + D4 + D4 + D4 
		+ D4 + D4 + D4 + D4 + D4 + D4 + D4 
		+ D4 + D4 + D4 + D4 + D4 + D4 + D4 
		+ D4 + D4 + D4 + D4 + D4 + D4 + D4 
		+ D4 + D4 + D4 + D4 + D4 + D4 + D4 
		+ D4 + D4 + D4 + D4 + D4 + D4 + D4 
		+ D4 + D4 + D4 + D4 + D4 + D4 + D4 
		+ D4 + D4 + D4 + D4 + D4 + D4 + D4;
	
	static final String VELOCITY_HISTORY_TABLE = ""	
		+ (char)0 + (char)0 + (char)5*VELOCITY_VALUE
		+ (char)0 + (char)6*VELOCITY_VALUE + (char)0
					
		+ D0 + D0 + D0 + D0 + D0
		
		+ D1 + D1 + D1 + D1 + D1
		+ D1 + D1 + D1 + D1 + D1
		+ D1 + D1
		
		+ D2 + D2 + D2 + D2 + D2
		+ D2 + D2 + D2 + D2 + D2
		+ D2 + D2 + D2 + D2 + D2
		+ D2 + D2 + D2
		
		+ D3 + D3 + D3 + D3 + D3
		+ D3 + D3 + D3 + D3 + D3
		+ D3 + D3 + D3 + D3 + D3
		+ D3 + D3 + D3 + D3 + D3
		+ D3 + D3 + D3 + D3
				
		+ D4_ + D4_ + D4_ + D4_ + D4_ + D4_ + D4_
		+ D4_ + D4_ + D4_ + D4_ + D4_ + D4_ + D4_
		+ D4_ + D4_ + D4_ + D4_ + D4_ + D4_ + D4_
		+ D4_ + D4_ + D4_ + D4_ + D4_ + D4_ + D4_
		+ D4_ + D4_ + D4_ + D4_ + D4_ + D4_ + D4_
		+ D4_ + D4_ + D4_ + D4_ + D4_ + D4_ + D4_
		+ D4_ + D4_ + D4_ + D4_ + D4_ + D4_ + D4_
		+ D4_ + D4_ + D4_ + D4_ + D4_ + D4_ + D4_
		+ D4_ + D4_ + D4_ + D4_ + D4_ + D4_ + D4_
		+ D4_ + D4_ + D4_ + D4_ + D4_ + D4_ + D4_
		+ D4_ + D4_ + D4_ + D4_ + D4_ + D4_ + D4_
		+ D4_ + D4_ + D4_ + D4_ + D4_ + D4_ + D4_
		+ D4_ + D4_ + D4_ + D4_ + D4_ + D4_ + D4_
		+ D4_ + D4_ + D4_ + D4_ + D4_ + D4_ + D4_
		+ D4_ + D4_ + D4_ + D4_ + D4_ + D4_ + D4_
		+ D4_ + D4_ + D4_ + D4_ + D4_ + D4_ + D4_
		+ D4_ + D4_ + D4_ + D4_ + D4_ + D4_ + D4_
		+ D4_ + D4_ + D4_ + D4_ + D4_ + D4_ + D4_
		+ D4_ + D4_ + D4_ + D4_ + D4_ + D4_ + D4_;	
}