Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Tutorial em Espanhoç PDF
Tutorial em Espanhoç PDF
ROBOCODE
En Robocode hay dos elementos principales, los robots y los combates. Los
combates se llevan a cabo en el campo de batalla, entre los robots, que juegan por sí
mismos. En cuanto a los robots, un robot Robocode típico tendrá el siguiente aspecto:
Al ser el objetivo del juego derrotar a los otros robots, Robocode contará
también con multitud de métodos para gestionar los disparos y los ataques a nuestros
enemigos.
Al principio de cada combate todo robot comienza con un nivel de energía por
defecto, y se considera destruido el robot cuando su nivel de energía cae hasta cero,
existiendo varias situaciones en la que la energía de un robot puede disminuir, como son
que te alcance un disparo enemigo, que te choques con un enemigo, que te choques
contra una pared, además de por la energía liberada en el disparo (cuanta más energía se
imprima a un disparo más daño inflingirá en el robot enemigo en caso de alcanzarlo
pero también más nos restará a nosotros), por ejemplo. Pero no todo son pérdidas de
energía, también se recupera energía cuando se alcanza a algún enemigo o de forma
constante por “enfriamiento de los cañones”.
A la hora de programar uno de estos robots tendremos que tener en cuenta cuatro
áreas fundamentales del código:
- el propio método run(), que es llamado por el gestor de combate para comenzar
la vida del robot y típicamente se divide en dos áreas: un en la que se definen las
cosas que sólo se harán una vez por cada instancia del robot, y una segunda parte
dentro de un while infinito en la que se define la acción repetitiva en la que se
verá envuelto el robot.
- Métodos auxiliares para usar por el robot dentro de su método run. En esta
zona también se ponen los manejadores de eventos que se quieran implementar.
Arquitectura Robocode:
Cuándo disparar
Con qué potencia
Dónde apuntar
A qué distancia colocarme
Cómo nos movemos
Para ello nuestro robot irá almacenando ciertos valores que le harán falta para
optimizar la elección de las incóginitas anteriores. Para ello almacenaremos las
variables más actuales:
También almacenaremos algunos valores del anterior “escaneo” del robot, esto
es;
La posición anterior de nuestro robot (Point2D posicionAnt )
La posición anterior del robot enemigo (Point2D posicionEnemigoAnt )
Estos valores se actualizan cada vez que detecta un robot, esto es, en el método
onScannedRobot.
donde:
Esta función devolverá la media alterada por el nuevo valor de manera que
“simula” guardar una lista con todas las lecturas con longitud n y devolviendo la media
de los valores de esta lista. Hay que tener en cuenta que los valores antiguos nunca son
olvidados, simplemente juegan un menor papel en el cálculo de la media actual.
Todas las variables anteriores serán estáticas ya que almacenaremos los valores
de una ronda a otra.
Existen varias condiciones que podemos tener en cuenta a la hora de disparar. Las
primeras que tenemos en cuenta son:
Esto es, que cuando mi energía sea menor que 0.2 sólo disparará si mi distancia
al enemigo es menor de 100, así aseguramos que cuando estamos apunto de morir si
disparamos, tener mayor probabilidad de acertar.
Para gestionar esto utilizaremos la posibilidad que nos dan los AdvancedRobot
de utilizar condiciones. Para ello añadimos un evento propio mediante addCustomEvent
pasándole como parámetro una nueva condición donde su función test() controle estas
condiciones. Cuando esta función test() devuelva true (esto es, todas las condiciones se
han cumplido) se lanzará un CustomEvent y ejecutará el método onCustomEvent, que
disparará setFireBullet con la potencia estimada (explicado a continuación).
Conservar la energía de nuestro robot es una buena manera de sobrevivir en una batalla.
Hay muchas formas de conseguir esto, por ejemplo:
Escoger la correcta potencia de los misiles a disparar es una estrategia muy importante.
Podemos minimizar:
Pero… ¿para una distancia dada cómo modelamos la potencia con la que
disparar? Consideramos la máxima distancia entre los dos robots que será
cuando cada uno esté en una esquina del campo en la diagonal mayor. Tomamos
como una distancia de referencia la mitad de esta distancia máxima, por lo que
la máxima potencia con la que deberíamos disparar estaría promediada por:
(Dmax/2) / Distancia al enemigo.
La distancia a la que esté del robot enemigo determinará en gran medida los
resultados de la batalla. Si nos colocamos muy lejos conseguiremos que nuestro
enemigo falle más si nos movemos deprisa, pero también nosotros fallaremos más, por
lo que procuraremos no disparar si estamos muy lejos. La distancia óptima a la que
situarnos dependerá del robot adversario contra el que nos enfrentemos, por lo que la
calculamos dinámicamente. Como tomamos valores de las energías ganadas y perdidas
de ambos robots para una serie de distancias podemos definir una función de ventaja
para cada punto donde definimos. Entonces para una de las distancias muestreadas
promediamos la ventaja que obtenemos a partir de una relación entre nuestro beneficio
(la energía que gano y la energía que pierde el otro) y nuestra penalización (la energía
que perdemos y la que gana el otro). Esta relación tomara valor máximo 1 cuando no
obtengamos nada de penalización, el valor -1 cuando no obtengamos nada de beneficio
y 0 cuando obtengamos el mismo beneficio que penalización.
Por ello para calcular la distancia óptima a la que colocarme será evaluando la
ventaja obtenida para cada una de las distancias.
¿Dónde apuntar?
Así, para cada cañón virtual disponemos de un ángulo donde se estima que se
suele encontrar el robot adversario cuando se mueve en esa dirección. Por lo que a la
hora de apuntar nuestro cañón, lo primero es elegir el cañón virtual correspondiente en
función del ángulo movido:
cañon virtual Izquierdo si anguloMovimiento < - 0.3
cañon virtual Derecho si anguloMovimiento > 0.3
cañon virtual Central si anguloMovimiento está en (-0.3,0.3)
Pero justamente para poder probar nuestro robot generamos varios casos para
ver como reaccionaba éste. Observamos que para un robot que cambiara constantemente
de sentido, nuestro IRCeitor era poco eficiente. Para probarlo generamos el IRCBot, un
robot con estrategia diferente al IRCeitor, capaz de ganarle la mayoría de veces. Su
estrategia la explicaremos mostrando los comentarios en el código que adjuntamos:
package ircPackage;
import robocode.*;
import java.awt.Color;
import java.util.Enumeration;
import java.util.Hashtable;
/*
* IRCBot.java
* El movimiento de este robot impide que se choque contra los muros, de
* manera que no pierde energía en ese sentido.
* Asimismo evita las balas y los enemigos. Todo ello es posible gracias a la
* "Evasion", para la que hay implementada una clase. Dependiendo del tipo de
* evasion en el que nos encontremos en cada momento(que depende de
* los eventos y situaciones que se van dando en el juego) así será el
* movimiento del robot.
*
* Los potencia de los disparos se lleva a cabo de manera aleatoria pero
* siempre a partir de nuestra energía y de la distancia a la que se
* encuentre el enemigo al que pretendemos disparar.
*
* Targeting: si no tenemos ya fijado un enemigo, se fija como enemigo el
* primero que detecte nuestro radar y otra serie de factores. se calculará de
* manera ciertamente aleatoria la orientación del cañón para el disparo,
* pero teniendo en cuenta el movimiento de dicho oponente, para así poder
* adelantarnos a él y darle de lleno.
*
*/
/*
* En este método se implementarán las operaciones que tiene que hacer el
* robot una vez por instancia (parte de código fuera del do-while)
* y las operaciones que se realizarán en cada turno del robot
* (parte de código contenida dentro del do-while).
*/
public void run(){
inicializacion();
//Del disparo se encargará el método onScannedRobot, aqui lo unico que
//hacemos es definir el movimiento en caso de que queden más robots
// o marcarnos un bailecito en caso de que no queden más robots,
// es decir, que hayamos ganado.
do{
if(getOthers() > 0)
mover();
else
bailecito();
execute();
} while(true);
}
/*
* Constructor de IRCBot donde se inicializan algunos de sus atributos:
*/
public IRCBot(){
target = null;
/*Inicializamos un objeto de tipo Evasor, que nos gestionará la evasión
de las situaciones de peligro.*/
evasor = new Evasor();
dir = 1;
/*
* Método para inicializar el modo de operacion del robot
*/
public void inicializacion(){
setColors(Color.yellow, Color.blue, Color.black);
//Hacemos que tanto el cañón como el radar giren de manera independiente
al robot:
setAdjustGunForRobotTurn(true);
setAdjustRadarForGunTurn(true);
//Y hacemos un scaneo inicial
setTurnRadarRight(360);
}
/*
* El movimiento de este robot funciona de la siguiente manera:
* En primer lugar hacemos un movimiento dependiendo del tipo de evasion en
* la que nos encontremos.
* En segundo lugar tratamos de evitar los muros
* Y también atendemos al caso en el que estemos solos contra otro robot.
*/
public void mover(){
//No haremos nada hasta que fijemos un objetivo:
if(target == null)
return;
//No nos vamos a chocar con los muros, ya que cuando estemos a menos
//de una cierta distancia de estos daremos media vuelta.
if(N < 70 && getHeading() > 270 && getHeading() < 360)
dir = -1;
else
if(N < 70 && getHeading() > 0.0 && getHeading() < 90)
dir = -1;
else
//Aquí estamos en el caso de que estemos en zona próxima al muro
// norte pero nuestro sentido de avance es tal que nos aleja de
//este peligro.
if(N < 70)
dir = 1;
if(E < 70 && getHeading() > 0.0 && getHeading() < 180)
dir = -1;
else
if(E < 70)
dir = 1;
if(W < 70 && getHeading() > 180 && getHeading() < 360)
dir = -1;
else
if(W < 70)
dir = 1;
if(Evasor.tipoEvasion == 6){
case 1:
mov1();
break;
case 2:
mov2();
break;
case 3:
mov3();
break;
case 4:
mov1();
mov2();
mov3();
break;
default:
mov1();
}
}
}
/*
* Movimiento que seguimos cuando tenemos más de un robot acechándonos:
*/
public void circleGrav() {
double orientacion = 10000;
double closest = 10000;
if(getOthers() >= 4)
orientacion += orientacionChoque;
setAhead(dir * 100);
setTurnRight(NormalRelativeAngle(orientacion));
}
/*
* A partir de aqui definimos tres tipos de movimiento distintos para
* cuando solo quede otro robot, para ser más efectivos en ese caso.
* Con esto lo que hacemos es que al adversario que está contra nosotros
* le resulte muy complicado preveernos
*/
/*
* En este primer movimiento, si ya se ha acabado el movimiento
* anteriormente definido,cambiamos el sentido y angulo de nuestro
* movimiento, así como el tiempo que va a durar este.
*/
public void mov1(){
if((double)getTime() - evasor.movetime > evasor.time){
dir *= -1;
evasor.movetime = getTime();
evasor.ang = Math.random() * 25;
evasor.time = Math.random() * 7 + 15;
}
setAhead(dir * 50);
}
/*
* Definimos otro movimiento de manera completamente distinta:
* Utilizando incluso un subtipo del evasor.
*/
public void mov2(){
if(target.getDistance() < 400)
evasor.time = Math.min(target.getDistance() / 12, 24);
else
evasor.time = 28;
/*
* Cuando nuestro robot muere ahí no se queda la cosa,
* aprende un poco y pone el estado en el que ha de comenzar el evasor
* en la siguiente ronda.
*/
public void onDeath(DeathEvent e){
switch(Evasor.tipoEvasion){
case 1:
Evasor.tipoEvasion = 2;
break;
case 2:
Evasor.tipoEvasion = (int)(Math.random()*3.9900000000000002)+3;
break;
default:
Evasor.tipoEvasion = 1;
}
/*
* En este método se implementan las acciones a realizar cuando nos alcance
* una bala enemiga
*/
public void onHitByBullet(HitByBulletEvent e){
if(Evasor.tipoEvasion == 5){
Evasor.tipoEvasion++;
/*
* Este método se ejecuta cuando muere uno de los robots de la batalla,
* evento que es recogido por RobotDeathEvent.
* De entre los robots que teníamos como posibles objetivos, pasamos a
* considerar como muerto al robot que acaba de morir, y si dicho robot
* coincidía con el objetivo actual, a través de decir que lastsighted es
* cero dejará de ser nuestro objetivo.
*/
public void onRobotDeath(RobotDeathEvent e){
Enemigo en = (Enemigo)targets.get(e.getName());
en.estaVivo = false;
targets.put(e.getName(), en);
if(e.getName() == target.getName())
lastsighted = 0.0;
}
/*
* En este método se implememtan aquellas acciones que hay que realizar
* cuando al paso del scanner se detecta la presencia de un robot, no
* detectado antes o sí
*/
public void onScannedRobot(ScannedRobotEvent e){
Enemigo en;
if(Evasor.tipoEvasion == 3){
energy -= e.getEnergy();
if(energy <= (double)3 && energy > 0.0)
setAhead((double)dir * evasor.ahead);
energy = e.getEnergy();
}
/*
Si se cumple una o más de estas cosas:
- Actualmente no tenemos objetivo(porque se haya muerto el que teníamos p ej)
- El objetivo es el mismo que acabamos de detectar
- El robot recién detectado está mucho más cerca del que tenemos fijado como
enemigo prioritario
- Hace más de ocho ticks que no vemos un robot
entonces vamos a por el.
*/
if(target == null || e.getName() == target.getName() ||
e.getDistance() < target.getDistance() - 50 || (double)getTime() - lastsighted
> 8){
target = e;
lastsighted = getTime();
//comienza a contar de nuevo el tiempo desde el que vimos al ultimo enemigo.
double abs_orientacion = e.getBearingRadians() +
getHeadingRadians();
setTurnRadarRightRadians(Math.asin(Math.sin(abs_orientacion -
getRadarHeadingRadians())));
setFire(firepower);
}
mover();
}
/*
* Movimientos para celebrar la victoria:
*/
public void bailecito(){
setTurnLeft(36000);
setTurnGunRight(36000);
setAhead(50);
setBack(50);
}
/*
* Método para que todos los ángulos que utilicemos estén entre -180 y 180
* grados.
*/
public double NormalRelativeAngle(double angle){
Un Droid no tiene radar y por tanto no puede hacer un escaneo. Sin embargo,
todo Droid tiene 20 puntos extra de vida respecto a aquellos robots que no son Droid.
De esta manera, cada uno de los robots será capaz de determinar donde están sus
enemigos (lo que servirá para moverse de manera inteligente), cuál es el enemigo más
débil y dónde están sus compañeros. A todo esto le añadiremos una cierta coordinación
entre los miembros del equipo que hará que su táctica de combate sea más eficaz.
Para evitar el choque con miembros de nuestra cuadrilla hay dos fragmentos de
código dedicados a ello, el primero de ellos se encuentra en la función onScannedRobot,
en la que al detectar otro robot, comprobamos si es un compañero, en cuyo caso
calculamos la distancia a la que se encuentra de nosotros y si dicha distancia supone un
riesgo de colisión inminente giramos nuestro sentido de avance para evitar ese choque.
La segunda medida tomada al respecto se encuentra en el método onHitRobot, que se
ejecuta cuando se produce un onHitRobotEvent, es decir, cuando ya nos hemos chocado
contra otro robot. Esta situación puede producirse ya que el movimiento de un robot
está sujeto a varios factores y puede que estos lleven a una colisión antes de que
podamos detectar su posibilidad y evitarlo. En este caso, lo que se hace es generar un
movimiento aleatorio, de manera que lo más probable sea que cada robot, al calcularlo
por separado, lo haga de una manera distinta, y así al detectar los dos robots el choque
contra un compañero, los dos calculan por separado un movimiento aleatorio, que al
llevarlo a cabo lo más probable es que les aleje.
Como apunte, decir que en este método onHitRobot hay dos posibilidades, que
el robot contra el que chocamos sea amigo o sea enemigo, el primer caso ya lo hemos
explicado, mientras que en el segundo estamos ante una estupenda oportunidad de
disparar con todas nuestras fuerzas al enemigo, que al estar pegado a nosotros recibiría
un gran impacto. Mientras tanto nosotros también estamos perdiendo energía al estar en
contacto con él, pero al estarle disparando con la máxima potencia, recuperaremos parte
de esa energía y lo más probable es que aniquilemos a ese enemigo a costa de descender
un poco nuestra energía vital.
Al haber elegido la opción de implementar equipos en los que todos los robots
tienen bastante autonomía guardando cierta coordinación para ser más letales, cada uno
de los robots estará continuamente escaneando en busca de nuevos enemigos o en busca
de actualizar la información sobre los ya existentes.
Vemos como todos los robots del grupo contribuyen de esta manera a que la
tabla de enemigos esté siempre actualizada con las últimas posiciones y parámetros de
los mismos. Este comportamiento colectivo se traduce un control exhaustivo de los
enemigos para un ataque más eficaz.
Finalmente, pueden ocurrir dos cosas, o que el robot muera y termine muriendo
el equipo entero o que salgamos victoriosos. En el primero de los casos, se transmitirá
algo de información a la siguiente ronda, que en realidad es más bien un cambio
aleatorio en ciertos parámetros del movimiento para ser menos predecibles. En el
segundo de los casos se invocará nuestro método “bailecito()” en el que haremos una
serie de movimientos indicando nuestra alegría por la victoria.
Código de IRCTeamBot:
package ircPackage;
import robocode.*;
import java.awt.Color;
import java.util.*;
import java.io.*;
/**
* IRCTeamBot: Robot que extiende de TeamRobot y que por tanto está
* implementado con la intención de que pertenezca a un grupo de ataque de
* robots de la misma clase.
*/
public class IRCTeamBot extends TeamRobot{
double tiempoChoque;
double orientacionChoque;
double ultimaVezVisto;
inicializacion();
do{
if(getOthers() > numAmigosVivos){
setTurnRadarRight(360);
mover();
}
else
bailecito();
execute();
} while(true);
}
public IRCTeamBot(){
target = null;
targets = new Hashtable();
/*
* En primer lugar hacemos un movimiento dependiendo del tipo de evasion
* en la que nos encontremos
* En segundo lugar tratamos de evitar los muros
* Y también atendemos al caso en el que estemos solos contra otro robot.
*/
//No nos vamos a chocar con los muros, ya que cuando estemos a menos
de una cierta distancia de estos daremos media vuelta.
if(N < 70 && getHeading() > 270 && getHeading() < 360)
dir = -1;
else
if(N < 70 && getHeading() > 0.0 && getHeading() < 90)
dir = -1;
else
//Aquí estamos en el caso de que estemos en zona próxima al muro
norte pero nuestro sentido de avance es tal que nos aleja de este peligro.
if(N < 70)
dir = 1;
if(E < 70 && getHeading() > 0.0 && getHeading() < 180)
dir = -1;
else
if(E < 70)
dir = 1;
if(W < 70 && getHeading() > 180 && getHeading() < 360)
dir = -1;
else
if(W < 70)
dir = 1;
//Si estamos en las zonas de peligro:
if(N < 70 || S < 70 || E < 70 || W < 70){
evasor.movetime = getTime();
evasor.sub_tipoEvasion = 1;
orientacionChoque = -dir * 10 - 90;
tiempoChoque = getTime();
}
else{
orientacionChoque = 0.0;
}
Enemigo en = (Enemigo)e.nextElement();
//Calculamos nuestra orientacion de giro en funcion del enemigo
mas cercano:
if((en.estaVivo = true) && en.distancia < closest) {
closest = en.distancia;
setAhead(dir * 100);
//Metemos esa aleatoriedad en el giro porque sino miembros del mismo
equipo tienden a agruparse:
setTurnRight(NormalRelativeAngle(orientacion + Math.random()*20));
}
switch(Evasor.tipoEvasion){
case 1:
Evasor.tipoEvasion = 2;
break;
case 2:
Evasor.tipoEvasion=(int)(Math.random()*3.9900000000000002) + 3;
break;
default:
Evasor.tipoEvasion = 1;
}
}
if(!isTeammate(nombreFallecido)){
Enemigo en = (Enemigo)targets.get(nombreFallecido);
if(target.getName().equals(nombreFallecido))
ultimaVezVisto = 0.0;
targets.remove(nombreFallecido);
}
else
numAmigosVivos--;
}
/*
* Si chocamos con un robot de nuestro propio equipo nos movemos de
* inmediato con un movimiento aleatorio, de manera que si el otro
* también detecta que se ha chocado con nosotros se moverá, pero al ser
* aleatorio lo más probable es que lo haga de otra forma y así podamos
* separarnos.
*/
if(isTeammate(e.getName())){
double tpRnd = Math.random() * 10;
int rndInt = (int) Math.ceil(tpRnd);
tpRnd = tpRnd % 3;
switch (rndInt) {
case 0: turnLeft(90-e.getBearing());
back(100);
break;
case 1: turnRight(90-e.getBearing());
ahead(100);
break;
case 2: turnLeft(90);
back(200);
}
}
else{
setTurnGunRightRadians(Math.asin(Math.sin(e.getBearingRadians() +
getHeadingRadians() - getGunHeadingRadians())));
setFire(3);//Si nos chocamos con un enemigo le freimos
}
}
Enemigo en;
double abs_orientacion = e.getBearing() + getHeading();
double enemyX = getX() + e.getDistance() *
Math.sin(Math.toRadians(abs_orientacion));
double enemyY = getY() + e.getDistance() *
Math.cos(Math.toRadians(abs_orientacion));
double dx = enemyX - getX();
double dy = enemyY - getY();
if(!isTeammate(e.getName())){
if(target==null || e.getName().equals(target.getName()) ||
e.getDistance() < target.getDistance() - 50 || (double)getTime() -
ultimaVezVisto > 8){
target = e;
ultimaVezVisto = getTime();
//comienza a contar de nuevo el tiempo desde el que vimos al
ultimo enemigo.
double theta = Math.toDegrees(Math.atan2(dx,dy));
setTurnRadarRight(NormalRelativeAngle(abs_orientacion -
getRadarHeading()));
setFire(firepower);
}
}//Fin del if isTeammate
else{
//Si nos estamos acercando mucho a un compañero cambiamos de
direccion:
double distanciaComp = e.getDistance();
if(distanciaComp<100){
setTurnLeft(90-e.getBearing());
}
//y vamos en busca de charlies
setTurnRadarRight(360);
}
mover();
}
public void bailecito(){
setTurnLeft(36000);
setTurnGunRight(36000);
setAhead(50);
setBack(50);
}
Teamy:
En busca de un mejor robot de grupo también se ha implementado este otro
robot de simpático nombre. Su funcionamiento y manera de hacer las cosas es diferente
al anterior y éste no es ninguna derivación / adaptación de ningún otro robot.
En primer lugar vemos que, al igual que en el IRCTeamBot, contamos con una
Hashtable enemigos donde se almacenan los enemigos que los robots de nuestro equipo
van captando, también aquí es estática para que todos los miembros del grupo vean y
consideren a los mismos enemigos.
Aquí también contamos con un objeto de tipo Evasor, pues dado el buen
resultado en el movimiento del anterior robot implementado hemos decidido que era
una buena opción mantener esta funcionalidad.
que nos servirá para afinar nuestros disparos, para calcular nuestros movimientos en
función de los enemigos...
La ejecución de nuestro robot será más sencilla y ordenada que en el caso del
robot anterior, ya que en cada iteración del método run() lo que se hará será
sencillamente invocar una función operación(), en la que dependiendo del estado de la
máquina de estados en el que nos encontremos invocará unas funciones u otras, ara una
vez hecho esto, invocar al método que se encarga de nuestro movimiento, todo ello
realizado de forma “paralela” debido a la utilización de métodos de tipo setXXX que
permiten la realización de múltiples tareas no bloqueantes las unas con las otras, todas
ejecutadas al llamar a la función execute(), hecho que se da nada más regresar de la
función operación() (método run()).
La máquina de estados sobre la que funciona este robot tiene cuatro estados:
INICIO:
Estado en el que comienza la ejecución del robot y al que no volverá hasta una
nueva llamada al método run() del robot. En este estado se determina el número de
compañeros que hay luchando a nuestro lado, se establece la velocidad del robot y se da
paso al segundo estado, el de búsqueda de objetivos.
TARGETING:
Dado que en este estado lo que se pretende es adquirir objetivos, lo que se hará
aquí será básicamente generar giros completos del radar, para que cuando se detecte
algún robot, el método onScannedRobot haga el resto.
FIRING:
Este es el estado en el que se lleva el cálculo del ángulo con el que disparar, la
dirección y la fuerza del disparo, así como el disparo en sí.
Se distingue el caso en el que la velocidad del enemigo sea nula (puede que se
haya quedado atascado en una esquina, es carne de cañón) en cuyo caso apuntamos
hacia él directamente sin ningún tipo de cálculo previo, del caso en el que el enemigo se
está moviendo, caso en el que intervienen una serie de cálculos e iteraciones de
optimización de los parámetros implicados.
CELEBRATING:
Este es el estado al que se desea ganar en toda partida, aquel en el que todos los
enemigos han sido derrotados y hacemos nuestro baile de la victoria. A este estado se
llega cuando ha muerto un robot (RobotDeathEvent) y se ha comprobado que sólo
quedan robots aliados (en onRobotDeath).
Código de Teamy:
package ircteam;
import robocode.*;
import java.util.*;
import java.awt.Color;
/*****************************************************************************
* Teamy:robot implementado por Jorge Carrasco y Elisabeth Pérez
*
*Este robot utiliza una máquina de estados y esta implementado para funcionar
*dentro de un equipo de robots de la misma indole.
****************************************************************************/
double tiempoChoque;
double orientacionChoque;
dir = 1;
enemigos = new Hashtable();
evasor = new Evasor();
enemigoActual = null;
estadoActual = INICIO;
}
switch(estadoActual){
case INICIO:
if(getTeammates()==null) numAmigosVivos = 0;
else numAmigosVivos = getTeammates().length;
setMaxVelocity(Math.random() + 7);
estadoActual = TARGETING;
break;
case TARGETING:
setTurnRadarRight(360);
break;
case FIRING:
setTurnRadarRight(360);
disparar();
break;
case CELEBRATING:
bailecito();
return;
}
mover();
}
if(enemigoActual==null){
estadoActual = TARGETING;
return;
}
if(N < 70 && getHeading() > 270 && getHeading() < 360)
dir = -1;
else
if(N < 70 && getHeading() > 0.0 && getHeading() < 90)
dir = -1;
else
//Aquí estamos en el caso de que estemos en zona próxima al muro
norte pero nuestro sentido de avance es tal que nos aleja de este peligro.
if(N < 70)
dir = 1;
if(E < 70 && getHeading() > 0.0 && getHeading() < 180)
dir = -1;
else
if(E < 70)
dir = 1;
if(W < 70 && getHeading() > 180 && getHeading() < 360)
dir = -1;
else
if(W < 70)
dir = 1;
Enemigo en = (Enemigo)e.nextElement();
distancia = enemyParameters[0];
orientacionEnemiga = Math.toDegrees(enemyParameters[1]);
setAhead(dir * 100);
setTurnRight(NormalRelativeAngle(orientacion)+ Math.random()*20);
}
if(enemyParameters[3]==0){
//Calculamos el angulo a girar para apuntar al enemigo
double theta = Math.toDegrees(Math.atan2(posicion[0]-
getX(),posicion[1]-getY()));
//Apuntamos
setTurnGunRight(NormalRelativeAngle(theta - getGunHeading()));
}
else{
do {
if (count != 0)
hit_time = actual_time;
count++;
x = enemyParameters[0] * Math.sin(enemyParameters[1]);
y = enemyParameters[0] * Math.cos(enemyParameters[1]);
setFire(firepower);
}
if(isTeammate(nombreDetectado)){
if(enemigos.containsKey(nombreDetectado)){
enemigoDetectado = (Enemigo)enemigos.get(nombreDetectado);
enemigoDetectado.posX = X;
enemigoDetectado.posY = Y;
enemigoDetectado.energia = e.getEnergy();
}
else{
enemigoDetectado=new Enemigo(nombreDetectado,X,Y,e.getEnergy());
}
enemigos.put(nombreDetectado, enemigoDetectado);
if(getOthers()-numAmigosVivos == 0){
estadoActual = CELEBRATING;
operacion();
}
}
/**
* onHitByBullet: Turn perpendicular to the bullet
*/
// Evasive action
setTurnLeft(90 - e.getBearing());
Evasor.tipoEvasion++;
}
switch(Evasor.tipoEvasion){
case 1:
Evasor.tipoEvasion = 2;
break;
case 2:
Evasor.tipoEvasion =(int)(Math.random()*3.9900000000000002)+ 3;
break;
default:
Evasor.tipoEvasion = 1;
}
}
if(isTeammate(e.getName())){
double tpRnd = Math.random() * 10;
int rndInt = (int) Math.ceil(tpRnd);
tpRnd = tpRnd % 3;
switch (rndInt) {
case 0: turnLeft(90-e.getBearing());
back(100);
break;
case 1: turnRight(90-e.getBearing());
ahead(100);
break;
case 2: turnLeft(90);
back(200);
}
}
else{
double bearingFromGun=
NormalRelativeAngle(getHeading()+e.getBearing()-getGunHeading());
turnGunRight(bearingFromGun);
setFire(Math.min(3-Math.abs(bearingFromGun),getEnergy()-.1));
//Si nos chocamos con un enemigo le freimos
}
}
setTurnLeft(36000);
setTurnGunRight(36000);
setAhead(50);
setBack(50);
}
return Math.sqrt(Math.pow(x2-x1,2)+Math.pow(y2-y1,2));
}
}
RESULTADOS:
Como comentario final decir que hemos puesto a luchar a los dos equipos para
evaluar sus prestaciones uno contra el otro y estos han sido los resultados
proporcionados por robocode:
REFERENCIAS:
RoboHome
http://robowiki.net/cgi-bin/robowiki
Robocode FAQ :
http://robocode.alphaworks.ibm.com/help/robocode.faq.txt
Robocode API
http://robocode.alphaworks.ibm.com/docs/robocode/index.html