Next Previous Contents

4. Construcción de robots

En este capítulo se describe lo que necesitas saber para construir tus propios robots. Lo más importante es conocer el lenguaje de los mensajes, el cual es un conjunto de alrededor de 35 comandos utilizados para comunicarse con el programa servidor. También es interesante estudiar los robots de ejemplo del directorio Robots/.

4.1 Leer mensajes

Al comienzo de cada secuencia, los procesos de los robots son lanzados por el programa servidor y se les asignan dos tuberías, una para la entrada y otra para la salida. Estas están conectadas a STDIN y STDOUT, de modo que, desde el punto de vista del robot, se está comunicando con el servidor a través de su entrada y salida estándar.

Esta aproximación significa que los robots pueden escribirse en casi cualquier lenguaje de programación. No obstante, el robot debe ser capaz de saber cuando ha recibido un nuevo mensaje. Para conseguirlo, existen (al menos) tres métodos diferentes entre los que elegir:

La entrada estándar es bloqueante:

Este es el método más simple. Cuando se lee de la entrada estándar, el programa queda bloqueado hasta que llega el siguiente mensaje. El programa puede hacerse por tanto como si siempre hubiera un mensaje esperando. La contrapartida es que no se puede hacer ningún cálculo mientras se espera la llegada de nuevos mensajes.

Para elegir el método bloqueante, basta con enviar la siguiente opción del robot tan pronto como el programa comience:

cout << "RobotOption " << USE_NON_BLOCKING << " " << 0 << endl;
Ten en cuenta que esto es código C++. Si no utilizas C++ simplemente imprime este mensaje por la salida estándar. endl es lo mismo que 'end of line'.

Select:

Utilizando la función select de la librería libc de Unix hace posible que el robot tenga un mejor control sobre cuando buscar nuevos mensajes. Permite, por ejemplo, leer todos los mensajes disponibles, realizar algunos cálculos, enviar comandos y a continuación esperar la llegada de más mensajes. Para aprender más acerca de select, mira en la documentación de Unix (por ejemplo, páginas de manual o información de emacs).

Para elegir este método, envía la siguiente opción del robot tan pronto como el programa comience:

cout << "RobotOption " << USE_NON_BLOCKING << " " << 1 << endl;
Ten en cuenta que esto es código C++.

Señales:

Si quieres, puedes indicar a RealTimeBattle que envíe una señal al robot cuando un nuevo conjunto de mensajes haya sido enviado. Este método hace posible que el robot reciba continuamente información actualizada del programa servidor incluso cuando se encuentre ocupado realizando cálculos. Si no estás seguro de como utilizar las señales, mira en la documentación o estudia otros robots para aprender más.

Para elegir el método de señales, envía la siguiente opción del robot tan pronto como el programa comience:

cout << "RobotOption " << USE_NON_BLOCKING << " " << 1 << endl;
cout << "RobotOption " << SIGNAL << " " << SIGUSR1 << endl;
Ten en cuenta que esto es código C++.

Por supuesto, puedes elegir cualquier otra señal a parte de SIGUSR1.

Como apoyo para la implementación de estos métodos, el robot rotate_and_fire ha sido escrito en tres versiones distintas, aunque equivalentes. Tomate la libertad de estudiar y copiar este código para utilizarlo en tus propios robots.

Ten en cuenta que no es una buena idea emplear "espera activa", por ejemplo, mirar continuamente si hay un mensaje nuevo hasta que se obtiene uno. Esto ralentizaría las cosas notablemente y, peor todavía, en modo de competición el robot consumirá rápidamente su tiempo de CPU y morirá.

4.2 Messagetypes.h

El fichero Messagetypes.h es una buena fuente de información sobre el lenguaje de los mensajes. Es un fichero de cabecera de C/C++, pero puedes reescribirlo fácilmente para su uso con otros lenguajes. En él puedes encontrar un listado de los mensajes, tipos de alarmas, objetos, opciones del juego y opciones de los robots.

