Jrobots Tutorials
[English] [Italiano] [Espaņol]
- Tecniche di puntamento
- Jrobot: Platoon
- Jrobot: Phalanx and Stinger
Tecniche di puntamento - Autore: Leonardo Boselli
I limiti dei robot forniti come esempio sono evidenti: utilizzano lo scanner per individuare il nemico e sparano un missile verso il punto che hanno trovato. Spesso mancano il bersaglio perché il nemico è in movimento ed il missile impiega un certo tempo per raggiungere la distanza a cui esploderà
Per ottenere risultati migliori, un robot deve stimare la velocità del suo nemico e sparare il missile verso il punto in cui si troverà il bersaglio dopo qualche istante. Qui di seguito viene presentato l'algoritmo utilizzato da Phalanx. Può essere suddiviso in quattro parti:
- Stima della velocità
Per calcolare la velocità del nemico occorre utilizzare lo scanner per individuarne la posizione in istanti differenti. Bisogna ricordare che i metodi di sistema (come scan()) restituiscono valori interi, così è opportuno che passi un tempo sufficiente tra una lettura e l'altra per migliorare la precisione.
Questa è la parte più critica dell'algoritmo e la lascio al lettore come esercizio :)
- Calcolo del tempo di volo
Dopo aver stabilito la posizione e la velocità del nemico, il puntamento del cannone è praticamente immediato.
Prima di tutto, bisogna ricordare che il volo del missile è indipendente dal moto del robot che lo spara. Il missile viaggia sempre a 300 m/s, così occorre prevedere il punto in cui un missile che viaggia a tale velocità incontrerà il nemico in movimento.
E' possibile determinare la formula esatta in questo modo:
Sia P (in notazioni vettoriali) il punto sconosciuto in cui il missile incontrerà il nemico, R la posizione iniziale del nostro robot, T la posizione iniziale del bersaglio e V la sua velocità.
Il punto P sarà raggiunto dal bersaglio in t secondi, secondo la formula
P = T + V t
Il punto P sarà raggiunto dal missile nello stesso tempo, dopo aver percorso 300·t metri, che è la distanza tra R e P
(P - R)2 = (300 t)2
Ora abbiamo tre equazioni che possono essere utilizzate per ricavare il tempo di volo t.
Dopo alcuni calcoli algebrici si ottiene
t = ( sqrt(3002 D2 - (DxV)2) + D·V ) / (3002 - V2)
dove D = T - R, "x" è il prodotto vettoriale e "·" il prodotto scalare di due vettori.
Chi non ha dimestichezza con la notazione vettoriale, può forse comprendere meglio queste formule
Dx = Tx - Rx
Dy = Ty - Ry
t = ( sqrt(3002 (Dx2 + Dy2) - (DxVy - DyVx)2) - (DxVx + DyVy) ) / (3002 - (Vx2 + Vy2) )
- Calcolo della nuova posizione
Per determinare la nuova posizione del bersaglio, è possibile sostituire il tempo precedentemente calcolato nelle equazioni del moto del nemico
P = T + V t
cioè
Px = Tx + Vx t
Py = Ty + Vy t
- Puntamento del cannone
Infine, non rimane che calcolare gli argomenti del metodo cannon() (angolo e distanza) usando Px, Py e le coordinate del nostro robot.
E' tutto! Per domande o commenti, mandami un email.
Jrobot: Platoon - Autore: Leonardo Boselli
Questo è il codice sorgente del mio primo robot, Platoon. Può essere utile per imparare alcuni trucchi sui combattimenti tra Jrobots. Questo robot è molto semplice ed ottiene i migliori risultati nei combattimenti a squadre.
Per maggiori informazioni su Jrobots vai alla sezione Info.
Se vuoi scrivere un tutorial sul tuo robot, mandami un email.
Vediamo il codice sorgente:
public class __Platoon_ extends JJRobot {
/*
Il nome di ogni Jrobot deve iniziare con due underscore e terminare con uno. Nel mezzo sono ammessi solo caratteri alfanumerici. Deve estendere la classe JJRobot
*/
private static int count;
/*
Questa variabile conta i robot amici presenti nell'arena
*/
private static int[] cornerX = {50,950,950,50};
private static int[] cornerY = {50,50,950,950};
/*
Questi array contengono i valori del percorso seguito dal robot
*/
private static int targetX = 500;
private static int targetY = 500;
/*
Coordinate dell'ultimo bersaglio individuato
*/
private static int locX[] = new int[8];
private static int locY[] = new int[8];
/*
Posizione dei robot amici
*/
private static int corner1;
/*
Primo angolo scelto
*/
private int nCorner;
private int scan;
private int id;
void main() {
if((id = id()) == 0) {
count = 1;
corner1 = rand(4);
} else {
count = id+1;
}
/*
Nell'ultimo blocco if vengono contati i robot amici e vengono resettate le variabili statiche nel caso si tratti del primo robot creato. Il metodo id() restituisce un numero intero che identifica l'ordine in cui i robot vengono creati
*/
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);
/*
Il robot comincia ad avvicinarsi all'angolo scelto
*/
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 questo blocco switch il robot spara missili ed aspetta di raggiungere il primo angolo
*/
do {
drive(0,0);
while(speed() >= 50) fire1();
/*
Il robot aspetta che la velocità scenda al 50% e spara a ripetizione. Poi...
*/
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);
/*
... sceglie il prossimo angolo e...
*/
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;
/*
... spara missili aspettando di raggiungere l'angolo successivo
*/
}
} while(true);
}
private void fire1() {
/*
In questo metodo il robot sonda la zona dell'arena opposta al muro
*/
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 questo metodo il robot sonda l'arena a 360 gradi
*/
if(++scan > 360) scan = 0;
fire();
}
private void fire() {
locX[id] = loc_x();
locY[id] = loc_y();
/*
Il robot aggiorna la sua posizione
*/
int range;
if((range = scan(scan,1)) > 40 && range <= 740) {
/*
Lo scanner ha individuato un bersaglio
*/
if (count > 1) {
/*
Il robot non è solo
*/
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++) {
/*
Il bersaglio è un nemico?
*/
if(ct != id) {
int dx = shotX-locX[ct];
int dy = shotY-locY[ct];
if(dx*dx+dy*dy < 1600) {
shot = false;
break;
}
}
}
if(shot) {
/*
Si, è un nemico! Spara e avvisa i robot amici della posizione del nemico individuato
*/
targetX = shotX;
targetY = shotY;
cannon(scan,range);
scan -= 10;
/*
Arretra di 10 gradi l'angolazione dello scanner
*/
} else {
/*
No, è un amico! Spara all'ultimo bersaglio individuato
*/
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 {
/*
Il robot è solo. Fuoco a volontà
*/
cannon(scan,range);
scan -= 10;
}
}
}
}
Il codice sorgente di Platoon si può scaricare dalla pagina dei downloads.
Per domande o commenti, mandami un email.
Jrobot: Phalanx and Stinger - Author: Leonardo Boselli
Platoon si comporta bene soprattutto nei Team Match, ma i robot che usano buone tecniche di puntamento possono batterlo facilmente perché i suoi movimenti sono prevedibili. Con lo scopo di scrivere un robot con prestazioni migliori, ho creato Phalanx e Stinger.
I migliori robot calcolano la velocità dei nemici per aumentare i danni causati dai missili. Questa tecnica funziona bene quando i nemici mantengono una velocità costante; in queste condizioni è semplice prevedere la posizione del nemico quando il missile giungerà alla fine della sua corsa. Una possibile contromisura consiste nel far muovere il proprio robot avanti ed indietro; così facendo i robot più precisi sono ingannati, ma quelli meno intelligenti potrebbero essere abbastanza fortunati da colpire il robot quando cambia direzione. Una soluzione migliore è sicuramente quella di seguire un percorso a zig-zag come quello di Phalanx.
Stinger usa la stessa tecnica di tiro di Phalanx, ma segue un differente algoritmo di movimento. Cerca il nemico più vicino e lo segue come un'ombra. Quando è molto vicino (meno di 40 metri), spara ripetutamente verso la sua preda ad una distanza di 45 metri, colpendo così il suo bersaglio senza provocare alcun danno a se stesso.
Attualmente Phalanx combina le cinque tecniche principali utilizzate dai robot più forti. Le regole che segue sono:
- Non sparare agli amici: ottimo per gli incontri Double e Team
- Mantieni un'alta velocità e cambia direzione rapidamente: questo permette di evitare i missili sparati senza calcoli
- Segui un percorso a zig-zag: questo riduce i danni dei missili dei robot più intelligenti
- Corri in branchi per unire la potenza di fuoco: ottimo per gli incontri di tipo Team
- Calcola il tempo di volo dei missili per correggere la mira e seguire i nemici: per colpire veramente duro
Stinger sostituisce le regole 3 e 4 con:
- Segui il nemico più vicino: questo confonde gli avversari
- Spara sul nemico evitando di auto-danneggiarti: ottimo se la distanza è inferiore ai 40 metri
Il codice sorgente di Phalanx e Stinger si può scaricare dalla pagina dei downloads.
Per domande o commenti, mandami un email.