Difference between revisions of "Stop And Go Tutorial"
(little changes) |
(→Variable Length: fixing table, clarifying text) |
||
(9 intermediate revisions by 5 users not shown) | |||
Line 2: | Line 2: | ||
Stop And Go is a very popular movement among [[NanoBots]] and [[MicroBots]]. It's extremely powerful against simple targeting methods as [[Head-On Targeting]], [[Linear Targeting]] or [[Circular Targeting]], however, it's extremely useless against advanced targetings for example [[Pattern Matching]] guns. For more details take a look at the 'official' [[Stop And Go]] page. | Stop And Go is a very popular movement among [[NanoBots]] and [[MicroBots]]. It's extremely powerful against simple targeting methods as [[Head-On Targeting]], [[Linear Targeting]] or [[Circular Targeting]], however, it's extremely useless against advanced targetings for example [[Pattern Matching]] guns. For more details take a look at the 'official' [[Stop And Go]] page. | ||
− | == But how it | + | == But how does it work? == |
Generally, [[Stop And Go]] means moving a bit when the enemy fires and stopping before its next firing. It confuses [[Linear Targeting]] and [[Circular Targeting]], because at the time of firing our bot stands still, so they work as [[Head-On Targeting]] which is useless against all one-way movements. | Generally, [[Stop And Go]] means moving a bit when the enemy fires and stopping before its next firing. It confuses [[Linear Targeting]] and [[Circular Targeting]], because at the time of firing our bot stands still, so they work as [[Head-On Targeting]] which is useless against all one-way movements. | ||
− | == Okay, but | + | == Okay, but what does it look like in code? == |
Now I show you how I implemented it in my nanos. <br><br> | Now I show you how I implemented it in my nanos. <br><br> | ||
First and foremost, the most important part of [[Stop And Go]] is keeping track of the enemy's previous energy. The difference between the previous and the actual energy state gives the necessary data to decide whether the enemy fired or not. So you should create a global variable for it. Of course, you should update it every turn you see the enemy. | First and foremost, the most important part of [[Stop And Go]] is keeping track of the enemy's previous energy. The difference between the previous and the actual energy state gives the necessary data to decide whether the enemy fired or not. So you should create a global variable for it. Of course, you should update it every turn you see the enemy. | ||
− | < | + | <syntaxhighlight> |
. | . | ||
. | . | ||
Line 17: | Line 17: | ||
. | . | ||
public void onScannedRobot(ScannedRobotEvent e){ | public void onScannedRobot(ScannedRobotEvent e){ | ||
− | + | ||
+ | //energy monitoring | ||
prevEnergy = e.getEnergy(); | prevEnergy = e.getEnergy(); | ||
} | } | ||
− | </ | + | </syntaxhighlight> |
<br> | <br> | ||
Now comes the energy monitoring. When a robot fires, it loses energy equal to the power of the bullet it fired. So if you realise an energy drop >0 and <=3, the enemy fired. I found 2 modes to check this code size friendly. First is the conditional approachment (notice that the getDistanceRemaining is essential for [[Stop And Go]]): | Now comes the energy monitoring. When a robot fires, it loses energy equal to the power of the bullet it fired. So if you realise an energy drop >0 and <=3, the enemy fired. I found 2 modes to check this code size friendly. First is the conditional approachment (notice that the getDistanceRemaining is essential for [[Stop And Go]]): | ||
− | < | + | <syntaxhighlight> |
− | if(getDistanceRemaining()==0.0 && prevEnergy-e.getEnergy()>0.0){ | + | . |
− | + | . | |
+ | . | ||
+ | static double prevEnergy = 100.0; | ||
+ | . | ||
+ | . | ||
+ | . | ||
+ | public void onScannedRobot(ScannedRobotEvent e){ | ||
+ | |||
+ | //energy monitoring | ||
+ | if(getDistanceRemaining()==0.0 && prevEnergy-e.getEnergy()>0.0){ | ||
+ | setAhead(36*direction); | ||
+ | } | ||
+ | prevEnergy = e.getEnergy(); | ||
} | } | ||
− | </ | + | </syntaxhighlight> |
The another mode is implemented in the movement code: | The another mode is implemented in the movement code: | ||
− | < | + | <syntaxhighlight> |
if(getDistanceRemaining()==0.0){ | if(getDistanceRemaining()==0.0){ | ||
setAhead(direction*36*Math.max(0,Math.signum(prevEnergy-e.getEnergy()))); | setAhead(direction*36*Math.max(0,Math.signum(prevEnergy-e.getEnergy()))); | ||
} | } | ||
+ | </syntaxhighlight> | ||
+ | The choice is yours and of course, the circumstances. I used only >0 condition, because it's more than enough for most robots. Obviously, you can expand this energy monitoring with several adjustments. For example, you can add <=3 to the condition. This avoids the little mistakes in the movement when your enemy continually hits you.( anyway your robot would think that the enemy hasn't fired.) Then you can check wall-hitting which has a similar affect on energy. To be a bit more effective against other targeting methods, you can [[Stop And Go Tutorial#Variable Length|vary the length]] of the movement. Playing with heading is also a good idea. (approaching, retreating) | ||
+ | |||
+ | == Even less CodeSize == | ||
+ | However, this kind of StopNGo can be squeezed even more. For example, the energy monitoring condition can be shrinked like this: | ||
+ | <syntaxhighlight> | ||
+ | if(prevEnergy > (prevEnergy = e.getEnergy()) && getDistanceRemaining() == 0.0){ | ||
+ | ...movement code... | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | If you move only short distances (e.g. 30-40px) you can leave out the getDistanceRemaining() condition. | ||
+ | <syntaxhighlight> | ||
+ | if(prevEnergy > (prevEnergy = e.getEnergy())){ | ||
+ | // ...movement code... | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | You can also play with the direction variable. In many cases you can simply mix the moving distance and the direction variable together. For example, if your movement distance is 36px, you can simply initalize direction 36. Then the code would be this: | ||
+ | <syntaxhighlight> | ||
+ | if(prevEnergy > (prevEnergy = e.getEnergy())){ | ||
+ | setAhead(direction); | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | == Variable Length == | ||
+ | It is critically important that your robot stop moving ''before'' the next enemy bullet is fired, or else its movement may get predicted by [[LT|linear]] and [[CT|circular]] targeting. It's also a good idea to move as much as you can before you have to stop, because the enemy's gun isn't always perfectly accurate, and longer movements will allow you to cover more ground toward a preferred distance to the enemy or location on the battlefield. According to Robocode game physics, the maximum movement length before the enemy will be able to fire again will be dependent on the enemy's [[Robocode/Game Physics#Bullets|gun heat]] and your robot's [[Robocode/Game_Physics#Robot_Movement_Physics|acceleration and deceleration]]. It is important to note that the [[Energy Drop|energy drop]] will be detected two ticks ''after'' the enemy bullet is fired, and since bullets fire before guns turn, the bullet would have been aimed with your velocity in the tick before it was fired, so the actual movement length will have to stop three ticks sooner than the maximum movement length as predicted by gun heat and robot movement rules. | ||
+ | |||
+ | Here are the maximum movement lengths for different enemy bullet powers, along with gun heat calculations and a tick-by-tick examination: | ||
+ | <pre> | ||
+ | Power 0.0: 19 pixels = (((0.0 / 5) + 1) / 0.1) - 3 = 7 = 1 + 2 + 3 + 4 + 5 + 3 + 1 | ||
+ | |||
+ | Power 0.5: 27 pixels = (((0.5 / 5) + 1) / 0.1) - 3 = 8 = 1 + 2 + 3 + 4 + 5 + 6 + 4 + 2 | ||
+ | |||
+ | Power 1.0: 33 pixels = (((1.0 / 5) + 1) / 0.1) - 3 = 9 = 1 + 2 + 3 + 4 + 5 + 6 + 6 + 4 + 2 | ||
+ | |||
+ | Power 1.5: 37 pixels = (((1.5 / 5) + 1) / 0.1) - 3 = 10 = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 5 + 3 + 1 | ||
+ | |||
+ | Power 2.0: 48 pixels = (((2.0 / 5) + 1) / 0.1) - 3 = 11 = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 6 + 4 + 2 | ||
+ | |||
+ | Power 2.5: 56 pixels = (((2.5 / 5) + 1) / 0.1) - 3 = 12 = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 8 + 6 + 4 + 2 | ||
+ | |||
+ | Power 3.0: 64 pixels = (((3.0 / 5) + 1) / 0.1) - 3 = 13 = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 8 + 8 + 6 + 4 + 2 | ||
</pre> | </pre> | ||
− | + | ||
+ | To conserve codesize, you can use an approximation like this formula from [[Cotillion]] 0.1: | ||
+ | <syntaxhighlight> | ||
+ | ((3 + (int)(/*<enemy energy drop>*/*1.999999)) << 3 ) | ||
+ | </syntaxhighlight> | ||
== See Also == | == See Also == |
Latest revision as of 20:58, 3 September 2014
Contents
What is Stop And Go?
Stop And Go is a very popular movement among NanoBots and MicroBots. It's extremely powerful against simple targeting methods as Head-On Targeting, Linear Targeting or Circular Targeting, however, it's extremely useless against advanced targetings for example Pattern Matching guns. For more details take a look at the 'official' Stop And Go page.
But how does it work?
Generally, Stop And Go means moving a bit when the enemy fires and stopping before its next firing. It confuses Linear Targeting and Circular Targeting, because at the time of firing our bot stands still, so they work as Head-On Targeting which is useless against all one-way movements.
Okay, but what does it look like in code?
Now I show you how I implemented it in my nanos.
First and foremost, the most important part of Stop And Go is keeping track of the enemy's previous energy. The difference between the previous and the actual energy state gives the necessary data to decide whether the enemy fired or not. So you should create a global variable for it. Of course, you should update it every turn you see the enemy.
.
.
.
static double prevEnergy = 100.0;
.
.
.
public void onScannedRobot(ScannedRobotEvent e){
//energy monitoring
prevEnergy = e.getEnergy();
}
Now comes the energy monitoring. When a robot fires, it loses energy equal to the power of the bullet it fired. So if you realise an energy drop >0 and <=3, the enemy fired. I found 2 modes to check this code size friendly. First is the conditional approachment (notice that the getDistanceRemaining is essential for Stop And Go):
.
.
.
static double prevEnergy = 100.0;
.
.
.
public void onScannedRobot(ScannedRobotEvent e){
//energy monitoring
if(getDistanceRemaining()==0.0 && prevEnergy-e.getEnergy()>0.0){
setAhead(36*direction);
}
prevEnergy = e.getEnergy();
}
The another mode is implemented in the movement code:
if(getDistanceRemaining()==0.0){
setAhead(direction*36*Math.max(0,Math.signum(prevEnergy-e.getEnergy())));
}
The choice is yours and of course, the circumstances. I used only >0 condition, because it's more than enough for most robots. Obviously, you can expand this energy monitoring with several adjustments. For example, you can add <=3 to the condition. This avoids the little mistakes in the movement when your enemy continually hits you.( anyway your robot would think that the enemy hasn't fired.) Then you can check wall-hitting which has a similar affect on energy. To be a bit more effective against other targeting methods, you can vary the length of the movement. Playing with heading is also a good idea. (approaching, retreating)
Even less CodeSize
However, this kind of StopNGo can be squeezed even more. For example, the energy monitoring condition can be shrinked like this:
if(prevEnergy > (prevEnergy = e.getEnergy()) && getDistanceRemaining() == 0.0){
...movement code...
}
If you move only short distances (e.g. 30-40px) you can leave out the getDistanceRemaining() condition.
if(prevEnergy > (prevEnergy = e.getEnergy())){
// ...movement code...
}
You can also play with the direction variable. In many cases you can simply mix the moving distance and the direction variable together. For example, if your movement distance is 36px, you can simply initalize direction 36. Then the code would be this:
if(prevEnergy > (prevEnergy = e.getEnergy())){
setAhead(direction);
}
Variable Length
It is critically important that your robot stop moving before the next enemy bullet is fired, or else its movement may get predicted by linear and circular targeting. It's also a good idea to move as much as you can before you have to stop, because the enemy's gun isn't always perfectly accurate, and longer movements will allow you to cover more ground toward a preferred distance to the enemy or location on the battlefield. According to Robocode game physics, the maximum movement length before the enemy will be able to fire again will be dependent on the enemy's gun heat and your robot's acceleration and deceleration. It is important to note that the energy drop will be detected two ticks after the enemy bullet is fired, and since bullets fire before guns turn, the bullet would have been aimed with your velocity in the tick before it was fired, so the actual movement length will have to stop three ticks sooner than the maximum movement length as predicted by gun heat and robot movement rules.
Here are the maximum movement lengths for different enemy bullet powers, along with gun heat calculations and a tick-by-tick examination:
Power 0.0: 19 pixels = (((0.0 / 5) + 1) / 0.1) - 3 = 7 = 1 + 2 + 3 + 4 + 5 + 3 + 1 Power 0.5: 27 pixels = (((0.5 / 5) + 1) / 0.1) - 3 = 8 = 1 + 2 + 3 + 4 + 5 + 6 + 4 + 2 Power 1.0: 33 pixels = (((1.0 / 5) + 1) / 0.1) - 3 = 9 = 1 + 2 + 3 + 4 + 5 + 6 + 6 + 4 + 2 Power 1.5: 37 pixels = (((1.5 / 5) + 1) / 0.1) - 3 = 10 = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 5 + 3 + 1 Power 2.0: 48 pixels = (((2.0 / 5) + 1) / 0.1) - 3 = 11 = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 6 + 4 + 2 Power 2.5: 56 pixels = (((2.5 / 5) + 1) / 0.1) - 3 = 12 = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 8 + 6 + 4 + 2 Power 3.0: 64 pixels = (((3.0 / 5) + 1) / 0.1) - 3 = 13 = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 8 + 8 + 6 + 4 + 2
To conserve codesize, you can use an approximation like this formula from Cotillion 0.1:
((3 + (int)(/*<enemy energy drop>*/*1.999999)) << 3 )