4.3 Trampas

Dado que el combate se realiza en tiempo real con procesos reales, sería posible escribir programas que 'hagan trampa' de uno u otro modo. Por ejemplo, examinando otros robots o incluso el proceso de RealTimeBattle para obtener más información, empleando una gran cantidad de recursos para perjudicar a los otros robots, etc. Por supuesto, este no es el modo en que se pretende la victoria sobre los oponentes, por lo que intentamos erradicarlo tanto como sea posible.

En modo de competición, los robots tienen un tiempo de CPU limitado, de modo que un robot no puede utilizar todos los recursos del procesador. Podría resultar posible sortear este obstáculo lanzando procesos hijos. Pero dado que el tiempo utilizado por los procesos hijos sería contabilizado tan pronto como el proceso muera, debería ser muy fácil detectar si un robot hace algo sospechoso.

No es posible prevenir todas las maneras de hacer trampas en RTB. Esta permitido, por ejemplo, leer y escribir ficheros, pero recuerda que los organizadores de una competición pueden prohibir esto si así lo desean. Esto puede lograrse de un modo satisfactorio estableciendo los permisos y propietarios de los ejecutables de los robots y los directorios.

Pese a todo, aún es posible que puedan hallarse otras maneras de evitar estas restricciones. Si detectas una de estas maneras, envía por favor un informe de error. De todas formas, queda a discreción del organizador de un torneo el asegurarse de que las reglas se cumplan.

4.4 Mensajes a los robots

Initialize [first? (int)]

Este es el primer mensaje que el robot recibirá. Si el argumento es uno, se trata de la primera secuencia del torneo y deberán mandarse el nombre y color del robot al servidor, en caso contrario deberán esperarse los mensajes YourName y YourColour (ver más abajo).

YourName [name (string)]

Nombre actual del robot. No debe cambiarse a menos que se tengan buenas razones para ello.

YourColour [colour (hex)]

Color actual del robot. Cámbialo si te desagrada. Todos los robots de un mismo equipo tendrán el mismo color.

GameOption [optionnr (int)] [value (double)]

Al comienzo de cada juego se enviarán a los robots un cierto número de parámetros, que pueden ser útiles para ellos. Para hallar una lista completa de estos, mira en el fichero Messagetypes.h el enumerado game_option_type. En el capítulo de opciones puedes obtener información más detallada sobre cada opción. El nivel de depuración es también enviado como una opción del juego a pesar de no encontrarse en la lista de opciones.

GameStarts

Este mensaje es enviado cuando comienza el juego (¡sorpresa!).

Radar [distance (double)] [observed object type (int)] [radar angle (double)]

Este mensaje proporciona cada turno información del radar. Recuerda que el ángulo del radar es relativo al frontal del robot y viene dado en radianes.

Info [time (double)] [speed (double)] [cannon angle (double)]

El mensaje Info siempre sigue al mensaje Radar. Proporciona más información general sobre el estado del robot. El tiempo es el tiempo de juego transcurrido desde el comienzo del mismo. Este no es necesariamente igual al tiempo real transcurrido, debido a la escala de tiempo y el máximo paso de tiempo.

Coordinates [x (double)] [y (double)] [angle (double)]

Informa sobre la posición actual del robot. Es enviado solo si la opción Send robot coordinates es 1 o 2. Si es 1, se envían las coordenadas relativas a la posición inicial, con la consecuencia de que el robot no sabe donde ha comenzado, sino solo adonde se ha desplazado desde entonces.

RobotInfo [energy level (double)] [teammate? (int)]

Si se detecta un robot con el radar, este mensaje se enviará a continuación, dando cierta información sobre el robot. El nivel de energía del oponente es suministrado del mismo modo que tu propia energía (ver más abajo). El segundo argumento solo es interesante en el modo de equipos: 1 significa compañero de equipo y 0 significa enemigo.

