Advantages could be measure by: damage, alive partners, axis positions, etc. If you are in
a considerable advantage, attack!
There are several ways to estimate the values that determine if you are in advantage, and
some of them have been discussed in the group messages (read the Mailing List).
Share information among partners
Be sure you can access the information of your partners when playing in Double and Team
modes. They will help you to develop a cooperative strategy.
At the initialization phase, you can create static attributes or a static array containing all your robots, to access directly their information (or methods)...
M. Movement
- Start quickly
Weak robots frecuently lose at least 5 point of difference just at the very beginning, due
to being quiet too much time. Start moving...
- Keep moving, ever!
To stop completely is worst than being predictable. Speed never should go down the
"minimum reasonable speed" of 15m/s.
- Avoid the walls
A pair of points is a big difference when the competition is hard. And worst, your robot
will be quiet for a while and it will be an easy target for the enemy. Define
your own move() method, which test for potential collisions before calling the
native drive().
- Flock is good, but avoid to be too near from partners
Each enemy's missile will produce the double (or worse) of damage if 2 (or more)
partners are in the range of the explosion. If two partners are too near, they
have almost the same potential value than just one enemy, and therefore they
lose the numerical advantage.
- 700m strategy is a must
Every good robot has one... It's important in Single mode and vital in Team mode. If you
choose an agressive one, remember don't insist until the death. Take care with
corners... or you could be jailed.
- Precision decreases with distance
That could be a good or bad thing depending on the situation and your strategy, ... but
it's a fact. So, use it!
Of course if you develop a good targeting algorithm, try to be far away from your
opponent to take advantage of that. In general, there is an optimal distance
that balance your shooting precision and the length of your movements.
- Going straight is very dangerous
It's the most easy "pattern" to predict. Never expose an easy target to your
enemy!
- Return over the track is dangerous too
Some basic robots shoot to the position collected by the radar. When the missile arrives to
the destination, you should be far away from there... but you could be in the wrong place if your bot has decided to return.
- Optimal time to turn
Assuming that the most common estimation method is to fire ahead, the best moment to
turn is when the enemy has fired the missile. You can estimate this precise
moment assuming it is shooting at the maximum frequency (1 missile per second). So
you can use the time of the last impact received by your robot and the distance,
to estimate when he is ready to fire again.
- Optimal angle to turn?
Maybe... but one thing it's true, turning 180 (or around 0) degrees, is not the best
choice because it simplify the task of your opponent. Most of them estimate
your movement as linear, therefore every position over the actual traveling
line won't be safe. Some will shoot behind you, and other ahead you, so side
turns is a smarter choice.
- Consider the distance
When you are closer to the enemy, precision improves and missiles arrive quicker. So you
have less time to run away... don't expose an easy target, change your position quickly.
- Protect weak partners
A very damaged partner produces the SAME damage than a healthy one. A dead robot doesn't produce anything... so move them far away from enemies.
T. Targeting
- Save a history of samples
You will need them to estimate the target's future position, and to act in consecuence.
It's obvious when you think about shooting, but sometimes it could be useful to
determine your own movements too...
- Take care about time consumption
To make 360 scans too often could take too much time, specially if your robot needs a lot
of calculations inside the scanning process. You can remember target's last
position and search around it, or use a kind of dichotomic search.
At the beginning, it originated a delay in Tango that affected its overall performance.
Moreover, if you have an efficient (time) robot, you can use faster speeds in the Arena to
improve the debug process.
- Improve the precision
The native scan gives you a maximum precision of 1 degree. The error it could contain at long
distance is important.
Once found the target, you can play with a pair of consecutive readings with small
variations of angles and beam width to double the precision.
- Use several samples to approximate the real position
Don't believe just in one reading. Use a combination of 2 (or more) consecutive readings to
get a more approximated position.
Try to find a sampling frecuency that gives you some meaningful information between
samples.
Sampling too often could slow down your bot, and the variation could be too small to be
useful.
- Share information among partners
Precision increases with a pair of different points of view. You can use 2 (or more) partners
to combine information to improve the precision.
Moreover, you can give preponderant value to scans of robots nearer to target.
- Signal processing?
Assume you are sampling a signal wich have "noise", so you should
"absorb" it. You can try some known function, or to invent your own...
Fortunately here things are simpler than the general problem. In the game, the signal is
not arbitrary... It's compounded of broken lines, so you could "aling" the samples (just take care of angles)
- Iterative targeting
Remember, your estimation should consider that the target will be moving while the missile is
travelling. So you could need an iterative process (or a mathematical model) to
estimate the most approximated target position when the missile arrive.
Iteration is a worth and easy technique... but general experience shows that 2 cycles are
enough to obtain a reasonable precision. There are mathematical models to
simplify it too. (Read previous explanation about it, in the Mailing List).
- Improve your scanning alone
To test my scanning algorithm, I used to collect, in a simultaneous way, the estimations
obtained by my scan algorithm and the real positions of the target.
After that, I estimated the overall (quadratic) error comparing estimated vs. real in a
spreadsheet, so I can evaluate the precision of different targeting methods.
To collect the real position, you can fight against a robot prepared for testing, that
just save its real path... or other way: modifying the scope of the array
"jr" in the JJRobots class, and then simply call the enemy methods
loc_x() and loc_y() to get the target's real position.
S. Shooting
- Care your friends and yourself...
It's a very obvious advice, but surprisingly it's common to find bots with self destructive
behavior... To recognize a friend, compare the estimated position with the real
positions (previously saved in a shared array?) of your partners.
- Quicker is better
Don't miss time between shots, every ms can make the vital difference in the last shot
of the game if things come tight... so synchronize your weapon.
- Sinchronize shared target
Eat the cake, bite by bite. It's more productive to join fire power against shared
targets than to fire in a separate way.
- Be persistent
Insist with your targets. A very damaged enemy produces the SAME damage than a healthy one.
So finish your work before change the target.
- If you doubt, be conservative
To "overestimate" the movement of your opponent in general works fine
just with "linear" robots. Good robots change of direction
frequently, so a less predictive estimation could work better.
- Put "hard" limits to estimations
Your estimations never should break the "physical" rules, so put a filter
before call the cannon() function.
For example, a target never could advance more than 30 m/s so you can limitate your
estimation considering the missile flight time. If you have estimated the
current target's speed, you could adjust and improve this limit... Consider
that in general they never advance less than 15m/s neither, and the estimated
position never could be out of arena's limits. Etc.
If the target is in the explosion (40m) range, what should we do? You can optimize the
benefit considering the enemy´s damage and your own self damage.
- Pattern prediction works!
Some robots have a predictable pattern... and in general other too ;-)
Some of them have a very deterministic pattern (e.g. Dragon, etc.), and other have more
complex patterns... but if you are patient you should find some relationship
among coordinates (x,y,t). Use these patterns to improve your estimations...
- Scenarios
You can use several techniques (or parameters) to estimate the target future position, and
you will note each technique (or parameters) works well with some enemies but not
as well with other...
It's possible to use a kind of "what if" analysis during the game, to decide which
technique is better against the current robot.
Unfortunatly, as corresponding to every rule, most of those included here have small
exceptions... and I'm sure these exceptions are exploited by good robots. At least Tango does it ;-)
Anyway, I think general rules are a good beginning, and exceptions could be discussed
further.
I hope some of you find these advices useful to improve your robots.
See you in the arena, Caos (the author of Tango, I mean the jrobot not the dance :-> )
The Shortest Effective Jrobot Ever Written - Author: Angsuman
JROBOTS is an extremely addictive Java game where you develop robots in java to fight against other jrobots in a monthly battle royale. I will present you with a simple sample jrobot to encourage you to participate in this contest. It kicks the butt of all sample jrobots provided in the download bundle and even some veterans.
JROBOTS developers are hesitant to provide actual code because of two reasons;
- It will lead to proliferation of copy-cat jrobots with a different name which are just a waste of time for all.
- Nobody likes to reveal their secrets
I have considered them over the years. I have come to the conclusion that the benefits of providing simple code for developers to begin with far outweighs other concerns. So here is a simple jrobot which despite its simplicity can really kick butt of many jrobots. It was initially released as CounterStrike. However now the CounterStrike code is slightly more sophisticated. So I am releasing this jrobot named Simple.
public class __Simple_ extends JJRobot {
void main() {
int distance, angle = 0;
while (true) {
while((distance = scan(angle, 1)) == 0) angle++;
cannon(angle, distance);
drive(angle, 100);
}
}
}
You can see how easy it is to start coding jrobots. What are you waiting for?
See you in the arena, Angsuman (author of Bizarro, Janeway, Shrike, CounterStrike)
A Pseudocode Template for Cadets - Author: GregM
The following example of pseudocode is an outline of a complex bot. You can read detailed explanations below.
public void main() { - this function runs your bot
while(true) { - this loop executes once per second
find and record the position of the enemy
move in a random direction at 15 m/s
wait one second
find and record the position of the enemy again
use the linear targetting formula to determine how to shoot
fire at that spot -make sure a full second has elapsed!
}
}
So what this bot does is it finds the enemy at intervals of a second,
figures out what direction it's moving in and shoots to intercept it.
Meanwhile, our bot moves randomly, turning once every second, which
makes it hard to hit with the kind of linear targetting we're using here.
You will want to split up these tasks into different functions that
are called from main(). Notice that you need to remember a position
twice in this example. An easy way to do this is with a JJVector,
which combines an x-coordinate, a y-coordinate, and a time into one
object that is easy to use.
This bot uses linear targetting, which is devastating against bots
that go straight but fails badly against bots that turn frequently. If
you know the enemy is moving randomly, you should not use linear
targetting, which will often miss completely, but try firing directly
at the enemy's current position. Or something in between linear and
direct targetting might work best. The best bots look at the enemy's
movement and try to figure out which shooting strategy will work best
in the current fight."
See you in the arena, GregM (author of StrangeMatter)
Aiming Techniques - Author: Leonardo Boselli
The limitations of the simpler robots are clear: they use the scanner to locate the enemy and then fire a missile to that location. Often they miss the target because it moves away and the missile takes some time to reach the range where it explodes.
To get better performances, a robot must estimate the speed of its enemy and then it must fire the missile to a location some step forward the target. The following is the algorithm used by Phalanx and Stinger. It can be divided into four parts:
- Speed Estimation
To calculate the speed of the enemy a robot must use the scanner to take the location of the enemy at different instants. Remember that the main system methods (such as scan()) return integers, so you need to scan locations when some time has elapsed to improve precision.
This is the difficult part of the algorithm and I leave it to the reader as an exercise :)
- Flight Time Computation
When you have the location and speed of the enemy the training of the cannon is straightforward.
First of all, the flight of the missile is independent from the speed of the shooting robot (this is explained in the Info section). The missile always flies at 300 m/s, so we have to forecast the point where a missile flying at such a speed will meet the moving enemy.
You can find the exact formula to compute the flight time this way:
Say P (using vector notation) the unknown point in which the missile meets the enemy, R the starting location of your robot, T the starting location of the target and V its velocity.
The target will reach the point P in t seconds, according to the formula
P = T + V t
The missile will reach the point P in the same time after flying for 300·t meters, that is the distance of R from P
(P - R)2 = (300 t)2
Now we have three equations that we can use to find the flight time t.
After some algebraic computations we get
t = ( sqrt(3002 D2 - (DxV)2) + D·V ) / (3002 - V2)
where D = T - R, "x" is the cross product of two vectors and "·" their dot product.
If you are not familiar with vector notation, maybe this is clearer
Dx = Tx - Rx
Dy = Ty - Ry
t = ( sqrt(3002 (Dx2 + Dy2) - (DxVy - DyVx)2) + (DxVx + DyVy) ) / (3002 - (Vx2 + Vy2) )
- New Target Computation
To calculate the target location after the flight time, simply substitute t in the equations of motion of the enemy
P = T + V t
that is
Px = Tx + Vx t
Py = Ty + Vy t
- Training the Cannon
Finally, there is a trivial task: you must compute the arguments of the cannon() method (angle and range) using Px, Py and the coordinates of your robot.
That's all, folks! For questions or comments, send me an email.
Jrobot: Platoon - Author: Leonardo Boselli
This is the "making of..." Platoon, which is my first Jrobot. This tutorial may be useful to learn some tricks about Jrobots fights. This robot is really simple and performs better in team matches.
For more information about Jrobots see the Info section.
If you want to write a tutorial about your own robot, send me an email.
Let's see the source code:
public class __Platoon_ extends JJRobot {
/*
The name of every Jrobot must start with two underscores and end with one. Only alphanumeric characters are allowed in the middle. Your class must extend the JJRobot class
*/
private static int count;
/*
This variable counts the friend robots involved in the fight
*/
private static int[] cornerX = {50,950,950,50};
private static int[] cornerY = {50,50,950,950};
/*
These arrays contain values for the path followed by robots
*/
private static int targetX = 500;
private static int targetY = 500;
/*
Coordinates of the last target found
*/
private static int locX[] = new int[8];
private static int locY[] = new int[8];
/*
Locations of friend robots
*/
private static int corner1;
/*
First corner chosen
*/
private int nCorner;
private int scan;
private int id;
void main() {
if((id = id()) == 0) {
count = 1;
corner1 = rand(4);
} else {
count = id+1;
}
/*
The latter if-block counts the friend robots and reset static variables when the first robot is created. The built-in id() method returns a number that identifies the order of creation of robots.
*/
nCorner = corner1;
int dx = cornerX[nCorner]-(locX[id]=loc_x());
int dy = cornerY[nCorner]-(locY[id]=loc_y());
int angle;
if(dx == 0) {
angle = dy > 0? 90: 270;
} else {
angle = atan(dy*100000/dx);
}
if(dx < 0) angle += 180;
drive(angle,100);
/*
The robot starts a route to the chosen corner
*/
switch(nCorner) {
default:
case 0: while(locX[id] > 150 || locY[id] > 150) fire2(); break;
case 1: while(locX[id] < 850 || locY[id] > 150) fire2(); break;
case 2: while(locX[id] < 850 || locY[id] < 850) fire2(); break;
case 3: while(locX[id] > 150 || locY[id] < 850) fire2(); break;
}
/*
In this switch-block the robot fires missiles waiting for the first corner
*/
do {
drive(0,0);
while(speed() >= 50) fire1();
/*
The robot waits for a 50% speed fall firing. Then...
*/
if(++nCorner == 4) nCorner = 0;
dx = cornerX[nCorner]-loc_x();
dy = cornerY[nCorner]-loc_y();
if(dx == 0) {
angle = dy > 0? 90: 270;
} else {
angle = atan(dy*100000/dx);
}
if(dx < 0) angle += 180;
drive(angle,100);
/*
... the robot chooses the next corner and...
*/
switch(nCorner) {
default:
case 0: while(locY[id] > 150) fire1(); break;
case 1: while(locX[id] < 850) fire1(); break;
case 2: while(locY[id] < 850) fire1(); break;
case 3: while(locX[id] > 150) fire1(); break;
/*
... it fires missiles waiting for the next corner
*/
}
} while(true);
}
private void fire1() {
/*
In this method the robot scans the side opposite the wall
*/
switch(nCorner) {
default:
case 0: if(++scan > 470 || scan < 240) scan = 250; break;
case 1: if(++scan > 200 || scan < -30) scan = -20; break;
case 2: if(++scan > 290 || scan < 60) scan = 70; break;
case 3: if(++scan > 380 || scan < 150) scan = 160; break;
}
fire();
}
private void fire2() {
/*
In this method the robot scans all around
*/
if(++scan > 360) scan = 0;
fire();
}
private void fire() {
locX[id] = loc_x();
locY[id] = loc_y();
/*
The robot updates its location
*/
int range;
if((range = scan(scan,1)) > 40 && range <= 740) {
/*
The scanner finds a target
*/
if (count > 1) {
/*
The robot is not alone
*/
boolean shot = true;
int shotX = locX[id]+range*cos(scan)/100000;
int shotY = locY[id]+range*sin(scan)/100000;
for(int ct = 0; ct < count; ct++) {
/*
Is the target an enemy?
*/
if(ct != id) {
int dx = shotX-locX[ct];
int dy = shotY-locY[ct];
if(dx*dx+dy*dy < 1600) {
shot = false;
break;
}
}
}
if(shot) {
/*
Yes, it is an enemy! Fire and notify friend robots about the enemy found
*/
targetX = shotX;
targetY = shotY;
cannon(scan,range);
scan -= 10;
/*
Turn back the scanner a bit
*/
} else {
/*
No, it is a friend! Fire to the last target found instead
*/
int dx = targetX-locX[id];
int dy = targetY-locY[id];
int dist2 = dx*dx+dy*dy;
if(dist2 > 1600 && dist2 <= 547600) {
int angle;
if(dx == 0) {
angle = dy > 0? 90: 270;
} else {
angle = atan(dy*100000/dx);
if(dx < 0) angle += 180;
}
cannon(angle,sqrt(dist2));
}
}
} else {
/*
The robot is alone. Don't worry, fire!
*/
cannon(scan,range);
scan -= 10;
}
}
}
}
You can find the source code of Platoon in the downloads page.
For questions or comments, send me an email.
Jrobot: Phalanx and Stinger - Author: Leonardo Boselli
Platoon works fine in Team Match, but some robots with strong aiming techniques win against it in Single and Double Match, because its movement if easily foreseeable. To improve the behaviour of Platoon, I've written Phalanx and Stinger.
The best robots use enemy speed tracking to improve damages caused by fired missiles. This technique needs a constant speed to forecast the location of the enemy at the end of the flight of the missile. If the robot moves back and forth, smart enemies are confused, but less smart robots are luck enough to hit it when it changes direction. A better solution is to follow a zigzag path as Phalanx do.
Stinger uses the same shooting technique of Phalanx, but it follows a different movement algorithm. It looks for the nearest enemy and follows it like a shadow. When it's really close (less than 40 meters) it always fires missiles towards the enemy at a distance of 45 meters, so it damages the enemy without damaging itself.
Now Phalanx combines the five main fight techniques of the strongest robots. The rules it follows are:
- Don't shoot to friends: good for Double and Team play
- Keep high speed and change direction quickly: this avoids missiles fired in place
- Follow a zigzag path: this avoids missiles fired by smart robots
- Run in flocks to join fire power: a real value in Team play
- Compute flight time of missiles and rectify the aim to track enemies: good if you want to hit something very hard
Stinger changes rules 3 and 4 with:
- Follow the nearest enemy very close: this confuses the enemy
- Fire towards the enemy avoiding self damaging: good if the distance is below 40 meters
You can find the source code of Phalanx and Stinger in the downloads page.
For questions or comments, send me an email.