Jrobots Tutorials
[English] [Italiano] [Español]
- Técnicas para apuntar
- La construcción de Platoon
- La construcción de Phalanx y Stinger
Técnicas para apuntar - Autor: Leonardo
Boselli
Las limitaciones de los robots más simples son claras: usan el radar
para localizar el enemigo y disparan un misil a dicha ubicación.
Generalmente fallan en su intento de impactar el objetivo porque el
enemigo se ha movido mientras el misil viaja hasta el punto donde debe
explotar.
Para obtener mejores resultados, un robot debe estimar la
velocidad de su enemigo y luego disparar un misil a la posición futura que
éste tendrá al momento de explotar. El siguiente algoritmo es usado por Phalanx
y
Stinger, y puede ser dividido en cuatro partes:
- Estimación de velocidad
Para calcular la velocidad del
enemigo, un robot debe usar el radar para identificar la ubicación del
enemigo en diferentes momentos. Recuerde que las principales funciones
(como el scan()) retornan valores enteros, lo que obliga a realizar
rastreos cada cierto tiempo de tal manera de mejorar la precisión. Esta
es la parte difícil del algoritmo y la dejaré al lector como ejercicio
:)
- Cálculo del tiempo de vuelo
Cuando ya tienes la ubicación
y la velocidad del enemigo, el entrenamiento del cañón es sencillo.
Antes que nada, el vuelo del misil es independiente de la velocidad
del robot que lo dispara (esto es explicado en
Info
section). El misil siempre vuela a 300 m/s, por lo que tenemos
que estimar el punto donde un misil volando a dicha velocidad
interceptará al enemigo en movimiento.
Puedes encontrar la fórmula exacta para calcular el tiempo de vuelo
de esta manera:
Digamos que P (usando notación vectorial) es el
punto desconocido en el que el misil interceptará al enemigo. R
es la ubicación del robot que realiza el disparo.
T la ubicación inicial del objetivo y V su velocidad.
El objetivo alcanzará el punto P en t segundos,
de acuerdo con la fórmula:
P = T + V t
El misil recorrerá 300.t metros para alcanzar el punto P,
que es igual a la distancia de P a R(P - R)2 = (300 t)2
Ahora tenemos tres ecuaciones que podemos usar para encontrar el tiempo
de vuelo
t.
Después de algunos cálculos algebraicos obtenemos:t = ( sqrt(3002 D2 - (DxV)2) + D·V ) / (3002 - V2)
donde
D = T - R, "x" es el producto
vectorial de dos vectores y "·" su producto escalar.
Si no estás familiarizado con la notación vectorial, quizás es más
claro:
Dx = Tx - Rx
Dy = Ty - Ry
t = ( sqrt(3002 (Dx2 + Dy2) - (DxVy - DyVx)2) + (DxVx + DyVy) ) / (3002 - (Vx2 + Vy2) )
- Cálculo del nuevo objetivo
Para calcular la ubicación del
objetivo luego del tiempo de vuelo del misil, simplemente debes
sustituir t en las ecuaciones de movimiento del enemigo por:P = T + V t
esto es:
Px = Tx + Vx t
Py = Ty + Vy t
- Entrenamiento del disparo
Finalmente queda una tarea
trivial: debes calcular los argumentos de la función cannon() (ángulo
y distancia) usando Px, Py y las coordenadas de tu
robot.
Eso es todo! Por preguntas o comentarios, envía
un email.
Jrobot: Platoon - Autor: Leonardo Boselli
Estos son lo secretos de Platoon, el cual fue mi primer
Jrobot. Esta guía puede ser útil para aprender algunos trucos sobre
los combates con
Jrobots. Este robot es muy simple y funciona mejor en el modo de
equipos (Team).
Por más información sobre Jrobots ver la
sección de
información.
Si deseas escribir un manual sobre tu propio robot,
envíalo por email.
Veamos el código fuente:
public class __Platoon_ extends JJRobot {
/*
El nombre de cada robot debe comenzar con 2 underscores y terminar con 1.
Solo caracteres alfanuméricos son permitidos en el nombre. Tu clase debe ser
una extensión de la clase JJRobot.*/
private static int count;
/*
La variable contendrá la cantidad de robots amigos involucrados en el
combate*/
private static int[] cornerX = {50,950,950,50};
private static int[] cornerY = {50,50,950,950};
/*
Estos arreglos contienen las coordenadas de las esquinas que usará el
robot. */
private static int targetX = 500;
private static int targetY = 500;
/*
Coordenadas del último enemigo encontrado*/
private static int locX[] = new int[8];
private static int locY[] = new int[8];
/*
Ubicaciones de los robots amigos*/
private static int corner1;
/*
Selección de la primer esquina*/
private int nCorner;
private int scan;
private int id;
void main() {
if((id = id()) == 0) {
count = 1;
corner1 = rand(4);
} else {
count = id+1;
}
/*
El último bloque if cuenta los robots amigos y inicializa las
variables estáticas cuando el primer robot es creado. El método id()
retorna un número que identifica cada robot según sus orden de creación.*/
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);
/*
Los robots comienzan el camino hacia la esquina seleccionada*/
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;
}
/*
En este bloque switch el robot dispara misiles mientras llega a la
esquina*/
do {
drive(0,0);
while(speed() >= 50) fire1();
/*
El robot dispara mientras espera frenar hasta el 50% de velocidad. Luego... */
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);
/*
... el robot elige la próxima esquina y ... */
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;
/*
... dispara misiles esperando llegar a dicha esquina*/
}
} while(true);
}
private void fire1() {
/*
En este método el robot escanea el lado opuesto a la pared*/
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() {
/*
En este método el robot escanea todo a su alrededor*/
if(++scan > 360) scan = 0;
fire();
}
private void fire() {
locX[id] = loc_x();
locY[id] = loc_y();
/*
El robot actualiza su posición*/
int range;
if((range = scan(scan,1)) > 40 && range <= 740) {
/*
El radar detecta un robot en una rango de distancia conveniente
*/
if (count > 1) {
/*
El robot no está solo (tiene amigos)*/
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++) {
/*
Es el robot encontrado un enemigo?*/
if(ct != id) {
int dx = shotX-locX[ct];
int dy = shotY-locY[ct];
if(dx*dx+dy*dy < 1600) {
shot = false;
break;
}
}
}
if(shot) {
/*
Es un enemigo! Dispara e informa a sus amigos sobre el enemigo encontrado*/
targetX = shotX;
targetY = shotY;
cannon(scan,range);
scan -= 10;
/*
Gira el radar un poco hacia atrás*/
} else {
/*
Es un amigo! Disparar al último enemigo encontrado en su lugar*/
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 {
/*
El robot está solo. Disparar sin preocupación.*/
cannon(scan,range);
scan -= 10;
}
}
}
}
Puedes encontrar el código fuente de Platoon en la
página de downloads.
Por preguntas o comentarios, envía un email.
Jrobot: Phalanx
y Stinger - Autor: Leonardo
Boselli
Platoon funciona bien en el modo por equipos (Team), pero
algunos robots con buenas técnicas de detección le ganan fácilmente en los
modos Single y Double, porque sus movimientos son fácilmente previsibles.
Para mejorar el comportamiento de
Platoon, he escrito Phalanx y Stinger.
Los mejores robots usan el seguimiento de la velocidad del enemigo para
aumentar el daño causado por sus misiles. Esta técnica es útil cuando el
enemigo usa una velocidad constante, y facilita la estimación de la
ubicación del enemigo al final del vuelo del misil. Si el robot se mueve
hacia atrás y hacia adelante, los enemigos más inteligentes son
confundidos, pero los menos inteligentes tiene suerte, ya que sus disparos
no predictivos, pueden tener suerte e impactar al robot en los cambios de
dirección. Una mejor solución es seguir una ruta en zigzag como lo hace Phalanx.
Stinger usa la misma técnica de disparo de Phalanx, pero
tiene algoritmos de movimientos diferentes. Busca el enemigo más cercano y
lo sigue como una sombra. Cuando está realmente cerca (menos de 40 metros)
dispara misiles a una distancia de 45 metros, de tal manera de dañar al
enemigo sin dañarse a si mismo.
Ahora Phalanx combina las 5
principales técnicas de los robots más desarrollados. Las reglas que sigue
son:
- No disparar a los amigos: aplica a los modos Double y Team
- Mantener alta velocidad y cambiar de dirección rápidamente:
esto evita misiles disparados al lugar del escaneo
- Seguir una ruta
en zigzag: esto evita misiles disparados por robots más inteligentes
-
Correr en grupos para acumular poder de disparo: un excelente valor
en el modo Team
- Calcular tiempo de vuelo de los misiles y estimar correctamente
la posición futura del enemigo: bueno si deseas golpear duro a
alguien
Stinger cambia las reglas 3 y 4 por:
- Seguir al enemigo más cercano muy de cerca: esto confunde al
enemigo
- Dispara hacia el enemigo evitando daños propios: bueno
si la distancia es menor que 40 metros
Puedes encontrar el código fuente de Phalanx y Stinger en
la página de downloads.
Por preguntas o comentarios, envía un email.