Sunteți pe pagina 1din 17

Inteligencia en Redes de Comunicaciones

ROBOCODE

David de Miguel Medina 100029556 Pablo Andreu barasoain 100027455

INDICE
Pag.

Introduccin ..

El Campo de juego y los robots . 4 Estrategia. 6 Como movernos?.................................................................... . 6 Cuando, como y con que potencia disparar?........................... 7 Como localizar a nuestro enemigo?.......................................... 8 Cdigo 9 Conclusiones16 Bicliografia. 17

-2-

Introduccin
Robocode es un simulador de combate donde tanques programados en Java luchan en un escenario preparado para ello, siendo el vencedor aquel que quede vivo. Este proyecto fue creado por Mathew Nelson, ingeniero de IBM, en un intento de convencer a la comunidad de que Java est preparado para ser utilizado en juegos y adems, ser una metodologa adictiva de aprendizaje del lenguaje. Se trata de un juego en el que se puede aprender dicho lenguaje y el manejo de los eventos de java programando tu propio robot mediante el propio lenguaje y mtodos de java. Ayudndote de los mtodos que se te proporcionan en el API especfico para Robocode, el cual te permite ejecutar el programa y tu robot en cualquier sistema o PC, puedes implementar o sobrescribir mtodos de dicho API para conseguir un robot ms eficiente. Este API, parte de la clase Robot, Bullet, Condition y Event y se apoya en algunas otras clases de java como java.io.OutputStream y java.io.Writer. Adems, el API cuenta con una interfaz llamada Droid. En Robocode el programador debe de encargarse de elegir la mejor estrategia para su robot e implementarla mediante desplazamientos, giros, controlando el radar y can del robot as como hacindole disparar cuando considere apropiado. Tambin tiene que controlar los eventos que se producen mientras combate (impacto contra un muro, de una bala.) Todas las batallas entre robots constan de uno o varios combates, en los cuales los robots parten de una posicin inicial aleatoria y tienen que luchar entre ellos tanto individualmente como por equipos. El objetivo principal del juego es obtener ms puntos que los robots contrarios al final de la batalla, par ello se debe destruir al robot contrincante aunque tambin se pueden obtener puntos por diversas actuaciones. Hay dos tipos de combates: los combates individuales, y los combates en equipos, en el cual, un conjunto de robot luchan contra otro para conseguir la destruccin del equipo entero contrario. Dentro de los combates individuales, hay dos modalidades, una consistente en un todos contra todos en el cual solo debe quedar uno o los combates one2one, es decir uno contra otro, en los cuales combaten nicamente dos robots. Nosotros nos centraremos en este tipo de combates.

-3-

El Campo de juego y los robots


Los combates se realizan en superficies rectangulares que oscilan entre las dimensiones de 400x400 hasta 5000x5000 y por las cuales el robot tiene total libertad para moverse y localizar a los robots contrarios. Para ello, el robot consta de tres partes bsicas diferenciadas: el propio chasis del robot, el escner y el can, los cuales se pueden mover conjunta o separadamente en funcin de la estrategia seguida por el jugador. Todos los movimientos que se le ordenen al tanque, debern ir encaminados a mover el chasis, mientras que con el escner, este podr localizar a los enemigos para apuntarlos con el can, con el cual disparara. Los robots heredan de la clase Robot por defecto, aunque tambin pueden heredar de AdvancedRobot o TeamRobot. Las principales diferencias son que la clase Robot dispone nicamente de los mtodos bsicos para la implementacin del tanque. AdvancedRobot hereda a su vez de la clase Robot y permite, adems de todas las funciones bsicas, otras ms avanzadas que nos facilitaran el desarrollo de nuestro robot, as como el acceso a mtodos mas eficientes y variados para controlarlo. Por ltimo la clase TeamRobot hereda de AdvancedRobot y permite el intercambio de mensajes entre robots de un mismo equipo. Los robots que heredan de esta clase, suelen ser aquellos que compiten por equipos y que necesitan un paso de mensajes par comunicarse entre ellos. Cualquiera puede crear nuevas subclases de Robot y aadir nuevas funcionalidades que pueden ser usadas para construir robots. Como se acaba de explicar, Robocode proporciona una subclase a Robot: AdvancedRobot, que permite realizar las llamadas del API de manera asncrona, es decir, cambiar las acciones asociadas al robot en cada turno (los mtodos son bsicamente los mismos, aadiendo set delante de sus nombres). Esto nos vendr muy bien ya que podremos realizar diversos movimientos a la vez, decidir qu hacer en cada turno y tener acceso a la creacin y gestin de eventos creados por nosotros mismos. Al principio del combate, todos los robot parten de una energa inicial de 100, dicha energa se ira reduciendo en funcin de los impactos que reciba as como de los disparos perdidos que realice, de igual modo, si el robot consigue que sus balas impacten en el contrincante, su energa aumentara en la misma proporcin que la del enemigo disminuya. Tambin disminuyen la energa el hecho de impactar contra un muro del terreno de juego o contra otro robot. Cuando su energa sea cero, el robot entrara en un estado llamado disable, en el cual permanece quieto y no puede realizar ninguna accin, siendo destruido en el caso de que alguna bala impacte contra el. Debido a esto ultimo, se pueden implementar muchas estrategias, pero todas estarn basadas en acertar los mximos disparos en el tanque enemigo mientras que nuestro robot no reciba ningn disparo ni choque contra las paredes o enemigos.

