Difference between revisions of "HawkOnFire/Understanding HawkOnFire"
m (change YouTube link text) |
m (Small fixups) |
||
(3 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
{{Youtube|7e9qyOmo6nc|HawkOnFire}} | {{Youtube|7e9qyOmo6nc|HawkOnFire}} | ||
− | [[Rozu]] released the source to his breakthrough melee bot, [[HawkOnFire]], when he saw that people were genuinely interested in it some time ago | + | [[Rozu]] released the source to his breakthrough melee bot, [[HawkOnFire]], when he saw that people were genuinely interested in it some time ago. Since then, I think it's been on everyone's todo list to take a look at it. You can view it [[HawkOnFire/Code|here]]. |
− | + | It seems that [[Rozu]] took some time to edit and fix up the code before uploading it here, and for the benefit of clarity, it compiles to be a bit larger than the barely-micro size HawkOnFire normally is. That having been said, with some analysis and tweaking, I got HawkOnFireOS under 700 bytes with no loss of functionality or performance that I can see. | |
− | [[ | ||
− | |||
− | |||
− | == | + | == Classes == |
− | + | HawkOnFire is made up of 2 classes: | |
+ | * The main robot class. | ||
+ | * the <tt>microEnemy</tt> class, which contains the location, energy, and whether or not the enemy is alive. These are stored in a <tt>Hashtable</tt> in the robot class. | ||
− | + | == Functions == | |
+ | The primary magic in HawkOnFire lives in the <tt>evaluate()</tt> and <tt>doMovementAndGun()</tt> methods. <tt>run()</tt> doesn't do much besides set up and call these methods, and <tt>onScannedRobot()</tt> just updates the enemies and handles target selection. | ||
− | + | There are a few typical utility functions: | |
+ | * <tt>calcPoint()</tt>, which projects a point some distance away from a base location at some angle. | ||
+ | * <tt>calcAngle()</tt>, which finds the absolute bearing from one point to another. | ||
− | + | HawkOnFire also overrides the <tt>onRobotDeath()</tt> method to mark enemies as dead. | |
− | |||
− | |||
− | |||
− | |||
− | == | + | == Globals == |
− | + | Most of these are pretty self-explanatory, but the <tt>Point</tt>s declared should be explained: | |
+ | * <tt>nextDestination</tt> is the point that HawkOnFire is trying to get to. | ||
+ | * <tt>lastPosition</tt> is the point that HawkOnFire is coming from last. | ||
+ | * <tt>myPos</tt> is where HawkOnFire is now. | ||
− | == | + | == Radar == |
− | + | Spins the radar in melee, [[One on One Radar#The Infinity Lock|Infinity Lock]] in 1-on-1. | |
− | == | + | == Gun == |
− | + | Not too exciting. The enemy's position is set in <tt>onScannedRobot()</tt>, and lines 54-57 turn the gun and fire. | |
− | + | Contrary to rumors, HawkOnFire does not always fire power-3 bullets ‒ it's a little more aggressive than a lot of small melee bots as far as firepower is concerned, but not as aggressive as bots with a dependable gun. One feature that's worth pointing out is that <code>target.energy / 3</code> is in there, which is more than enough to kill the target at that point. HawkOnFire doesn't want a low-energy target to get lucky after being hit. Also, HawkOnFire always tries to target the closest living enemy, and likes to have its gun turned, and never fires when its energy is under 1. | |
− | |||
− | + | == Movement == | |
− | + | HawkOnFire is a textbook example of [[Minimum Risk Movement]]. The point-generating function generates 200 points at random between 100 and 300 pixels away but no more than 80% of the distance to its current target (to avoid hitting other robots as much). | |
− | |||
− | |||
− | Once you understand this formula, you pretty much understand [[ | + | === Risk Function === |
+ | The <tt>evaluate()</tt> method is HawkOnFire's risk function, except for one part ‒ the <tt>addLast</tt> variable that is passed in as a parameter is precomputed for consistency so that the same value is used when comparing for every point. <tt>addLast</tt> is set to <code>1 - Math.rint(Math.pow(Math.random(), getOthers()))</code>, which makes it 1 most of the time with more bots on the field and 0 about half of the time in 1-on-1. This variable determines whether <tt>lastPosition</tt> is used in the risk calculation. | ||
+ | |||
+ | Which leads us into <tt>evaluate()</tt> itself. Basically, after starting out the risk as addLast times an [[Anti-Gravity Movement|anti-gravity]] function on <tt>lastPosition</tt>, HawkOnFire iterates through the enemies, and for each live one, adds the proposed risk to the total risk (called <tt>eval</tt>). The formula is very simple and elegant (and I don't think I'm exaggerating to say that it's a breakthrough in and of itself) ‒ simply <code>energyRatio * (1 + perpendicularity) / distanceSq</code>. | ||
+ | * <tt>energyRatio</tt> is the enemy's energy / HawkOnFire's energy (but no more than 2) ‒ this makes enemies with higher energy more "dangerous". | ||
+ | * <tt>perpendicularity</tt> is the absolute value of the cosine of the difference between the angle from the point to HawkOnFire's current location and the angle from the point to the enemy. This is 0 when the point is at a right angle and 1 if the point is directly toward or away from the enemy. | ||
+ | * <tt>distanceSq</tt> is the distance from the point to the enemy. | ||
+ | |||
+ | Once you understand this formula, you pretty much understand HawkOnFire. | ||
+ | |||
+ | [[Category:Tutorials]] |
Latest revision as of 21:29, 24 October 2017
Rozu released the source to his breakthrough melee bot, HawkOnFire, when he saw that people were genuinely interested in it some time ago. Since then, I think it's been on everyone's todo list to take a look at it. You can view it here.
It seems that Rozu took some time to edit and fix up the code before uploading it here, and for the benefit of clarity, it compiles to be a bit larger than the barely-micro size HawkOnFire normally is. That having been said, with some analysis and tweaking, I got HawkOnFireOS under 700 bytes with no loss of functionality or performance that I can see.
Classes
HawkOnFire is made up of 2 classes:
- The main robot class.
- the microEnemy class, which contains the location, energy, and whether or not the enemy is alive. These are stored in a Hashtable in the robot class.
Functions
The primary magic in HawkOnFire lives in the evaluate() and doMovementAndGun() methods. run() doesn't do much besides set up and call these methods, and onScannedRobot() just updates the enemies and handles target selection.
There are a few typical utility functions:
- calcPoint(), which projects a point some distance away from a base location at some angle.
- calcAngle(), which finds the absolute bearing from one point to another.
HawkOnFire also overrides the onRobotDeath() method to mark enemies as dead.
Globals
Most of these are pretty self-explanatory, but the Points declared should be explained:
- nextDestination is the point that HawkOnFire is trying to get to.
- lastPosition is the point that HawkOnFire is coming from last.
- myPos is where HawkOnFire is now.
Radar
Spins the radar in melee, Infinity Lock in 1-on-1.
Gun
Not too exciting. The enemy's position is set in onScannedRobot(), and lines 54-57 turn the gun and fire.
Contrary to rumors, HawkOnFire does not always fire power-3 bullets ‒ it's a little more aggressive than a lot of small melee bots as far as firepower is concerned, but not as aggressive as bots with a dependable gun. One feature that's worth pointing out is that target.energy / 3
is in there, which is more than enough to kill the target at that point. HawkOnFire doesn't want a low-energy target to get lucky after being hit. Also, HawkOnFire always tries to target the closest living enemy, and likes to have its gun turned, and never fires when its energy is under 1.
Movement
HawkOnFire is a textbook example of Minimum Risk Movement. The point-generating function generates 200 points at random between 100 and 300 pixels away but no more than 80% of the distance to its current target (to avoid hitting other robots as much).
Risk Function
The evaluate() method is HawkOnFire's risk function, except for one part ‒ the addLast variable that is passed in as a parameter is precomputed for consistency so that the same value is used when comparing for every point. addLast is set to 1 - Math.rint(Math.pow(Math.random(), getOthers()))
, which makes it 1 most of the time with more bots on the field and 0 about half of the time in 1-on-1. This variable determines whether lastPosition is used in the risk calculation.
Which leads us into evaluate() itself. Basically, after starting out the risk as addLast times an anti-gravity function on lastPosition, HawkOnFire iterates through the enemies, and for each live one, adds the proposed risk to the total risk (called eval). The formula is very simple and elegant (and I don't think I'm exaggerating to say that it's a breakthrough in and of itself) ‒ simply energyRatio * (1 + perpendicularity) / distanceSq
.
- energyRatio is the enemy's energy / HawkOnFire's energy (but no more than 2) ‒ this makes enemies with higher energy more "dangerous".
- perpendicularity is the absolute value of the cosine of the difference between the angle from the point to HawkOnFire's current location and the angle from the point to the enemy. This is 0 when the point is at a right angle and 1 if the point is directly toward or away from the enemy.
- distanceSq is the distance from the point to the enemy.
Once you understand this formula, you pretty much understand HawkOnFire.