Difference between revisions of "Radar"

From Robowiki
Jump to navigation Jump to search
(→‎Wide lock: Updated comment at bottom to refer to hard coded value of 36 rather than what used to be there)
m (Higher-quality image)
 
(20 intermediate revisions by 9 users not shown)
Line 1: Line 1:
 +
[[Image:Radar.png|thumb|right|300px|Radar in [[Robocode]]]]
 +
 
'''Radar''' is one of the most vital components of your robot. Without it, [[targeting]] is effectively impossible and [[movement]] is purely random. Just as with movement and targeting, there are many simple and complex algorithms for radar control. In most robots the radar takes up the smallest portion of code.
 
'''Radar''' is one of the most vital components of your robot. Without it, [[targeting]] is effectively impossible and [[movement]] is purely random. Just as with movement and targeting, there are many simple and complex algorithms for radar control. In most robots the radar takes up the smallest portion of code.
  
[[Image:Radar.jpg|thumb|right|300px|Radar in [[Robocode]]]]
+
== Technical information ==
 +
A radar in Robocode can turn a maximum of 45° or &pi;/4 rad in a single tick. The radar scans robots up to 1200 units away. The angle that the radar rotates between two ticks creates what is called a radar arc, and every robot detected within the arc is sent to the <code>onScannedRobot()</code> method in order of distance from the scanning bot. The closest bot is detected first, while the furthest bot is detected last. By default, the <code>onScannedRobot()</code> method has the lowest event priority of all the event handlers in Robocode, so it is the last one to be triggered each tick.
  
== Technical Information ==
+
== Prerequisites ==
A radar in Robocode can turn a maximum of 45° or &pi;/4<sup>rad</sup> in a single tick. The radar scans robots up to 1200 units away. The angle that the radar rotates between two ticks creates what is called a radar arc, and every robot detected within the arc is sent to the <code>onScannedRobot()</code> method in order of distance from the scanning bot. The closest bot is detected first, while the furthest bot is detected last. By default, the <code>onScannedRobot()</code> method has the lowest [[event priority]] of all the event handlers in Robocode, so it is the last one to be triggered each tick.
+
Before you start implementing a radar, you should have:
 +
# Followed the [[Robocode/My First Robot|My First Robot Tutorial]], and created a robot.
 +
# Read the [[Robocode/FAQ|FAQ]], understood non-blocking calls, and switched your robot to an <code>AdvancedRobot</code>.
 +
# Gotten a good understanding of Java and at least a basic familiarity of the [http://robocode.sourceforge.net/docs/robocode/ Robocode API].
  
== 1-vs-1 Radars ==
+
If you haven't done all of these, do them first. Otherwise, this article will only make you more confused.
1-vs-1 radars are the smallest of the bunch and many can get a scan in every turn, producing a perfect lock.
 
  
=== Spinning radar ===
+
== Display scan arcs ==
A simple spin of the radar, this is very ineffective in one on one, but still used in [[NanoBot]]s.
+
By default, Robocode hides radar arcs, to prevent visual overload. This is a good idea in large [[melee]] battles, but not when debugging your radar.
  
Here is an example of this type of radar:
+
Scan arcs can be enabled in Robocode's Preferences:
<pre>
 
public void run() {
 
    // ...
 
  
    do {
+
[[File:EnableScanArcs.png]]
        turnRadarRightRadians(Double.POSITIVE_INFINITY);
 
    } while (true);
 
}
 
</pre>
 
  
=== The infinity lock ===
+
== Configure the radar ==
The infinity lock is the simplest radar lock and it is used frequently in [[NanoBots]]. It has the disadvantage of "slipping" and losing its lock frequently. But is a much better alternative to the Spinning radar in one on one combat.
+
Your first action in <code>run()</code> should '''always''' be:
  
Here is an example of this type of radar:
+
<syntaxhighlight>
<pre>
+
setAdjustGunForRobotTurn(true);
public void run() {
+
setAdjustRadarForGunTurn(true);
    // ...
+
</syntaxhighlight>
    turnRadarRightRadians(Double.POSITIVE_INFINITY);
 
}
 
 
 
public void onScannedRobot(ScannedRobotEvent e) {
 
    // ...
 
    setTurnRadarLeftRadians(getRadarTurnRemainingRadians());
 
}
 
</pre>
 
 
 
=== Perfect radar locks ===
 
There are several "perfect" radar locks that will not slip once they have a lock.
 
 
 
==== Narrow lock ====
 
Point the radar at the enemy's last known location. This results in a thin beam which follows the enemy around the battlefield. Many recent one on one bots use this type of radar. This radar lock is similar to, and considered an enhancement on the wide radar lock described below.
 
 
 
