- REDIRECT FastTargeting#CircularTargeting

public void onScannedRobot(ScannedRobotEvent e) { double turnrate=(e.getHeadingRadians()-lastEnemyHeading)/(getTime()-scantime); scantime=getTime(); lastEnemyHeading=e.getHeadingRadians(); ... ... ... }

Now we need to know the current position of the target bot. To keep things easy, we only calculate the position of your target relative to your position. Keep in mind that in Robocode, "north" is zero degrees(radians) and clockwise is a positive angle. This is exactly the inverse of unit-circle math, where the x-axis is zero degrees and anti-clockwise is a positive angle.

absoluteBearing = e.getBearingRadians() + getHeadingRadians(); double relativeX = e.getDistance()*Math.sin(absoluteBearing); double relativeY = e.getDistance()*Math.cos(absoluteBearing);

Since we __assume__ the target will keep turning at the same turnrate every turn, we can predict it's position at any time by calculating a new velocity-vector, and add that to it's position. If we call the time that you scanned the target t=0, then it's position at t=1 will be:

(this is not a java code snippet) ( 1 ) newX(1) = relativeX + enemyVelocity*sin(initialHeading + turnrate) ( 2 ) newY(1) = relativeX + enemyVelocity*cos(initialHeading + turnrate)

at time t=2, it will be

(this is not a java code snippet) ( 3 ) newX(2) = relativeX + enemyVelocity*sin(initialHeading + turnrate) + enemyVelocity*sin(initialHeading + turnrate + turnrate) ( 4 ) newY(2) = relativeX + enemyVelocity*cos(initialHeading + turnrate) + enemyVelocity*cos(initialHeading + turnrate + turnrate)

You can see that you can calculate the new (relative) X/Y position at t=T by adding a newly calculated velocity-vector to its position on every t.

(this is not a java code snippet) ( 5 ) newX(T) = relativeX + enemyVelocity*sin(initialHeading + t*turnrate) ( 6 ) newY(T) = relativeY + enemyVelocity*cos(initialHeading + t*turnrate)

Space and time is not continuous in Robocode, but the discreet steps are small enough, that we can approximate the above summation with an integral:

(this is not a java code snippet) ( 7 ) newX(T) = relativeX + enemyVelocity * sin(initialHeading + t*turnrate) dt ( 8 ) newY(T) = relativeY + enemyVelocity * cos(initialHeading + t*turnrate) dt

integrating from t=0 to t=T wich results in: (__watch the +/- signs!! and where you need cosine and sine__)

(this is not a java code snippet) ( 9 ) newX(T) = relativeX - (enemyVelocity/turnrate) * (cos(initialHeading + T*turnrate) - cos(initialHeading)) ( 10 ) newY(T) = relativeY + (enemyVelocity/turnrate) * (sin(initialHeading + T*turnrate) - sin(initialHeading))

Just fill in T in the above and you can predict your circular-moving target's position at time T!
Now to predict at wich time your bullet is going to hit your target. The time it would take for your bullet to travel to the target's *current* position is a good guess to start with. So your first guess would be T = enemyDistance/bulletSpeed. If we plug this T in formulae (9) and (10), we have a prediction of the target's new (relative) position at time T. But since the target will be moving around, rather than playing sittingDuck, this is a rather poor approximation of the time T we are after. We can improve our approximation by calculating the time it would take for your bullet to reach the __previously predicted__ position. This new T can then in turn be used to calculate a better predicted position, wich, in turn, can be used to calculate an even better approximation of the actual time T, etc...etc... I myself have never used this iteration technique, but I remember reading somewhere(RoboCodeRepository? forums?) that 4 or 5 of these iterations should be good enough. Alisdair Owens, the author of Nicator and the [SnippetBot tutorial], wrote an article for "Secrets of the Robocode master" about circular targeting with iteration. You can find it here: http://www-106.ibm.com/developerworks/library/j-circular/

Another method is to start at T=0, and keep increasing with T with 1. Every time you increase your T, compare the distance your bullet would travel in T timeframes, with the distance between you and the predicted position of your target at time T. Stop when your bullet reaches your target, and you'll have a predicted position! Because the position of the target is calculated step-by-step anyway, we don't need formulae (9) and (10) and will be performing the summations (5) and (6) step by step as well. You can find an example from this in CodeSnippets section. It's the source-code from my bot Nano Circular Linear Predictor, a bot I built just to prove that a circular predictor fits into a NanoBot. :-) Note that the step-by-step method can be used for both CircularTargeting and LinearTargeting, whereas the integrated formulae (9) and (10) are not suited for linear targeting. (Linear targeting means turnrate = 0)

