PointInLineRRAL/Code
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)));
}
}