Épéeist/Code
Jump to navigation
Jump to search
/*
Epeeist(Micro) v3.7 by Sheldor. 05/01/2024 Code size: 749 bytes
a microbot with stop and go/random movement and a guess factor gun
v3.7 -- targeting based on v2.1, radar, fix table
Épée is one of the three forms of modern sport fencing,
along with foil and sabre. https://en.wikipedia.org/wiki/Epee
Credits:
Targeting: pez.micro.Aristocles, nz.jdc.HedgehogGF, kc.micro.Thorn, pez.mini.Pugilist, jam.mini.Raiko, Falcon, voidious.mini.Komarious, jam.micro.RaikoMicro, jk.mini.CunobelinDC, jk.micro.Connavar, mld.LittleBlackBook
Movement : nz.jdc.HedgehogGF, jk.micro.Cotillion, jk.micro.Toorkild, kc.micro.Thorn, wiki.nano.RaikoNano
Special thanks go to Jdev and Voidious for helping me with a mathematical error.
Also, a general thanks to all open source bot authors and contributors to the RoboWiki.
Epeeist 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.*;
public class Epeeist extends AdvancedRobot
{
//constants
static final int GUESS_FACTORS = 25;
static final int MIDDLE_FACTOR = (GUESS_FACTORS - 1) / 2;
static final double MAXIMUM_ESCAPE_ANGLE = 0.72727272727272727272727272727273; //8 / 11
static final double FACTOR_ANGLE = MAXIMUM_ESCAPE_ANGLE / MIDDLE_FACTOR;
static final char FW1 = 6;
static final char FW2 = 12;
static final char RW1 = (char)-6;
//global variables
static double direction = 1;
static double enemyBulletSpeed;
static double enemyDirection;
static double enemyEnergy;
static double enemyHeading;
static double hits;
static int movementMode;
static int previousEnemyVelocity;
static int mostVisited = 4 + MIDDLE_FACTOR;
static double enemyVelocity;
static int ticksSinceVelocityChange;
//array to store the number of times the enemy has visited each guess factor
//segmented on velocity history, velocity, forward and reverse wall proximity, and distance
static int[][][][][] guessFactors = new int[7][3][6][4][GUESS_FACTORS];
public void onStatus(StatusEvent e)
{
//colors
setColors(java.awt.Color.white, java.awt.Color.black, java.awt.Color.lightGray);
//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);
//set the radar and gun to turn independently
//Putting these here with the radar code lets me get rid of the run() method, saving one byte. credit to Cotillion
setAdjustRadarForGunTurn(true);
setAdjustGunForRobotTurn(true);
}
public void onScannedRobot(ScannedRobotEvent e)
{
//local variables
//declare the most used integer before the most used double to save several bytes
int i = 4;
double absoluteBearing;
double enemyDistance;
double localEnemyDirection;
double offset;
double theta;
int antiRam;
//fire a wave
Wave wave;
addCustomEvent(wave = new Wave());
//energy management based on distance, energy, and enemy energy
//retreat very heavily when the enemy is ramming
setFire((offset = (2 + (antiRam = (100 / (int)(wave.enemyDistance = enemyDistance = e.getDistance())))
)) + antiRam - (BULLET_POWER_TABLE
.charAt((((int)getEnergy() >> 3) * 127) + (int)e.getEnergy()) / 100.01)
);
/*********************************************
*---------------MOVEMENT CODE---------------*
*********************************************/
//wall smoothing based on HedgehogGF's
do{}while(fieldContains(theta = (wave.absoluteBearing = absoluteBearing =
(e.getBearingRadians() + getHeadingRadians())) + direction * (offset -= 0.02), 160) > 0);
setTurnRightRadians(Math.tan(theta -= getHeadingRadians()));
//stop and go movement originally based on Thorn's
//move when the enemy fires, or when the robot is moving randomly, or when the enemy is ramming
double energyDrop;
if ((energyDrop = (enemyEnergy - (enemyEnergy = e.getEnergy()))) > movementMode - antiRam)
{
//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 stop and go mode
//reverse direction if the bot gets too close to a wall
if (Math.random() + antiRam < (-0.6 * Math.sqrt(enemyBulletSpeed / enemyDistance) + 0.04) * movementMode
|| offset < Math.PI/3.5)
{
direction = -direction;
}
/********************************************
*--------------TARGETING CODE--------------*
********************************************/
//determine enemy wall proximity
//inspired by Pugilist and HedgehogGF
int wallScore = 0;
do
{
wallScore += 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.enemyDirection = localEnemyDirection = (enemyDirection = Math.signum(0.00000000000001 +
((enemyVelocity = e.getVelocity()) * Math.sin((enemyHeading = e.getHeadingRadians()) - absoluteBearing))
+ (enemyDirection / 100))) * FACTOR_ANGLE)
* ((short)WALL_TABLE.charAt(i))), enemyDistance);
}
while(--i >= 0);
//calculate deceleration and whether or not to reset ticks since velocity change
int deceleration;
if ((deceleration = Integer.signum(previousEnemyVelocity - (previousEnemyVelocity = (int)Math.abs(enemyVelocity)))) != 0)
{
ticksSinceVelocityChange = deceleration;
}
//determine the current situation
//Declaring a local array saves two bytes.
int[] guessFactorsLocal = wave.guessFactors = guessFactors
[VELOCITY_HISTORY_TABLE.charAt(ticksSinceVelocityChange += 3)] //deceleration and ticks since velocity change
[previousEnemyVelocity / 3] //velocity
[wallScore] //wall proximity
[(int)enemyDistance >> 8]; //distance
//find the most visited guess factor for the current situation
//default to previous most visited
//Looping like this is ugly, but it saves two bytes over the proper way.
try
{
while (true)
{
if ((guessFactorsLocal[++i]) > guessFactorsLocal[mostVisited])
{
mostVisited = i;
}
}
}
catch(Exception ex)
{
}
//turn the gun to the most visited guess factor
//random offset to resist bullet shielding
//aim directly at current enemy location when enemy energy == 0
setTurnGunRightRadians((0.007 * Math.random()) + Utils.normalRelativeAngle(absoluteBearing - getGunHeadingRadians()
+ (localEnemyDirection * (mostVisited - MIDDLE_FACTOR) * Math.signum(enemyEnergy))));
//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 -= 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 += damage) > (getRoundNum() * 23) + 40)
{
movementMode = -1;
}
}
static class Wave extends Condition
{
//global variables
double absoluteBearing;
double enemyDirection;
double bearingOffset;
double enemyDistance;
double waveDistanceTraveled;
int[] guessFactors;
public boolean test()
{
//velocity-based bearing offset for code size
//velocity and heading updated each tick
double relativeHeading;
bearingOffset += (enemyVelocity * Math.sin(relativeHeading = (enemyHeading - absoluteBearing))) / (enemyDistance += (enemyVelocity * Math.cos(relativeHeading)));
//check if the wave has passed the enemy's current location
if ((waveDistanceTraveled += 14) > enemyDistance)
{
//calculate the guess factor that the enemy has visited
//increment the bin that represents that guess factor
guessFactors[(int)Math.round(bearingOffset / enemyDirection) + MIDDLE_FACTOR]++;
//one result per wave
waveDistanceTraveled = Double.NEGATIVE_INFINITY;
}
return false;
}
}
//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 to look up wall tests
static final String WALL_TABLE = ""
+ FW1 + FW1
+ FW2 + FW2
+ RW1;
//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;
static final String MAIN = ""
+ (char)175 + (char)150 + (char)125 + (char)100
+ (char)83 + (char)66 + (char)50 + (char)33
+ (char)16 + (char)0
+ BP0
+ BP0
+ BP0
+ BP0
+ 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;
static final String BP190 = ""
+ (char)190 + (char)190 + (char)190 + (char)190
+ (char)190 + (char)190 + (char)190 + (char)190
+ (char)190 + (char)190 + (char)190 + (char)190
+ (char)190 + (char)190 + (char)190 + (char)190
+ (char)190 + (char)190 + (char)190 + (char)190;
static final String BULLET_POWER_TABLE = ""
//0 * 127
+ BP190
+ BP190
+ BP0 + BP0 + BP0 + BP0
+ (char)0 + (char)0 + (char)0 + (char)0
+ (char)0 + (char)0 + (char)0
//1 * 127
+ (char)175 + (char)150 + (char)170 + (char)170
+ (char)170 + (char)170 + (char)170 + (char)170
+ (char)170 + (char)170 + (char)170 + (char)170
+ (char)170 + (char)170 + (char)170 + (char)170
+ (char)170 + (char)170 + (char)170 + (char)170
+ (char)170 + (char)170 + (char)170 + (char)170
+ (char)170 + (char)170 + (char)170 + (char)170
+ (char)170 + (char)170 + (char)170 + (char)170
+ (char)170 + (char)170 + (char)170 + (char)170
+ (char)170 + (char)170 + (char)170 + (char)170
+ (char)170 + (char)170 + (char)170 + (char)170
+ (char)170 + (char)170 + (char)170 + (char)170
+ (char)170 + (char)170 + (char)170 + (char)170
+ (char)170 + (char)170 + (char)170 + (char)170
+ (char)170 + (char)170 + (char)170 + (char)170
+ BP0 + BP0 + BP0
+ (char)0 + (char)0 + (char)0 + (char)0
+ (char)0 + (char)0 + (char)0
//2 * 127
+ MAIN
//3 * 127
+ MAIN
//4 * 127
+ MAIN
//5 * 127
+ MAIN
//6 * 127
+ MAIN
//7 * 127
+ MAIN
//8 * 127
+ MAIN
//9 * 127
+ MAIN
//10 * 127
+ MAIN
//11 * 127
+ MAIN
//12 * 127
+ MAIN
+ 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
+ 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
+ BP0 + BP0 + BP0 + BP0 + BP0 + BP0 + BP0
+ BP0 + BP0 + BP0 + BP0 + BP0 + BP0 + BP0;
//tables to look up velocity history segment
//substrings for deceleration information
static final String D0 = ""
+ (char)0 + (char)0 + (char)0;
static final String D1 = ""
+ (char)1 + (char)1 + (char)1;
static final String D2 = ""
+ (char)2 + (char)2 + (char)2;
static final String D3 = ""
+ (char)3 + (char)3 + (char)3;
static final String D4 = ""
+ (char)4 + (char)4 + (char)4;
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
+ (char)0 + (char)6 + (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_;
}