If implemented correctly, it is not possible for the enemy escape this lock. A robot's width is 36px (that's 18px from the middle) and it can only move at up to 8px/turn, so if your beam is pointing at its centre, it won't be able to move entirely out of it in one turn. However, a robot will only automatically scan for enemies if its radar is turning, which might not happen if you are using a Narrow Lock and your enemy decides to stay still for 2 turns. For this reason, if you decide to use an unmultiplied Narrow Lock, you must call <code>scan()</code> yourself to avoid losing lock. Furthermode, if you skip turns, your enemy might be able to move out from your radar beam before you recover.
 
 
 
To overcome these issues, a Narrow Lock is often multiplied by a factor (as described below) to keep the radar moving and ensure the enemy does not escape the scan arc.
 
 
 
Here is an example of this kind of radar:
 
<pre>
 
import robocode.util.Utils;
 
 
 
public void run() {
 
    // ...
 
 
 
    turnRadarRightRadians(Double.POSITIVE_INFINITY);
 
    do {
 
        // Check for new targets.
 
        // Only necessary for Narrow Lock because sometimes our radar is already
 
        // pointed at the enemy and our onScannedRobot code doesn't end up telling
 
        // it to turn, so the system doesn't automatically call scan() for us
 
        // [see the javadocs for scan()].
 
        scan();
 
    } while (true);
 
}
 
 
 
public void onScannedRobot(ScannedRobotEvent e) {
 
    double radarTurn =
 
        // Absolute bearing to target
 
        getHeadingRadians() + e.getBearingRadians()
 
        // Subtract current radar heading to get turn required
 
        - getRadarHeadingRadians();
 
 
 
    setTurnRadarRightRadians(Utils.normalRelativeAngle(radarTurn));
 
 
 
    // ...
 
}
 
</pre>
 
  
The following factors affect the behaviour in the following ways (eg. <code>factor * Utils.normalRelativeAngle(radarTurn)</code>)
+
This allows your robot's base, gun, and radar to rotate independently. It is practically essential for radar locks and any form of accurate targeting.
* 1.0 - Thin radar lock. Must call scan() to avoid losing lock. God help you if you ever skip a turn.
 
* 1.9 - Radar arc starts wide and slowly narrows as much as possible while staying on target.
 
* 2.0 - Radar arc sweeps through a fixed angle. Exact angle chosen depends on positions of enemy and radar when enemy is first picked up. Angle will be increased if necessary to maintain a lock. Most used corrective factor.
 
  
==== Wide lock ====
+
== At round start ==
The Wide Radar Lock tries to scan a fixed distance to either side of the enemy. It was to the best of knowledge created before the Narrow Radar Lock. Its constant motion means the radar will not slip as long as you don't miss any turns.
+
One of the first actions your robot performs should be to turn the radar as much as possible. A simple implementation would be:
  
One nice effect of using this lock is that your robot's scan arc will increase as the enemy gets closer. This looks cool, if nothing else. This is the only benefit of this type of lock, as the narrow lock above can maintain a perfect lock with less code.
+
<syntaxhighlight>
 +
setTurnRadarRight(Double.POSITIVE_INFINITY);
 +
</syntaxhighlight>
  
Here is an example of this type of radar:
+
This causes the radar to begin turning clockwise, forever. However, it may not be wise to always turn the radar clockwise. Sometimes, turning it counterclockwise might provide more information, faster. The optimal scan direction is the one with the shortest rotational difference to the angle between the robot and the battlefield center.  
<pre>
 
import robocode.util.Utils;
 
  
public void run() {
+
For even faster information collection, you should turn the gun (or even the robot base as well) in the same direction as the radar. Due to [[Robocode/Game Physics|Robocode game physics]], spinning the gun and radar at the same time will give your robot a 65° (20° + 45°) scan arc, instead of a 45° arc.
    // ...
 
  
    do {
+
== 1-vs-1 radar ==
        // ...
+
: ''Main article: [[One on One Radar]]
        if (getRadarTurnRemaining() == 0.0)
+
One on one radars are the smallest of the bunch and many can get a scan in every turn, producing a perfect lock. This simplest lock is:
            setTurnRadarRightRadians(Double.POSITIVE_INFINITY);
 
        execute();
 
    } while (true);
 
}
 
  
 +
<syntaxhighlight>
 