Como se ha comentado anteriormente, al principio del combate, todas las partes de las que se compone el tanque estn alineadas y forman una unidad, es decir, cuando un tanque

-4-

gira, el can y el radar harn el mismo movimiento a no ser que se le indique lo contrario. Esto viene del hecho de que el can est montado sobe el cuerpo y el radar sobre el can. Debido a esto, si giro el chasis de nuestro tanque para en una direccin en concreto, tanto el can como el radar, giraran tambin hacia esa direccin en concreto. Si giro el can, el cuerpo no se mueve, pero si lo hace el radar. Y por ltimo, si muevo el radar, no se mueve nada ms.

-5-

Estrategia
A la hora de elegir una estrategia en concreto para nuestro robot, se vio que tenamos que concretar estrategias para diversos puntos, en concreto: Como movernos Cuando, como y con que potencia disparar. Como localizar a nuestro enemigo

Tras consultar diversas paginas y tutoriales de Internet y realizar simulaciones de los robots bsicos que se adjuntaban con el Robocode, decidimos que la mejor estrategia podra ser seguir la pared al igual que hacia el tanque walls, adems, se podran realizar diversas mejoras para que nuestro robot tardar menos en escasear, disparara mas eficientemente y esquivara las balas del enemigo. Por todo ello, se opto por una estrategia de evasin, ya que al estar pegado a la pared, si se realizaran los movimientos correctamente, podramos conseguir que nuestro enemigo fuera perdiendo energa poco a poco debido a que no nos acertara en los disparos. Centrndonos en cada una de las estrategias seguidas para cada uno de los tres puntos enunciados anteriormente, tenemos:

Como movernos?
Para elegir esta opcin, lo primero que tuvimos que hacer es consultar que mtodos del API de Robocode nos ayudaran a realizar los movimientos y por donde moveramos a nuestro robot: Para que tanto el radar, como el can se muevan independientemente del chasis del tanque, se necesitan: void setAdjustGunForRobotTurn(boolean newAdjustGunForRobotTurn) sirve para tener un movimiento del can independiente del cuerpo void setAdjustRadarForGunTurn(boolean newAdjustRadarForGunTurn) sirve para tener un movimiento del radar independiente del can. void setAdjustRadarForRobotTurn(boolean newAdjustRadarForRobotTurn) sirve para tener un movimiento del radar independiente del robot.

Para obtener las dimensiones del campo se pueden utilizar los siguientes mtodos: double getBattleFieldHeight() nos indica la altura mxima del campo de batalla. double getBattleFieldWidth() nos indica la anchura mxima del campo de batalla. Sabiendo que el campo de batalla, tiene el origen de coordenadas en la esquina inferior izquierda, durante cualquier instante del combate, se puede obtener la posicin en el campo de batalla del robot mediante:

double getX() nos indica la posicin en la coordenada X de nuestro robot. double getY() nos indica la posicin en la ordenada Y de nuestro robot. Para mover en si el tanque, estn los siguientes mtodos: void setAhead(double distance) sirve para mover el robot hacia adelante void setBack(double distance) sirve para mover el robot hacia atrs void turnLeft(double degrees) sirve para girar a la izquierda void turnRight(double degrees) sirve para girar a la derecha de igual modo, existen mtodos para mover tanto el radar como el escner: void setTurnGunLeft(double degrees) void setTurnGunRight(double degrees) void setTurnRadarLeft(double degrees) void setTurnRadarRight(double degrees) con todos estos mtodos, podemos conseguir que nuestro robot mueva independientemente el escner y el can del chasis, y por tanto, podemos ir moviendo el tanque siguiendo las paredes mientras que escaneamos y disparamos independientemente de nuestro movimiento. De esta manera, si nos movemos mucho y deprisa, sin que el movimiento sea predecible por los robots enemigos, ellos iran gastando poco a poco su energa disparndonos. Con lo que habremos implementado nuestra estrategia de evasin. El principal problema de esto, es que al movernos tan cerca de la pared, tenemos que controlar constantemente que no se choca con ella ya que estaramos perdiendo energa intilmente. Y de igual modo, tenemos que tener cuidado con el robot que est cercano a la pared, o como nosotros la siguen para que no colisionemos, y en caso de que lo hagamos, salgamos beneficiados de ello.