RotationReached [what has reached(int)]

Cuando la opción del robot SEND_ROTATION_REACHED está establecida del modo apropiado, este mensaje se envía cuando una rotación (realizada con RotateTo o RotateAmount) ha finalizado o la dirección ha cambiado (barrido). El argumento corresponde a 'qué rotar' en, por ejemplo, el mensaje Rotate.

Energy [energy level(double)]

Al final de cada ronda el robot recibirá un mensaje con su propio nivel de energía. No se recibirá, sin embargo, el valor exacto de energía, sino que este es discretizado en un cierto número de niveles de energía.

RobotsLeft [number of robots (int)]

Al comienzo del juego, y cada vez que muera un robot, se enviará a todos los robots supervivientes el número de robots restantes.

Collision [colliding object type (int)] [angle relative robot (double)]

Cuando un robot choca contra (o recibe el impacto de) algo, recibe este mensaje. En el fichero Messagetypes.h puedes encontrar una lista de los tipos de objeto. Se recibe el ángulo desde donde la colisión ha ocurrido (el ángulo relativo al robot) y el tipo de objeto con el que se ha chocado, pero no la severidad del impacto. Esto puede, no obstante, determinarse indirectamente (de forma aproximada) a través de la pérdida de energía.

Warning [warning type (int)] [message (string)]

Un mensaje de advertencia será enviado cuando haya de notificarse a un robot acerca de diferentes problemas que hayan ocurrido. Actualmente hay siete mensajes distintos de advertencia que pueden ser enviados, a saber:

UNKNOWN_MESSAGE: El servidor recibió un mensaje que no pudo reconocer.

PROCESS_TIME_LOW: El uso de CPU ha alcanzado el porcentaje de advertencia. Solo en modo de competición.

MESSAGE_SENT_IN_ILLEGAL_STATE: El mensaje recibido no puede ser tratado en el estado actual del programa. Por ejemplo, en caso de que Rotate sea enviado antes del comienzo del juego.

UNKNOWN_OPTION: El robot envió una opción con un nombre ilegal o un argumento ilegal para esa opción.

OBSOLETE_KEYWORD: La palabra clave enviada es obsoleta y no debe ser utilizada más. Véase el fichero Changelog para más detalles sobre que palabra emplear en su lugar.

NAME_NOT_GIVEN: El robot no ha enviado su nombre antes del comienzo del juego. Esto puede ocurrir si el tiempo de arranque del robot es demasiado corto o el robot no envía su nombre lo bastante pronto.

COLOUR_NOT_GIVEN: El robot no ha enviado su color antes del comienzo del juego.

Dead

El robot ha muerto. No intentes enviar más mensajes al servidor hasta el final del juego, ya que el servidor no los leerá.

GameFinishes

El juego actual ha terminado. ¡Prepárate para el siguiente!

ExitRobot

¡Sal del programa inmediatamente! De lo contrario será matado a la fuerza.

4.5 Mensajes de los robots

Cuando envíes mensajes al servidor de RealTimeBattle asegúrate de que su longitud no sea mayor de 128 caracteres, de lo contrario RealTimeBattle los partirá en dos y puede informar acerca de un mensaje desconocido.

RobotOption [option nr (int)] [value (int)]

Actualmente solo están disponibles las siguientes opciones:

SIGNAL: Indica al servidor que debe enviar una señal cuando haya un mensaje esperando. El argumento determinará que señal. Envía este mensaje (por ejemplo con SIGUSR1 por argumento) tan pronto como estés preparado para recibir la señal. El valor por defecto es 0, que significa que no debe enviarse señal alguna.

SEND_SIGNAL: Indica al servidor que debe enviar SIGUSR1 cuando haya un mensaje esperando. Envía este mensaje (con argumento 1, o sea cierto) tan pronto como estés preparado para recibir la señal. El valor por defecto es falso.