--- Dummy

__Related Links:__

- Circular targeting example-code
- Alisdair Owen's [circular targeting tutorial] with iteration

**Comments**

Does anyone have a good way to put the iterative predicitive stuff (ala the NCLP) into an ExtendsRobot bot? --Alphax

FOR loops --UnderDark

Thank you, Captain Obvious.

The problem is that it's useful to have scans on consecutive ticks for that. You could either stop your bot and try and get two consecutive scans, or if the other bot is really moving in a roughly even curve, you can find the change in heading and divide it by the number of ticks between observations.

Of course, you should probably just use an AdvancedRobot, or not do circular targeting - if you're trying to enter it into a competition where only ExtendsRobot is allowed, none of your opponents will be moving in curves. -- Kawigi

double TurnRate = (Math.abs(Heading1-Heading2))/(Math.abs(TimeOfHeading1-TimeOfHeading2));Hope this helps --UnderDark

Here is a play on Circular Targeting, it uses math only, its the Orbit gun from my nanobot Orbit (expanded of course, which wasn't an easy task). This piece of code could maybe be changed into a circle gun by putting something into the aimAngle calculation. (and calculating where that center is).

Orbit's Gun

double absoluteBearing = e.getBearingRadians() + getHeadingRadians(); double lateralVelocity = e.getVelocity() * Math.sin(e.getHeadingRadians() - absoluteBearing); double bulletSpeed = (20 - 3 * bulletPower); double distance = e.getDistance(); double circularTravel = absoluteBearing + lateralVelocity / bulletSpeed; double aimAngle = Math.atan2(distance * Math.sin(circularTravel), distance * Math.cos(circularTravel)); turnGunRightRadians(Utils.normalRelativeAngle(-getGunHeadingRadians() + aimAngle));

- I'm pretty sure this is just linear targeting. In this equation, aimAngle will always equal circularTravel. -- Simonton
- Hrm dang, I reversed a equation of a circle to help get that. There must be a way to deloop the loop in a circle gun, its just math! But again simonton is far better at delooping things then I am. --Chase-san
- Starting to deloop it...I'll explain everything later, as this is simply replacing variables such as "turnCircleRadius?" with the actual formula (I'll post y later), although this requires a VERY accurate bullet travel time formula.

- Hrm dang, I reversed a equation of a circle to help get that. There must be a way to deloop the loop in a circle gun, its just math! But again simonton is far better at delooping things then I am. --Chase-san

x=(enemyX-(((Math.abs(enemyVelocity) * 360.0 / (10.0 - .75 * Math.abs(enemyVelocity))) / (2.0 * Math.PI))*Math.sin((enemyHeading+(Math.PI/2))%Math.PI))) + (Math.sin((((8/((Math.abs(enemyVelocity) * 360.0 / (10.0 - .75 * Math.abs(enemyVelocity))) / (2.0 * Math.PI))) * bulletTravelTime) % (2.0 * Math.PI)) * ((Math.abs(v) * 360.0 / (10.0 - .75 * Math.abs(v))) / (2.0 * Math.PI)));

---

The loop is only necessary to work out the time`t`

when the bullet will hit the robot. If you can guess `t`

beforehand, you can avoid the looping and just shoot at where the enemy will be at time `t`

. A working estimate for `t`

is the time it takes to shoot a bullet into the centre of the enemy's movement:
double t = Math.sqrt(Math.pow(getX() - movementCentreX?, 2) + Math.pow(getY() - movementCentreY?, 2))/bulletSpeed;

Plug this into equations (9) and (10) above and you have co-ordinates to shoot at.

This might not give you the smallest possible value of `t`

for a given bullet speed (I haven't checked, but the code seems to do rather poorly against sample.Corners), but it'll give you a value that works. The only way I know to get a smaller value of `t`

will require iteration as you're essentially backing out roots from a trig function.

Of course, it goes without saying that a delooped circular targeting gun will be useless against anything that doesn't move in great arcs. If you want to hit those robots, you're better off sticking with the iterative method. But since a delooped circular targeting gun runs in constant time, it can form part of a virtual guns system without causing you to skip turns on massive battlefields. --duyn