Cuando, como y con que potencia disparar?


Una vez decidida la estrategia del movimiento, y sabiendo que es independiente de los disparos, se nos planteo el problema de que el adversario se moviese mucho y estuviese muy lejos de nosotros. Ya que nosotros no nos acercamos a el, y no sabemos si el lo har, decidimos que no sala rentable dispararle desde lejos ya que estaramos utilizando nuestra propia tcnica en nuestra contra, as que decidimos que si se encontraba a mas de 300 de distancia, no le dispararamos. Aunque este a menos de 300 de distancia, si nos queda poca energa mientras que el enemigo tiene mas que nosotros, tampoco le disparamos, es preferible esquivarle para que siga perdiendo energa hasta que tenga aproximadamente la misma que nosotros. Tambin, tenemos que pensar con que potencia de disparo lanzamos nuestra bala contra el robot contrincante. Tras decidir que a mas de 300 de distancia no le dispararamos, y que la potencia de fuego puede variar entre 0 y 3 fue sencillo pensar que si estaba a menos de 50 le dispararamos con la mxima energa, si estaba entre 50 y 100 con algo menos y as progresivamente tal y como muestra el cuadro siguiente:

distancia 0 - 50 50 - 100 100 - 150 150 200 200 250 250 300

Potencia de disparo 3 2.5 2 1.5 1 0.5

En resumen, solo dispararamos al contrincante si tiene nuestra misma energa o menos y se encuentra cerca de nosotros, sino, preferimos esquivarle para que siga perdiendo energa disparndonos.

Como localizar a nuestro enemigo?


Para localizar a nuestro enemigo, lo primero que tenemos que hacer es girar el radar 360 grados para obtener por primera vez su posicin y dems datos necesarios para el disparo. Adems, si llevamos un algn tiempo sin localizarle, tambin vendra bien volver a rotar el escner para volver a localizarle cuanto antes. En caso de que le tengamos localizado, puesto que el radar estar siempre intentando apuntar hacia el enemigo, lo nico que tenemos que hacer para actualizar la posicin del radar es obtener la posicin relativa del otro robot y restarle el ngulo de diferencia que haya entre nuestro escner y la posicin de 0 de nuestro robot (el heading). Adems, si se le aade un pequeo offset, se conseguir corregir el desfase entre el momento en el que calculamos la situacin del otro tanque y la que tendr en el momento siguiente de actualizar el escner. De esta forma estar siempre localizado y puesto que solo nos tenemos que preocupar de un solo contrincante, no necesitaremos implementar muchas mejoras respecto a este movimiento de escner. Para almacenar toda la informacin que necesitamos de nuestro enemigo, tendremos que crearnos una clase aparte de la del propio robot donde estn almacenadas todas las variables y mtodos que tenemos que realizar sobre el clculo de posicin y disparo de nuestro enemigo.

