PointInLineRRAL/Code

From Robowiki
< PointInLineRRAL
Revision as of 23:10, 17 March 2026 by Sheldor2 (talk | contribs) (Created page with "<syntaxhighlight lang="java"> /* PointInLineRRAL v1.0 by Sheldor. 03/12/2025 749 bytes multimode movement and randomized statistical targeting v1.0 -- expanded multimode, ex...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
/*
PointInLineRRAL v1.0 by Sheldor.  03/12/2025  749 bytes
multimode movement and randomized statistical targeting
v1.0 -- expanded multimode, experimental targeting

Point-in-line is a fencing technique.  https://en.wikipedia.org/wiki/Fencing_terminology#P
The "RRAL" stands for Randomized Rolling Average Linear targeting; it's a reference to John Cleland's nanobot naming scheme.

Credits:
Many thanks to John Cleland (nz.jdc) for his Neophyte series of nanobots, from which I drew much inspiration.
Movement : sheldor.micro.Epeeist, jk.micro.Toorkild, kc.micro.Thorn, wiki.nano.RaikoNano, nz.jdc.HedgehogGF, jk.micro.Cotillion
Also, a general thanks to all open source bot authors and contributors to the RoboWiki.

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

package sheldor.micro;
import robocode.*;
import robocode.util.Utils;
import java.awt.geom.*;

public class PointInLineRRAL extends AdvancedRobot
{
	//Constants
	static final int NUMBER_OF_AVERAGES = 100000;	
	
	//Global variables
	static int scans;
	static double averageEnemyLateralVelocity;
	static double[][] velocities = new double[17][NUMBER_OF_AVERAGES + 1];		
	static int[] indexVelocities = new int[NUMBER_OF_AVERAGES + 1];	
	
	static double direction = 1;
	static double enemyBulletPower;	
	static double enemyEnergy;	
	static double hits;
	static int    movementMode;
	
	static double distance;	
	static double gunHeat;
	static int enemyBullets;	
	static int reverseTicks;
	
	//En garde!
	public void run()
	{
		gunHeat = (enemyBulletPower = 3.0);
		
		//hedgehog colors
		setBodyColor(java.awt.Color.pink);
		
		//set the radar and gun to turn independently
		setAdjustRadarForGunTurn(true);
		setAdjustGunForRobotTurn(true);
	}

	public void onStatus(StatusEvent e)
	{		
		gunHeat -= 0.1;
		reverseTicks--;

		//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    antiRam;
		double enemyDistance;
		double absoluteBearing;
		double theta;
		
		double offset = (antiRam = 100 / (int)(distance = enemyDistance = e.getDistance()))
			+ (enemyDistance > ((2 + movementMode) * 125) ? 1.4 : 2.1);
		
		//wall smoothing based on HedgehogGF's
		while(fieldContains(theta = (absoluteBearing = 
			(e.getBearingRadians() + getHeadingRadians())) + direction * (offset -= 0.02), 160) > 0);
		setTurnRightRadians(Math.tan(theta -= getHeadingRadians()));
		
		//enemy firing and wall hit detection
		double energyDrop;
		if ((energyDrop = (enemyEnergy - (enemyEnergy = e.getEnergy()))) > 0)
		{
			if (energyDrop > 3 || gunHeat > 0)
			{
				energyDrop -= 3;
				//averageEnemyLateralVelocity = 0;
			}
			else
			{
				gunHeat = 1.0 + (energyDrop / 5);
				enemyBulletPower = energyDrop;
				
				 //second movement mode
				 if (++enemyBullets % 2 >= movementMode)
				 {
					direction = -direction;
				 }
			}
		}
			
		//stop and go movement originally based on Thorn's
		//move when the enemy fires, in other movement modes, and when the enemy is ramming
		if (energyDrop > -antiRam || movementMode != 2)
		{			
			//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, or if the bot is in other movement modes
		//reverse direction if the bot gets too close to a wall
		if (Math.random() + antiRam < (-0.6 * Math.sqrt(Rules.getBulletSpeed(enemyBulletPower)
			/ enemyDistance) + 0.04) * Math.signum(2 - movementMode) || offset < Math.PI/3.5)
		{
			direction = -direction;
			reverseTicks = 40;
		}
		
		//System.out.println(0.5 * Math.log((getEnergy())));
		double bulletPower;// = Math.min(enemyEnergy / 4, Math.max((int)(480 / enemyDistance), Math.min(getEnergy() / 25, enemyBulletPower)));//antiRam + 2;		
	/*	if (enemyEnergy <= 16)
		{
			bulletPower = enemyEnergy / 4;
		}	*/	
		
	//	if ((antiRam != 0 || getEnergy() > bulletPower + 0.21)  ) 
		if (getEnergy() > (bulletPower 
			= Math.min(enemyEnergy / 4, Math.max((480 / enemyDistance), Math.min(getEnergy() / 25, enemyBulletPower)))
			)){
 			setFire(bulletPower);
 		}
/*&& setFireBullet(bulletPower) != null){
	 
 }
			accuracy *= 0.9;
			//random = --accuracy < -10 / Math.random();
		}*/
		
		double bulletVelocity;// = Rules.getBulletSpeed(bulletPower);
		int bulletFlightTime = (int)Math.ceil(enemyDistance / (bulletVelocity = Rules.getBulletSpeed(bulletPower)));
	
		double[] v;
		
		//randomized statistical targeting
		setTurnGunRightRadians(Utils.normalRelativeAngle((Math.random() * 0.007) + absoluteBearing  - getGunHeadingRadians() +
			Math.asin(velocities[(indexVelocities[bulletFlightTime + ++scans] = (8 + (int)((v = velocities[indexVelocities[scans]])[(int)++v[0]] = (averageEnemyLateralVelocity = ((averageEnemyLateralVelocity * bulletFlightTime) 
			+ (e.getVelocity() * Math.sin(e.getHeadingRadians() - absoluteBearing))) / (bulletFlightTime + 1)))))][(int)(Math.sqrt(Math.random()) * v[0])] / bulletVelocity)
			));
		
		//radar lock
		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 -= Rules.getBulletDamage(e.getBullet().getPower());
		
		//accuracy += 5;
	}
	
	public void onHitByBullet(HitByBulletEvent e)
	{
		//adjust the enemy energy variable when the bot gets hit
		double damage;
		enemyEnergy += (damage = 20 - e.getVelocity());
		
		//low-weight situations
		if (reverseTicks > 0 || distance < 200){
			damage *= 0.4;
		}
		
		//movement mode test
		//ignore ramming distance
		if (distance > 100 && (hits += Math.sqrt(damage)) > ((getRoundNum() + 1) * 5))
		{
			movementMode++;
			hits = 0;
			reverseTicks = 40;
		}
    }
	
	//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, getBattleFieldWidth() - 36, getBattleFieldHeight() - 36).outcode(getX() + distance * Math.sin(heading), getY() + distance * 				Math.cos(heading)));
	}
}