This article is about understanding Nene, the reluctantly top-10 robot.
Originally Nene was not designed to be a top anything robot. Her codebase was originally a experimental codebase where I shoved any interesting bits of code. Which made it a development platform.
Nene's radar was designed to be as efficient as possible. When a round starts the radar controls movement, gun and radar control. This is because at this point it does not know where the enemy is. The robot then spins all parts so that its radar will turn towards the center of the battlefield. Which is a slightly more efficient method of its initial scan.
Once it finds the enemy, it determines if it can get another scan without having to turn any other parts of the robot. If not it enters the radar correction mode. This only occurs on the first initial scan. It will reverse the direction of its gun and turn so that its radar doesn't lose sight of the target. This is required because we were turning the gun and the body to give it a much greater then average scan radius in the first place.
After this is completed, the radar gives up control of the gun and body to the targeting and movement respectively.
Nene has a non-standard robot design. Every class extends the previous class, and it is built up like a tower. This allows data defined in super classes to be used in child classes. Such as as enemyAbsBearing, and similar values. However despite this benefit, the design is clunky and difficult to manage. It is easy to forget the class in which something is defined. I would not recommend this design to anyone else.
If there are no waves of any kind in the air, and the enemy robot is dead. Nene does a simple victory dance where she stops all forward/back movement and spins in place while randomly changing colors.
At the start of the round or when there are no waves of any kind in the air, Nene enters a special waveless movement mode. This mode is mainly used to keep her distance from enemies and walls.
This movement is a simple Minimum Risk Movement, of which Seraphim has a similar movement mode for the same purpose. The movement avoids the enemy robot and avoids going to close to the walls. It will eventually settle somewhere between the enemy and the walls, and face perpendicular to the enemy. It also has a special code to prevent it from getting trapped in a corner.
This is because, the surfing movement, while intelligent enough to avoid getting caught in a corner itself. Isn't intelligent enough to figure a way out of a corner if it is already there (such at the start of a round) and dodge bullets at the same time. Which often means it would otherwise end up dying quickly on the start of a round if it got unlucky.
Unlike a melee Minimum Risk Movement, this movement is used only for finding a superior position on the battlefield for its surfing movement, rather then dodging bullets itself.
Nene is a true surfer. It calculates the GuessFactor range it would cover when a wave would pass it, and determines the risk at that position by way of precise intersection and kNN. It then moves in the direction which it considers least dangerous.
It considers 3 different possible moves. Forward, Back and Stop.
Maximum Escape Angle
Nene uses the standard asin(8 / waveSpeed) method to determine maximum escape angle, it multiplies this by the direction to simplify calculation. It does not multiply the MEA by any factor, such as 1.1 or 1.2. This is because the robot simply does not clamp GF values to -1 to 1, which means a multiplier is unneeded.
It does however clamp shadow factors to -1.1 to 1.1. This is done mainly for improving the visual display of bullet shadows when painting rather then for any kind of mechanical benefit.
As with most true surfers. It uses a driving algorithm to determine how it will move. This is encloses within its predictMove method. It is fairly simple in that it determines takes an orbit center that it then tries to drive around at a certain distance. It reduces its maximum velocity if it is moving too quickly when approaching a wall, to better avoid hitting them.
It's distance function is fairly simple. When under or over its preferred distance, it refers to a minimum or maximum distance and a maximum turn which will be achieved at that distance. This way it avoids pointing directly towards or away from the enemy, which allows it to continue to avoid bullets efficiently.
Wave to Surf
It uses the wave that will hit it soonest as the wave to primarily surf. If two waves would hit it at the same time. It goes with the one fired first, which is usually the one with the highest bullet power.
Multiple Wave Surfing
It surfs multiple waves. After it determines the last position the primary wave could hit it. It then goes on to surfing the secondary wave, the wave that would hit it second, or at the same time. For every position it simulates on the second wave, it calculates the risk. It then takes the lowest risk it found on the second wave within a certain time limit and adds half of that to the primary risk.
If the second wave would have already have passed it by the time, it still calculates the risk at the current (end) position. It does this as it does not add the time offset from the primary wave to this calculation. It does however only evaluate the one position if it would have already passed. It isn't a perfect solution to the multiple bullets hitting at the same time problem. However it seems to work well enough in practice, as the primary bullet is almost always the more dangerous one (higher fire power).
Wall Collision Detection
It guesses when an enemy may have hit the wall if it suddenly slows down more then 2 when it nears a wall, and its velocity is 0. Which is impossible unless it hit it. While it may not be exact, as the robot may have slowed down before it it the wall, it just assumes it stayed at its previous velocity. This reduces the amount of shrapnel surfing the robot does.
Gun Heat Waves
It uses gun heat waves. This is especially important on end of round. As your bullet can kill an enemy as it is firing, meaning you don't know if it fired (as it is dead). It uses this heat wave to dodge this possible last shot.
It calculates if the gun will be cool in 2 turns, if so it fires a imaginary wave so that it can better dodge enemy fire at close range, by starting to move two turns before the enemy actually fires.
Gun Heat Wave Bullet Power
Nene uses the average power of the last 4 bullets the enemy fired, or the enemies energy, whichever is less.
Whenever Nene fires a bullet it is added to a list of active bullets. It also adds shadows to current surfing waves based on the bullet. Each wave gets an individual shadow entry for each bullet. Each of these shadows is then combined into a combined shadow, which is used in the surfing algorithm.
Whenever the enemy fires a wave, it checks each of the bullets in the list, if active they are added from their current position to these waves. If they are not active, they are removed from the list.
When a bullet collides with the enemy robot, or with another bullet, that bullet is removed from the bullet list. All waves the bullet has yet to pass through have that shadow removed from their individual shadow list as well, then it recombines the shadows.
The ETA to the robot is calculated by the distance from the waves current position to the nearest edge of the robot based on a unrotated square.
When the algorithm has determines the GuessFactor range the robot will be in for a given wave, it calculates the risk for those GFs.
For up to the 64 nearest kNN matches:
- If the GuessFactor is within the range, it adds a flat risk. Approximately 80% of the risk.
- It adds a risk based on the distance from the center of the range to the GuessFactor, this gets a relatively small weight, approximately 15%.
- It also adds risk based on the distance from the wave center to the calculated position, or enemy position to the calculated position, whichever is less. This gets approximately 5%.
After it does this it then calculates how much of the gf range is covered by bullet shadows for that range and removes risk based on that ratio. A complete coverage reduces the risk to zero.
It then weighs this value by how old the given data is, and if the given wave is imaginary or not.
Each of these risks is added to a running total which is then averaged by the total number of nearest matches.
When hit by a bullet, or a bullet hits another bullet. Nene takes the enemy bullet and checks all of its waves to find one with a similar fire power. When found it calculates how far from the bullets position the wave's traveled distance is. If that distance is close enough it marks that wave as the one that hit and removes it.
It updates the kd-tree based on the wave that was removed and the heading of the bullet for aim.
Nene's targeting is actually Mint's targeting. There is a great deal of structure between the gun and the rest of Nene for this reason, to translate all the variables between the two.
As far as targeting goes, this targeting is very simple.
The gun uses the next simulated position the robot will be at (as provided by the movement) as the firing location for the waves it fires. This not only allows the gun to be more accurate with its targeting, but also has the added benefit of making things more difficult for bullet shielders. Since it know exactly where it will be next, but the shielder does not.
A wave is created every turn and fired at the enemy. Normal waves get a weight of 0.1, where as waves that correspond to an actual fired bullet get a weight of 1.0.