Cdigo
package dmm; import robocode.*; import java.awt.Color; /** * Definitivo by dmm y pa */ public class Definitivo extends AdvancedRobot { double movimiento; // cuanto nos movemos double movMaxHor; //movimiento maximo horizontal double movMaxVer; //movimiento maximo vertical double potencia; // potencia de disparo //variables de estado para saber el movimiento siguiendo las paredes int pared = 2; // variable final para tener el valor de 180 final double PI = Math.PI; Enemigo target;// referencia a un objeto de la clase enemigo // varibles que nos ayudan a saber en que sentido va el escaner y el robot int direction = 1; int sentidoEscaner = 1; /** * run: Mtodo principal de nuestro Robot */ public void run() { //Coloreamos nuestro robot setColors(Color.black,Color.black,Color.yellow); //inicializamos variables del entorno de combate y nos creamos el enemigo target = new Enemigo(); target.distance = 100000; movMaxHor = getBattleFieldWidth(); movMaxVer = getBattleFieldHeight();

//Iniciamos movimiento hacia la pared superior y giramos para empezar //el movimiento evasivo turnLeft(getHeading()); movimiento = movMaxVer - getY() -25; ahead(movimiento); turnRight(90);

//activamos las funciones del caon y radar para que sean independientes setAdjustGunForRobotTurn(true); setAdjustRadarForGunTurn(true); setAdjustRadarForRobotTurn(true);

//Bucle principal de funcionamiento while (true) { //nos movemos y actualizamos la pared en la que estamos pared = mover(); // escaneamos en busca del objetivo, y si cumple las especificaciones de // cercania disparamos escanear(); calcularTiro(); if(calcularPotencia()) fire(potencia); //Disparamos execute(); } }

/** * mover: Metodo que define el movimiento general de nuestro Robot */ public int mover(){ // varible que contiene el movimiento maximo que puede realizar el robot double movimientoMax = 100000; // variable local que nos indica en que pared estamos int isInWall; isInWall = pared; // el movimiento esta comprendido entre 300 y 0, siendo mas o menos aleatorio movimiento = Math.random()*300; //si nos ha salido un movimiento muy pequeo, lo cambiamos if (movimiento < 50) movimiento = 50; switch (isInWall){ //actualizamos el movimiento maximo en funcion de la pared en la que //estemos y la situacion del robot actual case 1: movimientoMax = movMaxVer - getY() - 25; break; case 2: movimientoMax = movMaxHor - getX() - 25; break; case 3: movimientoMax = getY() - 25; break; case 4: movimientoMax = getX() - 25; break; default: movimientoMax = 25; pared = 4; } // si el movimiento es justo para llegar al fin de esa pared, giramos, sino simplemente nos movemos hacia adelante

10

if (movimiento > movimientoMax &&( pared == 1 || pared == 2 || pared == 3 || pared == 4 )) { if (pared == 4 && movimientoMax == 25){isInWall = 4;} else {isInWall = ++pared %4; movimiento = movimientoMax; ahead(direction*movimiento); turnRight(90); } } else {setAhead(movimiento);} return isInWall; } /** * onHitRobot: Si chocamos con un adversario, retrocedemos o avanzamos segun *donde este y cambiamos el sentido de la marcha. */ public void onHitRobot(HitRobotEvent e) { direction = direction*-1; // Si esta delante nuestra, echamos para atrs if (e.getBearing() > -90 && e.getBearing() < 90) setBack(100); // Si est detrs nos desplazamos en sentido contrario else setAhead(100); } /** * calcularPotencia(): Calculamos la potencia optima basado en la distancia al objetivo */ boolean calcularPotencia() { /*variables auxiliares donde se almacenara la distancia al enemigo y los valores maximos y minimos que acotan cada potencia de disparo*/ double distancia, min, max; distancia = target.distance; /*si la distancia esta fuera del rango asignado, no se dispara, con lo que se pone el poder de disparo a 0 y se devuelve false*/ if (distancia > 300 || distancia < 0) potencia = 0; else{ min = 250; max = 300; potencia = 3;

11

// calculamos la potencia de tiro en funcion de la distancia a la que este while(!(distancia > min && distancia < max)){ potencia = potencia -0.5; min= min -50; max = max -50; if (distancia > 300 || distancia < 0){potencia = 0; break;} } // si esta en el rango, devolvemos true, con lo que se disparara if (potencia != 0) return true; } // en caso de no devolver true, es porque no esta en el rango, con lo que no se disparara. return false; } /** * escanear(): Realizamos un scanner */ void escanear() { double radarOffset; //Si hace tiempo que no localizamos a nadie if (getTime() - target.ctime > 4) { radarOffset = 360;//lo rotamos 360 } else { //Calculamos el giro necesario del radar para seguir al objetivo radarOffset = getRadarHeadingRadians() absbearing(getX(),getY(),target.x,target.y); //Calculamos el offset debido al seguimiento del objetivo //para no perderlo if (radarOffset < 0) radarOffset -= PI/8; else radarOffset += PI/8; } //giramos el radar setTurnRadarLeftRadians(NormaliseBearing(radarOffset)); } /** * calcularTiro(): Realizamos los clculos de balstica */ void calcularTiro() {

12

// Primera estimacin: calculamos el tiempo que tardara en llegar el proyectil a la posicion actual del objetivo long time = getTime() + (int)(target.distance/(20-(3*potencia))); // calculamos el offset de giro segn una estimacin de movimiento lineal double gunOffset = getGunHeadingRadians() absbearing(getX(),getY(),target.guessX(time),target.guessY(time)); //giramos el caon setTurnGunLeftRadians(NormaliseBearing(gunOffset)); }

//ajustamos el ngulo si no se encuentra de -pi a pi double NormaliseBearing(double ang) { if (ang > PI) ang -= 2*PI; if (ang < -PI) ang += 2*PI; return ang; } //Si no se encuentra de 0 a 2pi lo modificamos para que sea el ngulo ms corto double NormaliseHeading(double ang) { if (ang > 2*PI) ang -= 2*PI; if (ang < 0) ang += 2*PI; return ang; } //Calcula la distancia entre dos puntos x e y public double getrange( double x1,double y1, double x2,double y2 ) { double xo = x2-x1; double yo = y2-y1; double h = Math.sqrt( xo*xo + yo*yo ); return h; } //Calcula el ngulo entre dos puntos public double absbearing( double x1,double y1, double x2,double y2 ) { double xo = x2-x1; double yo = y2-y1; double h = getrange( x1,y1, x2,y2 ); if( xo > 0 && yo > 0 ) { return Math.asin( xo / h ); } if( xo > 0 && yo < 0 )

13

{ return Math.PI - Math.asin( xo / h ); } if( xo < 0 && yo < 0 ) { return Math.PI + Math.asin( -xo / h ); } if( xo < 0 && yo > 0 ) { return 2.0*Math.PI - Math.asin( -xo / h ); } return 0; }

/** * onScannedRobot: Mtodo que se ejecuta cuando el scanner encuentra un robot */ public void onScannedRobot(ScannedRobotEvent e) { //Si encontramos un robot ms cercano al objetivo actual if ((e.getDistance() < target.distance)||(target.name == e.getName())) { //Calcular apuntamiento double absbearing_rad = (getHeadingRadians()+e.getBearingRadians())%(2*PI); //actualizamos las variables del nuevo objetivo target.name = e.getName(); target.x = getX()+Math.sin(absbearing_rad)*e.getDistance(); target.y = getY()+Math.cos(absbearing_rad)*e.getDistance(); target.bearing = e.getBearingRadians(); target.head = e.getHeadingRadians(); target.ctime = getTime(); target.speed = e.getVelocity(); target.distance = e.getDistance(); } }

/** * onRobotDeath: Mtodo que corre cuando muere un adversario */ public void onRobotDeath(RobotDeathEvent e) { if (e.getName() == target.name) target.distance = 10000; //actualizamos la variable de distancia } }

14

/* * Clase Enemigo. La utilizamos para almacenar la informacin acerca de nuestros adversarios * Posicin, velocidad, disparos, etc */ class Enemigo { String name; public double bearing; public double head; public long ctime; public double speed; public double x,y; public double distance; //metodo que intenta adivinar la coordenada X del enemigo en function de los datos que tenemos de el public double guessX(long when) { long diff = when - ctime; return x+Math.sin(head)*speed*diff; }

//metodo que intenta adivinar la coordenada Y del enemigo en function de los datos que tenemos de el public double guessY(long when) { long diff = when - ctime; return y+Math.cos(head)*speed*diff; } }

15

Conclusiones
La primera de las conclusiones es que ha sido extremadamente difcil depurar el cdigo ya que no contbamos con ninguna manera de poder mostrar mensajes por pantalla con lo que nunca hemos tenido a ciencia cierta si el robot hacia lo que nosotros pensbamos o no. Esto se ha debido a que los mtodos del paquete java.io que tenamos en el API de Robocode daban errores de compilacin. Este problema ha sido determinante en la construccin del robot ya que no hemos podido implementar muchas de las mejoras y estrategias que tenamos pensadas en el robot, teniendo que simplificar el cdigo con lo que nuestro robot se ha hecho mucho ms vulnerable. El comportamiento, aun as del robot ha sido satisfactorio en las pruebas realizadas con los robots de ejemplo suministrados con Robocode con los cuales siempre se ha obtenido la victoria para cada uno de ellos.

el siguiente ejemplo muestra otra batalla con otro de los robots de muestra, se ha probado con todos los robots tanto en 10 como en 5 asaltos y siempre se ha obtenido la victoria.

No se ha podido implementar totalmente la estrategia de disparo ni de movimiento por el motivo anteriormente mencionado, pero ajustando el disparo al un valor por defecto, tambin se han conseguido buenos resultados con los robots de prueba. La experiencia ha sido pese a todo, entretenida y muy divertida.

16

Bibliografa
http://www.it.uc3m.es/jvillena/irc/ http://www.robocode.ie/index.html http://robocode.sourceforge.net/ http://www.codepoet.org/~markw/robocode/ http://www.ibm.com

17

S-ar putea să vă placă și