SEND_ROTATION_REACHED: Si deseas que el servidor envíe un mensaje de tipo RotationReached cuando una rotación termine, debes establecer esta opción. Con un valor de 1, el mensaje se envía cuando RotateTo o RotateAmount han concluido. Con un valor de 2, los cambios en la dirección de barrido también son notificados. El valor por defecto es 0, a saber, no enviar ningún mensaje.

USE_NON_BLOCKING: Selecciona como funcionará la lectura de mensajes. Esta opción debe enviarse exactamente una vez tan pronto como el programa se inicie. Dado que siempre debe enviarse, no existe valor por defecto.

Name [name (string)]

Cuando se recibe el mensaje Initialize con argumento 1, indicando que se trata de la primera secuencia, deben enviarse el nombre y color del robot. Si el nombre termina con la cadena Team: nombre_de_equipo, el robot estará en el equipo indicado. Por ejemplo "Name foo Team: bar" asignará el robot al equipo bar y su nombre será foo. Todos los robots en un mismo equipo tendrán el mismo robot y se reconocerán entre sí a través del mensaje RobotInfo. Para posibilidades más sofisticadas, mira la infraestructura de equipos para RealTimeBattle.

Colour [home colour (hex)] [away colour (hex)]

Ver más arriba. Los colores son como las camisetas de fútbol habituales. El color propio es utilizado a menos que ya esté siendo empleado. De otro modo, se usará el segundo color o, como último recurso, un color en desuso seleccionado aleatoriamente.

Rotate [what to rotate (int)] [angular velocity (double)]

Fija la velocidad angular del robot, el cañón y/o el radar. El primer parámetro adopta valores de 1 para el robot, 2 para el cañón, 4 para el radar o una suma de estos para rotar varios elementos al mismo tiempo. La velocidad angular es dada en radianes por segundo y está limitada por la máxima velocidad de rotación (robot/cañón/radar).

RotateTo [what to rotate (int)] [angular velocity (double)] [end angle (double)]

Como Rotate, pero rotará a un ángulo dado. Ten en cuenta que los ángulos del cañón y el radar son relativos al ángulo del robot. Este comando no puede ser utilizado para hacer girar el propio robot, usa RotateAmount en su lugar.

RotateAmount [what to rotate (int)] [angular velocity (double)] [angle (double)]

Como Rotate, pero rotará un ángulo relativo al ángulo actual.

Sweep [what to rotate (int)] [angular velocity (double)] [right angle (double)] [left angle (double)]

Como Rotate, pero deja el cañón y/o el radar en un modo de barrido (no disponible para el robot).

Accelerate [value (double)]

Fija la aceleración del robot. El valor queda acotado por la aceleración máxima y mínima del robot.

Brake [portion (double)]

Activa el freno. Frenado total (parámetro igual a 1.0) significa que el rozamiento en la dirección del robot es igual a la fricción de deslizamiento.

Shoot [shot energy (double)]

Dispara con la energía dada. Las opciones de disparo proporcionan más información al respecto.

Print [message (string)]

Imprime un mensaje en la ventana de mensajes.

Debug [message (string)]

Imprime un mensaje en la ventana de mensajes si se está en el modo de depuración.

DebugLine [angle1 (double)] [radius1 (double)] [angle2 (double)] [radius2 (double)]

Dibuja una línea directamente sobre la arena. Esto solo está permitido en el nivel de depuración más alto (5). De lo contrario se enviará un mensaje de advertencia. Los argumentos son el punto inicial y final de la línea en coordenadas polares relativas al robot.

DebugCircle [center angle (double)] [center radius (double)] [circle radius (double)]

Similar a DebugLine, pero dibuja un círculo. Los dos primeros argumentos son el ángulo y el radio del punto central del círculo relativos al robot. El tercer argumento proporciona el radio del círculo.


Next Previous Contents