public void onScannedRobot(ScannedRobotEvent e) {
 
public void onScannedRobot(ScannedRobotEvent e) {
     double radarTurn = Utils.normalRelativeAngle(
+
     setTurnRadarRight(2.0 * Utils.normalRelativeAngleDegrees(getHeading() + e.getBearing() - getRadarHeading()));
        // Absolute bearing to target
 
        getHeadingRadians() + e.getBearingRadians()
 
        // Subtract current radar heading to get turn required
 
        - getRadarHeadingRadians() );
 
 
 
    // Distance we want to scan from middle of enemy to either side
 
    double extraTurn = Math.min(Math.atan(36.0 / e.getDistance()), Math.PI/4.0);
 
 
 
    setTurnRadarRightRadians(radarTurn + (radarTurn < 0) ? -extraTurn : extraTurn);
 
 
 
    // ...
 
 
}
 
}
</pre>
+
</syntaxhighlight>
  
You can replace <code>36.0</code> with any distance you want covered. Too large a value and your robot will be caught in an infinity lock (described above).
+
Other types of [[One on One Radar|1v1 radar]] include the [[One on One Radar#Width Lock|width lock]] and the [[One on One Radar#The Infinity Lock|infinity lock]].
  
 
== Melee radars ==
 
== Melee radars ==
Melee radars are more complex and take up considerable more room inside a robot. Since the field of opponents does not usually fall within a 45° area, compromises must be made between frequent data of one bot (e.g., the firing target) and consistently updated data of all bots.
+
: ''Main article: [[Melee Radar]]
 
+
Melee radars are more complex and take up considerably more room inside a robot. Since the field of opponents does not usually fall within a 45° area, compromises must be made between frequent data of one bot (e.g., the firing target) and consistently updated data of all bots. Common melee radars include:
=== Spinning radar ===
+
* Spinning radar ‒ Simple but inefficient.
Just as with one on one, there is the generic spinning radar. This is the most used melee radar as it is by far the easiest to implement.
+
* Oldest scanned radar ‒ Scan all bots, and then reverse (unless it would be more efficient to not do that). Probably good enough.
 
+
* Optimal radar ‒ Present in all top melee bots. Left as an exercise to the reader.
<pre>
+
* Gun heat lock ‒ Lock on a target before firing, spin otherwise. Some bots do this.
public void run() {
 
    // ...
 
 
 
    while(true) {
 
        turnRadarRightRadians(Double.POSITIVE_INFINITY);
 
    }
 
}
 
</pre>
 
 
 
==== Corner Arc ====
 
A variation on the spinning radar, if the robot is in a corner it scans back and forth across the 90 degree arc away from the corner, as not to waste time scanning where there cannot be any robots. Typically, this is used only in smaller melee robots, which do not ahve room for a more complicated radar system. Melee bots with room tend to use one of the implementations below.
 
 
 
=== Oldest Scanned ===
 
This type of melee radar spins towards the robot it hasn't seen in the longest amount of time. Here is an example of this type of radar.
 
<pre>
 
import java.util.*;
 
import robocode.*;
 
import robocode.util.*;
 
 
 
// ... Within robot class
 
 
 
static LinkedHashMap<String, Double> enemyHashMap;
 
static double scanDir;
 
static Object sought;
 
 
 
public void run() {
 
    scanDir = 1;
 
    enemyHashMap = new LinkedHashMap<String, Double>(5, 2, true);
 
 
 
    // ...
 
 
 
    while(true) {
 
        setTurnRadarRightRadians(scanDir * Double.POSITIVE_INFINITY);
 
        scan();
 
    }
 
}
 
 
 
public void onRobotDeath(RobotDeathEvent e) {
 
    enemyHashMap.remove(e.getName());
 
    sought = null;
 
}
 
 
 
public void onScannedRobot(ScannedRobotEvent e) {
 
    String name = e.getName();
 
    LinkedHashMap<String, Double> ehm = enemyHashMap;
 
 
 
    ehm.put(name, getHeadingRadians() + e.getBearingRadians());
 
 
 
    if ((name == sought || sought == null) && ehm.size() == getOthers()) {
 
scanDir = Utils.normalRelativeAngle(ehm.values().iterator().next()
 
            - getRadarHeadingRadians());
 
        sought = ehm.keySet().iterator().next();
 
    }
 
 
 
    // ...
 
}
 
</pre>
 
With above code, the radar will spin passed every bot, and then reverse it's direction until passed all bots and repeat again. if spin take more than 4 ticks, Radar will continue spinning like spinning radar above. This kind of radar are use in many top bots include Shadow and Phoenix. I prefer you to use this kind of radar unless you need a melee radar lock or your targeting system require you to have enemy scan every 8 ticks.
 
 
 
=== Gun Heat Lock ===
 
A technique developed by [[Paul Evans]]/[[Kawagi]] for [[SandboxDT]]/[[FloodHT]]. This radar locks onto a target when the robot has low gunheat. Normally this is best for melee robots which use GuessFactor Targeting.
 
<pre>
 
 
 
public void run() {
 
    // ...
 
    setTurnRadarRightRadians(Double.POSITIVE_INFINITY);
 
}
 
 
 
public void onScannedRobot(ScannedRobotEvent e) {
 
    // ... your own target selection
 
    double absoluteBearing = getHeadingRadians() + e.getBearingRadians();
 
    if (isCurrentTarget && getGunHeat() < 0.5) { // Lock for 5 ticks
 
        setTurnRadarRightRadians(3.5 * Utils.normalRelativeAngle(absoluteBearing - getRadarHeadingRadians()));
 
    else
 
        setTurnRadarRightRadians(Double.POSITIVE_INFINITY);
 
}
 
</pre>
 
The code above uses a Narrow Lock but the simpler Infinity Lock works just as well. For a narrow lock, it is recommended you multiply by a large factor to continue scanning other robots while locked.
 
 
 
== Notes ==
 
For most of these radar locks, you will need to add one of the following to your <code>run()</code> method:
 
 
 
<pre>
 
setAdjustRadarForRobotTurn(true);
 
setAdjustGunForRobotTurn(true);
 
setAdjustRadarForGunTurn(true);
 
</pre>
 
 
 
[[Category:Code Snippets]]
 
[[th:เรดาร์]]
 

Latest revision as of 02:01, 28 August 2017

Radar in Robocode

Radar is one of the most vital components of your robot. Without it, targeting is effectively impossible and movement is purely random. Just as with movement and targeting, there are many simple and complex algorithms for radar control. In most robots the radar takes up the smallest portion of code.

Technical information

A radar in Robocode can turn a maximum of 45° or π/4 rad in a single tick. The radar scans robots up to 1200 units away. The angle that the radar rotates between two ticks creates what is called a radar arc, and every robot detected within the arc is sent to the onScannedRobot() method in order of distance from the scanning bot. The closest bot is detected first, while the furthest bot is detected last. By default, the onScannedRobot() method has the lowest event priority of all the event handlers in Robocode, so it is the last one to be triggered each tick.

Prerequisites

Before you start implementing a radar, you should have:

  1. Followed the My First Robot Tutorial, and created a robot.
  2. Read the FAQ, understood non-blocking calls, and switched your robot to an AdvancedRobot.
  3. Gotten a good understanding of Java and at least a basic familiarity of the Robocode API.

If you haven't done all of these, do them first. Otherwise, this article will only make you more confused.

Display scan arcs

By default, Robocode hides radar arcs, to prevent visual overload. This is a good idea in large melee battles, but not when debugging your radar.

Scan arcs can be enabled in Robocode's Preferences:

EnableScanArcs.png

Configure the radar

Your first action in run() should always be:

setAdjustGunForRobotTurn(true);
setAdjustRadarForGunTurn(true);

This allows your robot's base, gun, and radar to rotate independently. It is practically essential for radar locks and any form of accurate targeting.

At round start

One of the first actions your robot performs should be to turn the radar as much as possible. A simple implementation would be:

setTurnRadarRight(Double.POSITIVE_INFINITY);

This causes the radar to begin turning clockwise, forever. However, it may not be wise to always turn the radar clockwise. Sometimes, turning it counterclockwise might provide more information, faster. The optimal scan direction is the one with the shortest rotational difference to the angle between the robot and the battlefield center.

For even faster information collection, you should turn the gun (or even the robot base as well) in the same direction as the radar. Due to Robocode game physics, spinning the gun and radar at the same time will give your robot a 65° (20° + 45°) scan arc, instead of a 45° arc.

1-vs-1 radar

Main article: One on One Radar

One on one radars are the smallest of the bunch and many can get a scan in every turn, producing a perfect lock. This simplest lock is:

public void onScannedRobot(ScannedRobotEvent e) {
    setTurnRadarRight(2.0 * Utils.normalRelativeAngleDegrees(getHeading() + e.getBearing() - getRadarHeading()));
}

Other types of 1v1 radar include the width lock and the infinity lock.

Melee radars

Main article: Melee Radar

Melee radars are more complex and take up considerably more room inside a robot. Since the field of opponents does not usually fall within a 45° area, compromises must be made between frequent data of one bot (e.g., the firing target) and consistently updated data of all bots. Common melee radars include:

  • Spinning radar ‒ Simple but inefficient.
  • Oldest scanned radar ‒ Scan all bots, and then reverse (unless it would be more efficient to not do that). Probably good enough.
  • Optimal radar ‒ Present in all top melee bots. Left as an exercise to the reader.
  • Gun heat lock ‒ Lock on a target before firing, spin otherwise. Some bots do this.