DOCUMENTACIÓN FINAL TIKITAKA Jesús Ladevesa Medina jesus.ladevesa@estudiants.urv.cat Miguel Ángel Linares Herrero miguelangel.linares@estudiants.urv.cat Àngel Moreno Prats amoreno@tinet.org Javier Sánchez Alonso javier.sanchez@estudiants.urv.cat 2 ÍNDICE Parte I: El proyecto Tikitaka 5 1 Introducción 5 2 Especificación del estándar 5 3 Temporización 6 Parte II: Descripción técnica del proyecto Tikitaka 8 4 Tecnología utilizada 8 5 Implementación 9 5.1 Módulo de Control 9 5.1.1 Introducción 9 5.1.2 Diseño 9 5.1.2.1 Connecta 11 5.1.2.2 Inici 11 5.1.2.3 Joc 11 5.1.2.4 Gol-Ack 11 5.1.2.5 Falta 12 5.1.2.6 Fipart 12 5.1.2.7 Fipartit 12 5.2 Módulo de Comunicaciones 13 5.2.1 Introducción 13 5.3.2 Diseño 13 5.2.3 Implementación 15 5.2.3.1 Núcleo 16 5.2.3.2 Servidores 17 5.2.3.3 Gestores 18 5.2.3.4 Factorías 20 5.2.3.5 Reloj 21 5.2.3.6 Auxiliares 21 5.2.4 Modificaciones sobre el protocolo 23 5.3 Módulo de Inteligencia Artificial 23 5.3.1 Introducción 23 5.3.2 Diseño 23 5.3.2.1 Comportamiento de los agentes 24 5.3.2.2 Algoritmo de encaminamiento 25 5.3.3 Implementación 26 5.4 Módulo de Gráficos 27 5.4.1 Introducción 27 5.4.2 Diseño 28 5.4.2.1 Diseño de objetos 28 5.4.2.2 Diseño de la programación 3D 28 5.4.3 Implementación 29 6 Resultados 30 6.1.1 Módulo de Comunicaciones 30 Anexos 32 A Manual de usuario 32 A.1 Instalación 32 A.2 Uso 32 A.2.1 Servidor 32 A.2.2 Cliente 32 A.2.2.1 Inicio 32 3 A.2.2.2 Unirse a partida 33 A.2.2.3 Iniciar el juego 33 A.2.2.4 Durante el partido 34 A.2.2.5 Xiulet 35 A.2.2.6 Selección de Cámara 35 A.2.2.7 Cronómetro 35 A.2.2.8 Fin del partido 35 B Referencias 35 C Oficina Técnica 36 C.1 Sesión 2 de Febrero 36 C.2 Sesión 8 de Febrero 36 C.3 Sesión 9 de Febrero 37 C.4 Sesión 15 de Febrero 39 C.5 Sesión 16 de Febrero 43 C.6 Fe de erratas 22 de Marzo 43 C.7 Aclaraciones 12 de Abril 43 C.8 Actualización especificaciones 20 de Abril 44 D Protocolo Simulador FIRA Middle League SimuroSot 44 4 Parte I: El proyecto Tikitaka 1 Introducción El objetivo de este proyecto es el de crear un simulador de la liga intermedia de fútbol robótico basado en la FIRA middle league. El proceso de desarrollo se ha llevado a cabo por varios grupos dando diferentes soluciones a un mismo problema, que debían ser compatibles. Para ello se hicieron varias reuniones con el usuario final para decidir que características debía tener este software. Durante estas semanas se decidió que el sistema a realizar seria desarrollado en dos partes, un servidor que simularía el comportamiento del campo y un software cliente que simularía un equipo de la competición y dejaría visualizar al usuario lo que ocurre e interactuar con el sistema. Una vez decidido esto se mostraba un nuevo punto a tener en cuenta, las comunicaciones entre los distintos resultados. Después de semanas de negociación se pactan unas modificaciones en las reglas de juego originales y se especifican las partes comunes a todos los desarrollos. Una vez concluida esta parte cada grupo puede empezar de manera libre el desarrollo utilizando las tecnologías que crea convenientes, y marcándose sus propias metas, siempre teniendo en cuenta la fecha límite en la cual se realizará la demostración del producto frente al resto de grupos y se hará una competición entre ellos. En nuestro caso como verán se ha realizado un trabajo de investigación dando con una solución que responde a todas las especificaciones necesarias de forma más que satisfactoria. También remarcar la tarea de las personas involucradas en el desarrollo, ya que se ha destinado un especialista para cada campo que resolver. 2 Especificación del estándar En este apartado usted podrá ver como está estructurada la aplicación y una visión global de su funcionamiento. Para ello explicaremos como se divide y después como se realiza cada parte. El diseño de la arquitectura de la aplicación sigue el patrón del diseño modular, creando así cuatro componentes que proporcionan a la aplicación las funcionalidades de control del flujo de ejecución (Módulo de Control), control de la comunicación entre cliente y servidor (Módulo de Comunicaciones), la planificación de los movimientos de los robots del equipo propio (Módulo de Inteligencia Artificial) y finalmente la representación gráfica de la simulación del partido al usuario (Módulo de Gráficos). En la siguiente figura podemos observar gráficamente como están organizados los módulos. Por una parte tenemos la aplicación servidor, donde entran en juego los módulos de control y comunicaciones. El módulo de control se encargará de mantener el flujo del ejecución del 5 programa así como de gestionar los eventos generados por los jugadores y por otra se encargará de la simulación física de la partida, aplicando las leyes que correspondan sobre los participantes del juego y sus movimientos para conseguir un comportamiento lo más parecido a la realidad posible. El módulo de comunicaciones se encargará de mantener los canales de comunicación con los jugadores, interactuando con el módulo de control para informarle de los eventos generados por los jugadores (arbitraje del partido). Por otra parte tenemos la aplicación cliente, donde entran en juego todos los módulos. El módulo de control se encargará igualmente de mantener el flujo de ejecución de la aplicación, así como de coordinar al resto de módulos para conseguir un comportamiento correcto. El módulo de comunicaciones se encargará – de la misma manera que hace en la parte cliente – de mantener los canales de comunicación con el servidor, y interactuando con el módulo de control informándole de los cambios producidos en la comunicación con el servidor. El módulo de inteligencia artificial interactuará con el módulo de control durante el transcurso de una partida para ordenar los movimientos óptimos a los robots del equipo que representa. Finalmente el módulo de gráficos interactuará con el módulo de control para representar gráficamente el transcurso de la partida así como dar la interfaz al usuario para que éste pueda producir los eventos de arbitraje que corresponda. En el anexo se puede consultar el resultado de las sesiones de la oficina técnica en las que se especifico el comportamiento que deberian seguir todos los proyectos desarrollados de éste simulador. 3 Temporización La temporización real de nuestro proyecto se puede dividir en las siguientes partes: Inicio (de 08/02/07 a 09/02/07). Durante estos días se decide el grupo de desarrollo y se asignan las tareas que realizará cada uno. En nuestro grupo la asignación queda como sigue: - Miguel Ángel Linares Herreros: Encargado de Gráficos y Jefe de proyecto - Àngel Moreno Prats: Comunicaciones - Jesús Ladevesa Medina: Inteligencia artificial - Javier Sánchez Alonso: Control Análisis entre grupos (de 15/02/07 a 23/02/07). Durante este período se llevan a cabo las negociaciones con el resto de grupos y el usuario final dando como resultado unas especificaciones comunes. Análisis individual (de 01/03/07 a 08/03/07). Este tiempo lo dedicamos a aprender como solucionaremos el problema propuesto. Preparamos la presentación que haremos al usuario con las herramientas que utilizaremos. Presentación (de 08/03/07 a 09/03/07). Estos dos días los dedicamos a hacer las presentaciones al usuario final. Se enseñan las tecnologías que utilizaremos y el funcionamiento general. 6 Aprendizaje (de 12/03/07 a 16/03/07). Esta semana se dedica a documentarnos con detenimiento sobre las herramientas que utilizaremos para más tarde poner en práctica los conocimientos adquiridos haciendo el desarrollo más rápido. Implementación (de 19/03/07 a 11/05/07). Este es el proceso que nos lleva más tiempo. Después de decidir las herramientas a utilizar y analizar nuestras necesidades nos dedicamos íntegramente al desarrollo de nuestra aplicación. Cada parte se trabaja por separado y nos dedicamos únicamente y exclusivamente a la parte asignada. Durante el proceso nos encontramos con varios problemas como la obligación de tener que reimplementar una parte de las comunicaciones por falta de especificación en el análisis. Como hay partes del proyecto que avanzan más rápidamente que otras, también se redirigen los recursos, empleando más tiempo y personas a partes que quedan atrasadas. Integración (de 14/05/07 a 25/05/07). Esta parte consistió en empezar a unir las diferentes partes y solucionar todos los problemas que aparecen en ellas. Incompatibilidades, sincronización, etc. Todos estos problemas son resueltos poco a poco. Se realizan pruebas por partes y se solucionan todos los problemas antes de empezar con la siguiente. Finalmente después de mucho esfuerzo se pasa a la parte de pruebas. Pruebas (de 28/05/07 a 08/06/07). Se realizan pruebas de todo el conjunto. Se corrigen pequeños errores y se siguen desarrollando partes todavía en proceso de desarrollo y comprobación. Documentación y empaquetado (de 11/06/07 a 12/06/07). Finalmente nos dedicamos a documentar todo el trabajo realizado y a empaquetar el producto. De esta manera se realiza todo lo necesario para crear un producto completo. Manuales de usuario, instalador, documentación de módulos, etc. 7 Parte II: Descripción técnica del proyecto Tikitaka 4 Tecnología utilizada Para el desarrollo de éste proyecto se ha utilizado el lenguaje C++, un lenguaje de programación de propósito general, de alto nivel con funcionalidades de bajo nivel y que proporciona la programación procedimental, abstracción de datos, programación orientada a objetos entre otras características. En los siguientes parágrafos se presentaran el resto de componentes y herramientas utilizadas para el desarrollo de éste proyecto. Microsoft Visual C++, también conocido como MSVC, es un entorno de desarrollo (IDE) que proporciona Microsoft para los lenguajes de programación C, C++ y C++/CLI. Incluye herramientas para desarrollar y depurar código C++, especialmente para los que utilizan el Microsoft Windows API, el API de DirectX o el entorno de ejecución basado en Microsoft .NET. Tiene como características el resaltado de sintaxis, el auto completado de código mediante el componente IntelliSense y una avanzada funcionalidad de depuración. Proporciona también funcionalidades como sus sistemas automáticos de compilación y generación, precompilación de ficheros de encabezado, reconstrucción minimalista o el vinculado incremental que permiten acortar sustancialmente el tiempo de compilación y vinculación de una aplicación, especialmente en proyectos de software extensos. POCO, acrónimo de C++ Portable Components, es una colección de clases C++ de código abierto que simplifican y aceleran el desarrollo de aplicaciones orientadas a la comunicación. Ésta biblioteca de funciones se integra perfectamente con la C++ Standard Library además de cubrir muchos de los aspectos que ésta deja sin cubrir. Su diseño modular y su eficiente implementación hacen de ésta biblioteca muy adecuada para entornos incrustados, un área donde el lenguaje de programación C++ está incrementando su popularidad, debido a su flexibilidad en adaptarse tanto en programación a bajo nivel (dispositivos de E/S, gestores de interrupciones, etc.) así como a alto nivel, en una programación orientada a objetos. Ésta biblioteca libera a los desarrolladores de reinventar la rueda, y permite invertir el tiempo en áreas más productivas del desarrollo como puede ser en la fase de diseño. Como características destacables y que usaremos en éste proyecto se pueden nombrar: - Proporciona las herramientas para la programación de un entorno multihilo (threads, sincronización entre threads, etc.) - Acceso a sistema de ficheros y a flujos de información (streams). - Permite la creación de librerías compartidas y la carga dinámica de clases. - Proporciona un potente entorno de registro (logging y accounting). - Facilita la programación en red (sockets TCP/IP, HTTP, FTP, SMTP, etc.) - Proporciona un entorno de ficheros de configuración para las aplicaciones. Además ésta biblioteca se puede usar en una gran variedad de plataformas, incluyendo: Windows ©, Mac OS X, Linux, HP-UX, Tru64, Solaris y QNX. OGRE, acrónimo de Object-Oriented Graphics Rendering Engine, es un motor de renderización 3D flexible y orientado a la escena, desarrollado en C++, diseñado para hacer más fácil y más intuitivo para los desarrolladores producir aplicaciones usando hardware de aceleración 3D. La biblioteca de funciones abstrae todos los detalles del uso de los sistemas de representación Direct3D y OpenGL y proporciona una interfaz basada en objetos mundo y otras clases muy intuitivas. Éste motor es de software libre, licenciado bajo la licencia LGPL y es el resultado de una comunidad muy activa que lo mantiene actualizado. Como características destacables podemos nombrar: - Tiene un diseño orientado a objetos, con una potente arquitectura de plugins que permite añadir funcionalidades fácilmente. - Es multiplataforma, con soporte para con Direct3D y OpenGL. 8 CEGUI, acrónimo de Crazy Eddie’s GUI, es una biblioteca de funciones para crear interfaces de usuario en C++. Está diseñada particularmente para cubrir las necesidades de los videojuegos, aunque es perfectamente utilizable para otras tareas, así mismo está diseñada para proporcionar una gran flexibilidad en la apariencia (lookand-feel) de la aplicación así como que sea muy adaptable a las herramientas y sistemas operativos escogidos por el desarrollador. GIMP, acrónimo de GNU Image Manipulation Program, es un programa de tratamiento de imágenes libre. Es ideal para tareas como retocar fotografías, crear imágenes para la web, etc. Se distribuye bajo una licencia libre, lo que permite usarlo, distribuirlo o incluso adaptarlo a las necesidades de cada uno. 3D Studio Max es una aplicación basada en el entorno Windows (9x/NT) que permite crear tanto modelados como animaciones en tres dimensiones (3D) a partir de una serie de vistas o visores (planta y alzados). 5 Implementación En los siguientes apartados se entrará en detalle en cada uno de los módulos, introduciendo en primer lugar sus objetivos, describiendo las decisiones y comportamientos del módulo definidos en la fase de diseño y las características referentes a la implementación del módulo. 5.1 Módulo de Control 5.1.1 Introducción El objetivo principal del módulo de control, es el de gestionar el hilo de ejecución de la aplicación poniendo todos los medios disponibles para que los diferentes módulos puedan ejecutarse cuando es debido y actúen de forma diferente según el estado en el que se encuentren. De esta forma el módulo de control se ejecutará siguiendo un diagrama de estados previamente definido y que se detallará en la parte de diseño. A cada estado de la aplicación el control podrá hacer una de las siguientes acciones: - Iniciar, detener y reanudar cada uno de los módulos que integran la aplicación. - Actualizar las clases compartidas por los diferentes módulos. De las cuales dichos módulos únicamente podrán consultar su contenido. - Ejecutar la parte de simulación física siempre y cuando nos encontremos en el estado adecuado. - Actualizar el estado en el que se encuentra la aplicación y hacérselo saber a todos los demás módulos. 5.1.2 Diseño El módulo de control estará alojado tanto en el servidor como en la parte cliente. De este modo dependiendo del rol que tenga cuando se le invoque se ejecutará un thread u otro. void ControlCore::run() { if (mRole == TikitakaRoles::SERVER_ROLE) { runServerControlCore(); } else { runClientControlCore(); } } 9 Ambos threads se ejecutarán cíclicamente respondiendo a las notificaciones que les van llegando a una cola de notificaciones. Estas notificaciones las puede recibir del módulo de comunicaciones o de sí mismo que encola una notificación para continuar realizando tareas después de haber acabado una. Las notificaciones responden a unos estados que están predefinidos, donde en cada uno de ellos se realizarán una serie de operaciones. El conjunto de estos estados representará el diagrama de estados de la aplicación global. for (;;) { Notificacion = DesencolarNotificacion(); Switch (Notificacion) { case ESTADO 1 case ESTADO 2 . . . case ESTADO n } A continuación detallaremos el diagrama de estados de la parte servidor. Donde recibirá notificaciones del módulo de comunicaciones y donde se ejecuta la simulación física. Los estados de la parte cliente son prácticamente los mismos. Conect a Inici FipartitAck JOC FipartAck Xiulet FaltaAck IniciJoc GolAck Como hemos comentado el módulo de control es el encargado de crear este diagrama de estados y actualizarlo dependiendo de los eventos que se vayan produciendo en el juego. A continuación detallaremos las acciones que se realizan en cada estado: 10 5.1.2.1 Connecta Este es el primer estado en el que se encuentra la aplicación. En este estado el módulo de control ya ha creado los threads correspondientes para cada uno de los otro módulos (Comunicación, IA, y Gráficos), para que estos se inicialicen. En este estado el control espera que los dos clientes se conecten. Cuando se conecta un cliente se le asigna un identificador de forma aleatoria, se guarda la información de este cliente en la clase Player (Ip, puerto Identificador, goles etc..), y también se actualiza la clase GameData (clase que utilizan todos los módulos de la aplicación para obtener datos relativos al juego) con el numero de conexiones servidas. En este mismo estado se ejecuta la función SimCalcularPosicionsInicials que inicializa los parámetros de la física y establece los componentes geométricos que van a ser simulados. La última acción que se desempeña en este estado es actualizar la clase GameData para que se pase al estado INICI, de esta forma todos los otros módulos podrán saber que hemos cambiado de estado consultando el valor de dicha clase. 5.1.2.2 Inici En el estado inici, el módulo de control resta a la espera de que los dos clientes inicien el juego. Cuando hemos recibido el inicio de los dos clientes iniciaremos el timer que controlará el tiempo de juego, y pasaremos al estado JOC. 5.1.2.3 Joc En este estado el módulo de control recibirá a través de la clase GameData las velocidades angular y lineal de cada uno de los objetos de la simulación a través de los mensajes UDP que gestionará el módulo de comunicaciones. En este caso ejecutaremos la función SimJOC. Esta función se encargará de realizar las siguientes acciones: 1. Obtener los parámetros de cada objeto a través de la clase GameData (velocidad lineal y angular). 2. Actualizar los cuerpos que se han creado con el simulador gráfico ODE con estos nuevos parámetros. 3. Generar un paso en la simulación parametrizando el tiempo de esta. 4. Obtener las nuevas posiciones de los objetos de la simulación resultadas de añadir nuevas velocidades y simular. 5. Actualizar la clase GameData con las nuevas posiciones para que tanto el módulo de IA como el módulo gráfico puedan consultarlas y actualizar sus clases. En este estado no pasaremos de estado, a no ser que desde el módulo gráfico se genere un evento que nos diga que se ha producido una de las siguientes opciones: 1. Gol 2. Falta 3. Fin de la primera parte 4. Fin del partido 5.1.2.4 Gol-Ack A este estado se pasa cuando el usuario ha seleccionado la opción GOL en la interfaz gráfica. En este estado el módulo de control se encargará de realizar las siguientes operaciones: 11 1. 2. 3. 4. 5. Parar el timer del juego. Calcular que equipo ha hecho el gol a partir de la posición de la pelota. Actualizar la clase GameData sumando al equipo el gol anotado. Actualizar la clase GameData con las posiciones de saque de centro. Ejecutar la función SimRecalcularPosicions para actualizar las nuevas posiciones de los objetos físicos que integran la simulación. 5.1.2.5 Falta A este estado se pasa cuando el usuario ha seleccionado una de las siguientes opciones en la interfaz gráfica: 1. Freball 2. Freekick 3. Penalty En este estado el módulo de control recibe como parámetros el tipo de falta que se ha seleccionado y al equipo al que se le ha señalado. A partir de estos parámetros se realizan las siguientes operaciones: 1. En el caso de que se hay seleccionado un penalty o un freekick: a. Dependiendo la parte en que nos encontremos y de quien haya cometido el penalty, actualizaremos el GameData con las posiciones POS_PENALTY_RIGHT o POS_PENALTY_LEFT. 2. En el caso de que se hay seleccionado un freeball: a. Si el freeball se ha seleccionado a un equipo en concreto, el freeball se lanzará en el campo del agresor y dependiendo de la la posición de la pelota calcularemos en que parte del campo del agresor se tendrá que ejecutar éste. De esta forma actualizaremos el GameData con las posiciones POS_FBALL_LEFT_UP, POS_FBALL_LEFT_DOWN, POS_FBALL_RIGHT_UP, POS_FBALL_LEFT_DOWN. b. Si el freeball no se ha seleccionado a ningun equipo, dependiendo unicamente de la posición de la pelota actualizaremos el GameData con las posiciones POS_FBALL_LEFT_UP, POS_FBALL_LEFT_DOWN, POS_FBALL_RIGHT_UP, POS_FBALL_LEFT_DOWN. Una vez actualizado el GameData con las nuevas posiciones, ejecutaremos la función SimRecalcularPosicions para actualizar las nuevas posiciones de los objetos físicos que integran la simulación. 5.1.2.6 Fipart A este estado se pasa cuando el usuario ha seleccionado la opción FI PART en la interfaz gráfica. En este estado el módulo de control se encargará de realizar las siguientes operaciones: 1. Parar el timer del juego. 2. Actualizar en el GameData la parte del juego. 3. Actualizar la clase GameData con las posiciones de saque de centro. 4. Ejecutar la función SimRecalcularPosicions para actualizar las nuevas posiciones de los objetos físicos que integran la simulación. 5.1.2.7 Fipartit A este estado se pasa cuando el usuario ha seleccionado la opción FI PARTIT en la interfaz gráfica. En este estado el módulo de control se encargará de realizar las siguientes operaciones: 12 1. 2. 3. 4. 5. 6. Parar el timer del juego. Inicializar todos los parámetros del GameData . Enviar un Fipartit ack a los dos jugadores. Liberamos la memoria de los objetos del ODE creados en la simulación. Cerramos los dos canales de comunicación de los jugadores. Pasar al estado de esperar conexiones, para poder empezar otra partida. 5.2 Módulo de Comunicaciones 5.2.1 Introducción El objetivo principal del módulo de comunicaciones dentro del diseño global de nuestra aplicación es proporcionar el medio por el cual dos jugadores puedan interactuar entre ellos para llevar a cabo, mediante el envío de una serie de órdenes y la recepción de una serie de resultados, una simulación de un partido de la FIRA Middle League entre ambos. Como se ha descrito con anterioridad, nuestra aplicación sigue un modelo de comunicación cliente-servidor, donde el cliente corresponde a la aplicación gráfica encargada de representar el resultado de la simulación del partido de forma amigable para el usuario además de ejecutar cierta lógica para ordenar los movimientos de los robots del equipo propio, y donde el servidor corresponde a la aplicación encargada de gestionar las ordenes de los clientes y efectuar una simulación del partido mediante las reglas de la física y en función de las órdenes enviadas por los jugadores. Éste modelo implica la necesidad de definir un lenguaje común que todas las partes conozcan, y que permita el intercambio de información necesaria durante el transcurso de una partida de forma eficiente e independiente de la implementación o plataforma donde corran los componentes cliente o servidor. Durante las sesiones de la oficina técnica, en la que se definieron las especificaciones generales de la aplicación, se definió también el protocolo de comunicación que deberían implementar los simuladores para poder interactuar entre ellos. Éste protocolo, cuya especificación podemos consultar en el anexo, está basado en el intercambio de mensajes de texto que viajan en dos canales diferenciados en función del objetivo de los mensajes, de control o de estado. Los mensajes de control corresponden a aquellas acciones referentes a la gestión de la partida, como pueden ser la unión a una partida y todas las órdenes que un árbitro puede ejecutar durante el juego, y los mensajes de estado corresponden a la información referente a las órdenes de movimiento de los robots y los resultados de la simulación física realista de la partida una vez aplicados los movimientos de los robots. La especificación del protocolo define con exactitud las características de los canales de comunicación, así como el flujo de mensajes que se debería respetar durante el transcurso de una partida, así como los formatos de los mensajes, intentando así definir un estándar gracias al cual, cualquier implementación que lo respetara seria capaz de llevar a cabo una partida con cualquier otra implementación de cualquier otro grupo que también lo respetara. Aún así, en el protocolo definido durante la oficina técnica hay una serie de disfuncionalidades que de acuerdo con otros grupos se ha solucionado mediante la corrección y ampliación del mismo tal como veremos posteriormente. 5.3.2 Diseño Durante la fase de diseño de la aplicación, y por tanto del módulo de comunicaciones, se definieron una serie de objetivos que debería seguir la implementación de dicho módulo para garantizar un rendimiento óptimo. 13 Éstos objetivos vinieron marcados principalmente por la arquitectura que debería seguir la aplicación, ya comentada en capítulos anteriores, así como por las restricciones definidas en la especificación del protocolo de comunicación. Así pues éstos objetivos son: - Garantizar un alto nivel de concurrencia, dado el modelo multi-hilo en el que se basa toda la arquitectura de nuestra aplicación se consiguen tiempos de respuesta a los mensajes – en el caso del módulo de comunicaciones – así como en el proceso de los mismos notablemente más rápido y eficiente que en implementaciones basadas en un hilo de ejecución secuencial. Garantizar el nivel de concurrencia óptimo y un eficiente proceso de los mensajes será básico dada la frecuencia con la que los componentes servidor y cliente deberán recibir, procesar y enviar mensajes, que especifica el protocolo que debería de ser de 25 mensajes por segundo. - Transparencia del módulo de comunicaciones, para el resto de módulos de la aplicación, en el sentido el módulo de comunicaciones deberá enmascarar todo el proceso de comunicación con los elementos remotos, independientemente del rol – cliente o servidor – que asume la aplicación. - Asincronismo con el módulo de control, intentando que toda interacción de éste con el módulo de comunicaciones sean llamadas no bloqueantes en la medida de lo posible – dado que siempre habrá un punto de sincronización para respetar el flujo de mensajes definido en la especificación – y que toda la lógica correspondiente a la recepción, proceso y envío de mensajes sea de forma completamente independiente de la ejecución del módulo de control. El diseño del módulo de comunicaciones está pues orientado para cumplir éstos tres objetivos básicos además de garantizar la implementación del protocolo definido en la oficina técnica. Para cumplir los objetivos marcados así como la especificación del protocolo, se han usado una serie de patrones estándar de programación que proporcionan una serie de herramientas comunes usadas por todos los módulos de la aplicación: - Bolsa de Hilos de ejecución (thread pools), patrón / herramienta que nos permita crear un conjunto de hilos de ejecución que originalmente se encuentran en un estado ocioso preparados para ejecutar tares de forma paralela a medida que necesitemos de ellas. Éste patrón es muy eficiente pues por una parte nos elimina la restricción de una ejecución secuencial y por otra parte nos elimina la sobrecarga que nos acarrearía la creación de los hilos a medida que se vayan necesitando. - Factorías (factories), patrón que nos permitirá la implementación de una serie de objetos capaces de crear otros objetos que desempeñaran una determinada función. Éste patrón se usará para crear los gestores de las conexiones de los jugadores, como veremos en el apartado de implementación. - Relojes (timers), patrón que nos permitirá la ejecución de una serie de tareas de forma periódica, de tal forma que cada cierto número de milisegundos se garantice que se desempeñe una función determinada. Una vez definidos los objetivos a cumplir y los patrones de diseño o herramientas disponibles, se está en disposición de describir el diseño interno del módulo. Éste se ha concebido como un objeto que el módulo de control creará y destruirá en cada una de les ejecuciones, que en función del rol que se deba asumir – cliente o servidor – tendrá un comportamiento u otro. A modo de resumen, si el módulo de comunicaciones asume el rol de cliente, éste será el encargado de crear y gestionar la conexión – o el canal – de control contra el servidor así como la de crear el reloj encargado de enviar periódicamente los movimientos de los robots que ordene el módulo de inteligencia artificial y crear el canal de estado por el que se recibirán los mensajes con el resultado de la simulación, 14 es decir, las posiciones de todos los robots así como de la pelota. Si el módulo de comunicaciones asume el rol de servidor, éste será el encargado de crear y gestionar los canales de control por los que los clientes enviaran las órdenes correspondientes a la gestión de la partida así como crear el reloj encargado de enviar periódicamente el estado de la partida a los jugadores y crear los canales de estado por los que recibir los movimientos de los jugadores. Así pues en ambos casos – cliente y servidor – se deberán crear un hilo servidor por el que recibir los mensajes de estado, y un reloj encargado de enviar periódicamente los resultados de los cálculos de la IA en el cliente o de la simulación física en el servidor. Ambos componentes usaran de un canal de comunicación basado en el protocolo de transporte UDP no orientado a la conexión, para garantizar así una eficiencia óptima en el envío de mensajes aunque no se garantice la recepción ni el orden. El protocolo especifica el uso de éste método para garantizar el envío de ésta de información a un ratio muy elevado. De la misma forma en ambos casos se deberá establecer un canal de comunicación de control, pero con un comportamiento diferenciado en función del rol: si se asume el rol de cliente el módulo será el encargado de gestionar una única conexión que establecerá a petición del usuario contra el servidor correspondiente, y si se asume el rol de servidor el módulo será el encargado de crear un hilo servidor por el que recibir los mensajes de control de los jugadores así como crear un hilo para cada canal de control que se establecerá posteriormente con cada uno de los jugadores y por el que se notificaran los eventos del partido de forma bidireccional, tanto en eventos generados desde el jugador y propagados al servidor como del servidor al jugador. Ambos comportamientos usaran de un canal de comunicación basado en el protocolo de transporte TCP orientado a la conexión, para garantizar así la recepción del mensaje y el orden de recepción dado que éstas características son importantes tal y como está definido en la especificación del protocolo. Así pues, los componentes de ambos canales encargados de gestionar la recepción y proceso de mensajes se implementaran mediante el patrón de bolsas de hilos de ejecución y factorías de gestores de la conexión y los componentes de envío periódico de información mediante relojes. Adicionalmente se implementaran una serie de clases auxiliares que se encargaran de la creación de los diferentes mensajes respetando el formato definido en la especificación del protocolo y de comprobar el formato de los mensajes recibidos por cualquier de los canales. 5.2.3 Implementación El proceso de plasmar en código los componentes definidos en la fase de diseño ha dado como resultado una serie de clases que definen una serie de objetos con sus funcionalidades especificas – con sus miembros y métodos correspondientes. Los objetos resultantes los podemos organizar jerárquicamente en función de su visibilidad para con los otros módulos, es decir, en función de quien usa sus características. Así pues los podríamos organizar en los siguientes grupos: - Núcleo: que corresponde al objeto CommCore, núcleo del módulo de comunicaciones, será el objeto visible desde el módulo de control y que creará los servidores multi-hilo, relojes y gestores y factorías en función del rol que asume en el instante de su creación. También proporciona el API que utilizará el módulo de control para generar mensajes a enviar a los extremos remotos de los canales de control o estado. - Servidores: correspondientes a los objetos StateUDPServer y StateUDPServerDispatcher, encargados de implementar el servidor UDP multi-hilo a imagen del objetos TCPServer ya disponible en la librería utilizada en el proyecto. 15 - - - - Gestores: correspondientes a los objetos designados con los nombres de ControlRequestHandler, ControlChannel y StateRequestHandler, encargados de gestionar las peticiones de control al servidor en el canal TCP, de gestionar el canal establecido con cada uno de los jugadores tanto en el cliente como en el servidor y de gestionar las peticiones de estado el canal UDP tanto en el cliente como en el servidor respectivamente. Factorías: correspondientes a los objetos ControlRequestHandlerFactory y StateRequestHandlerFactory, encargados de crear los objetos gestores del punto anterior. Reloj: correspondiente al objeto StateTimer, encargado de enviar periódicamente los mensajes de movimiento de los robots en el caso de los clientes o de los mensajes de estado de la partida en el caso del servidor. Auxiliares: correspondientes a los objetos ControlRequest, ControlResponse, StateRequest y StateResponse, encargados de generar mensajes y proporcionar los métodos para validar el formato de un mensaje para los correspondientes a las peticiones de control (conexión y interrupciones de juego provocadas por el jugador), a las respuestas de control (confirmaciones y interrupciones de juego propagadas desde el servidor), a las peticiones de estado (movimientos generados por los jugadores) y las respuestas de estado (posiciones resultantes de la simulación física) correspondientemente. 5.2.3.1 Núcleo La parte principal del módulo de comunicaciones consiste en un objeto que enmascara toda la arquitectura de hilos de ejecución al módulo de control, de tal forma que se le presenta como una caja cerrada en la que se le ofrecen una serie de puntos de entrada (API) con los que interactuar. Así pues el módulo de control, como responsable de gestionar el resto de módulos, se encarga de crear el módulo de comunicaciones cuando lo necesite, y en la creación del objeto, éste despliega todas las herramientas necesarias en función del rol asumido – cliente o servidor – desde la aplicación. De igual forma se establece un mecanismo por el cual el módulo de comunicaciones pueda interactuar con el módulo de control, señalándole mediante llamadas a los puntos de entrada del módulo de control (su API) los diferentes eventos que se puedan producir durante el transcurso de una partida. Éste mecanismo consiste en el almacenamiento de una referencia al objeto ControlCore para llamar a sus funciones. En definitiva, en la creación del objeto CommCore, se crea: - El subconjunto de hilos encargados de gestionar el servidor UDP, mediante el objeto StateUDPServer de desarrollo propio, al que se le proporciona el objeto factoría correspondiente para el canal de estado. - Si se asume el rol de servidor, el subconjunto de hilos encargados de gestionar el servidor TCP, mediante el objeto TCPServer ya proporcionado por la librería utilizada, al que se le proporciona el objeto factoría correspondiente para el canal de comunicación. - El reloj de envío periódico de mensajes mediante el objeto StateTimer. Una vez creado el objeto, todos los subsistemas que contienen están en un estado inicial parado, que el módulo de control puede cambiar a un estado arrancado mediante el conjunto de funciones que exporta el objeto. Así mismo, el núcleo del módulo de control también ofrece los métodos para gestionar el reloj encargado del envío periódico de mensajes, la gestión de los canales de control (ControlChannel) y el envío de mensajes a través de éstos. En la siguiente tabla se puede observar la relación de métodos públicos que ofrece el objeto CommCore: 16 Método CommCore ~CommCore start stop startTimer stopTimer createControlChannel getPtrControlChannel getRefControlChannel stopControlChannel sendMessage bcastEstatIni bcastGolAck bcastFaltaAck bcastFiPartAck bcastFiPartitAck Descripción Crea el objeto CommCore Destruye el objeto CommCore Arranca los servidores UDP (estado) en cualquiera de los roles de la aplicación y TCP (control) si el rol con el que se ha creado el CommCore es el rol de servidor. Para los servidores arrancados en el método start. Arranca el reloj encargado de enviar periódicamente los mensajes UDP de estado o movimiento en función del rol con el que se ha creado el CommCore. Para el reloj arrancado en el método startTimer. Crea el ControlChannel encargado de gestionar la conexión establecida de control con el jugador o servidor por el socket que se le pasa como parámetro. Retorna el puntero al objeto ControlChannel del jugador que se le pasa como parámetro. Retorna la referencia al objeto ControlChannel del jugador que se le pasa como parámetro. Para el ControlChannel arrancado en el método createControlChannel. Envía el mensaje que se la pasa como primer parámetro a través del ControlChannel que se le pasa como segundo parámetro. Propaga el mensaje ESTATINI a los jugadores a través de los ControlChannel correspondientes. Propaga el mensaje GOL-ACK a los jugadores a través de los ControlChannel correspondientes. Propaga el mensaje FALTA-ACK a los jugadores a través de los ControlChannel correspondientes. Propaga el mensaje FIPART-ACK a los jugadores a través de los ControlChannel correspondientes. Propaga el mensaje FIPARTIT-ACK a los jugadores a través de los ControlChannel correspondientes. 5.2.3.2 Servidores Como se ha comentado en el punto anterior, el núcleo del módulo de control se encarga entre otras funciones de crear el conjunto de hilos que ejecutaran los procesos correspondientes a los servidores que sirven peticiones de control por el puerto TCP y peticiones de estado por el puerto UDP. Para implementar el servidor TCP, se ha usado la clase que crea objetos de tipo TCPServer de la librería utilizada en nuestro proyecto. Éste objeto implementa un servidor multi-hilo para comunicaciones basadas en el protocolo de transporte TCP. En la creación de éste objeto, se le proporciona la clase factoría correspondiente para la creación automática del gestor que se encargaría de procesar el flujo de información recibido en ésa comunicación. En éste caso se le proporciona la factoría ControlRequestHandlerFactory. Para implementar el servidor UDP, se ha desarrollado una clase que crea objetos de tipo StateUDPServer, a imagen del comportamiento proporcionado por la clase TCPServer para el caso anterior. Éste objeto implementa un servidor multi-hilo para 17 comunicaciones basadas en el protocolo de transporte UDP. En la creación de éste objeto, se le proporciona la clase factoría correspondiente para la creación automática del gestor que se encargaría de procesar los mensajes recibidos por éste canal. En éste caso se le proporciona la factoría StateRequestHandlerFactory. En la siguiente tabla se puede observar la relación de métodos públicos que ofrece el objeto StateUDPServer: Método StateUDPServer ~StateUDPServer start stop port Descripción Crea un StateUDPServer usando el DatagramSocket (UDP) proporcionado por parámetro. El servidor usa la factoría StateRequestHandlerFactory proporcionada por parámetro para crear los gestores para los mensajes de estado. Destruye el StateUDPServer y el StateUDPServerDispatcher que genera en la creación del objeto. Arranca el servidor. Para el servidor. Retorna el puerto por el que el servidor escucha. Adicionalmente se ha desarrollado una clase que implementa el proceso de distribución o deliberación de mensajes a los diferentes hilos de ejecución del servidor multi-hilo. Ésta clase es una clase auxiliar de la anterior y que hemos llamado StateUDPServerDispatcher. En la siguiente tabla se puede observar la relación de métodos públicos que ofrece el objeto StateUDPServerDispatcher: Método StateUDPServerDispatcher ~StateUDPServerDispatcher duplicate release run enqueue stop Descripción Crea un StateUDPServerDispatcher Destruye un StateUDPServerDispatcher Incrementa el contador de referencias al objeto. Decrementa el contador de referencias al objeto y borra el objeto si el contador llega a 0. Ejecuta el dispatcher. Encola el mensaje para ser deliberado por el dispatcher Para el dispatcher. 5.2.3.3 Gestores Para procesar la información proporcionada por los mensajes del protocolo de comunicación en los diferentes canales de estado y control, se han implementado una serie de gestores que realizaran las acciones que correspondan en función de la información contenida en dichos mensajes. Éstos objetos gestores serán creados por los objetos factoría que se han proporcionado a los objetos servidores descritos en el punto anterior. Hay que destacar que cada objeto gestor corresponde a un hilo de ejecución independiente, de tal forma que durante el transcurso de una partida tendremos, en el caso del servidor, un gestor para las conexiones establecidas en el puerto TCP del servidor, dos gestores para las conexiones establecidas para cada uno de los jugadores y n-gestores para el proceso de los mensajes de estado UDP que se crearan y destruirán en función de las necesidades de proceso del servidor. 18 Adicionalmente también se podria destacar que la implementación hecha de todos los gestores intenta corregir en la medida de lo posible los errores que se puedan producir durante el juego. Éstos errores pueden venir prococados por: - El envio en un instante del flujo de mensajes de un mensaje que no corresponde con el estado en el que está la aplicación, por ejemplo, una vez conectados dos jugadores ser recibe la petición de recepción de un tercer jugador, o la recepción de un mensaje de reanudación del juego (XIULET) cuando éste está parado, etc. Todas éstas situaciones se solucionan mediante el envio de mensajes de confirmación negativa. - El envio de valores ilegales en los mensajes de estado, por ejemplo, que algun jugador establezca valors de velocidad mayores de los permitidos en las reglas definidas por la simulación física que efectua el servidor. Para solucionarlo, se ha relajado el protocolo de tal forma que en lugar de descartar el mensaje y, por tanto, alterar la percepción del juego, se ha decidido aceptar los mensajes pero corrigiendo el valor para que esté dentro del rango válido. És decir, si la velocidad lineal máxima permitida es de 50 mm/s, si se recibe un valor de 300 mm/s se corrige y se considera que el valor correcto es de 50 mm/s. El objeto correspondiente al gestor de las conexiones establecidas contra el puerto TCP del servidor es el ControlRequestHandler. Éste se encargará exclusivamente de servir las peticiones correspondientes a los mensajes CONNECTA del protocolo de comunicación, a los que contestará con el CONNECTA-ACK si la conexión se ha establecido correctamente, es decir, si el módulo de control considera aceptar la unión a la partida por parte del servidor, o contestará con el NACK si la conexión no se puede establecer, es decir, si el módulo de control considera que el jugador no se puede conectar. En la siguiente tabla se puede observar la relación de métodos públicos que ofrece el objeto ControlRequestHandler: Método ControlRequestHandler run Descripción Crea un ControlRequestHandler Ejecuta el gestor de peticiones de control. El objeto correspondiente al gestor del canal de control, se asuma el rol que se asuma, es el ControlChannel. Éste se encargará de mantener el flujo de mensajes de control con cada uno de los extremos: si se ejecuta como servidor los extremos son ambos jugadores y si se ejecuta como cliente los extremos es el servidor en el que se simula la partida. El flujo de mensajes corresponde al resto de mensajes de control definidos en la especificación del protocolo de comunicación, que en resumen son todos aquellos que impliquen información de estado inicial con el mensaje ESTATINI, interrupciones de juego generadas des de los jugadores con los mensajes GOL, FALTA, FIPART y FIPARTIT y las interrupciones propagadas desde el servidor a los jugadores con los mensajes GOL-ACK, FALTA-ACK, FIPART-ACK y FIPARTIT-ACK. Se mantendrá una comunicación entre el canal de control y el módulo de control para informar en los dos sentidos éstos eventos. En la siguiente tabla se puede observar la relación de métodos públicos que ofrece el objeto ControlChannel: Método ControlChannel Descripción Crea un ControlChannel. Almacena las referencias al módulo de control, con el que se comunicará para notificar los eventos, y del objeto GameData, del que 19 sendMessage stop obtendrá la información necesaria para seguir el control del canal. En función del rol asumido en la creación del objeto actuará como canal de control de cliente o de servidor. Envía por el canal de control el mensaje proporcionado por parámetro. Para el canal de control. El objetos correspondiente al gestor del canal de estado, se asuma el rol que se asuma, es el StateRequestHandler. Éste se encargará de gestionar los mensajes recibidos por el puerto UDP, es decir, si se actúa como servidor gestionará los mensajes con los que los jugadores informaran al servidor sobre que movimientos se ordenan a los robots, y si se actuá como cliente gestionará los mensajes con los que el servidor, después del proceso de simulación informará a ambos jugadores sobre el estado de la partida, que en definitiva serán la posiciones de la pelota y los jugadores después de aplicar los movimientos ordenados por cada módulo de inteligencia artificial. En la siguiente tabla se puede observar la relación de métodos públicos que ofrece el objeto StateRequestHandler: Método StateRequestHandler ~StateRequestHandler run start Descripción Crea un StateRequestHandler. Destruye un StateRequestHandler. Ejecuta el gestor de peticiones de estado. Arranca el gestor de peticiones de estado. Los tres gestores definidos utilizan las clases auxiliares definidas en un apartado posterior para garantizar que los mensajes recibidos y los mensajes generados para el envío cumplen las especificaciones del protocolo de comunicación definido en la oficina técnica. 5.2.3.4 Factorías Para que los objetos servidores puedan crear los objetos gestores, se han implementado dos clases que se encargaran de generar estos gestores de forma dinámica. Éstos objetos son el ControlRequestHandlerFactory, encargado de crear a los gestores de las peticiones de control enviadas contra el puerto TCP del servidor, y el StateRequestHandlerFactory, encargado de crear a los gestores de las peticiones de estado enviadas contra los puertos UDP. Ambas clases son utilizadas exclusivamente por los objetos servidores, por lo que se podrían catalogar como auxiliares de éstas. En la siguiente tabla se puede observar la relación de métodos públicos que ofrece el objeto ControlRequestHandlerFactory: Método ControlRequestHandlerFactory createConnection Descripción Crea un ControlRequestHandlerFactory. Crea un ControlRequestHandler pasándole como parámetro el StreamSocket asociado al canal. Retorna un puntero a éste nuevo gestor. En la siguiente tabla se puede observar la relación de métodos públicos que ofrece el objeto StateRequestHandlerFactory: 20 Método StateRequestHandlerFactory createHandler Descripción Crea un StateRequestHandlerFactory. Crea un StateRequestHandler pasándole como parámetro el mensaje que deberá procesar. Retorna un puntero a éste nuevo gestor. 5.2.3.5 Reloj En la especificación del protocolo de comunicación, se establece una recomendación sobre la frecuencia con la que se deberían enviar los mensajes sobre el canal de estado, es decir, los mensajes de movimientos en el caso de los jugadores y los mensajes de estado en cado del servidor. Se ha implementado un reloj mediante el objeto StateTimer que permite la ejecución de una función de retrollamada que se encargará de los envíos de los mensajes correspondientes con el rol con el que se esté ejecutando la aplicación cada cierto número constante de milisegundos. En la siguiente tabla se puede observar la relación de métodos públicos que ofrece el objeto StateTimer: Método StateTimer onTimer Descripción Crea un StateTimer. Almacenara la referencia al objeto GameData pasado por parámetro del que obtendrá la información para generar los mensajes de estado. Función de callback a ejecutar a cada tic de reloj. Se encargará del envío de los mensajes. 5.2.3.6 Auxiliares Así mismo, gran parte de los objetos anteriores así como el módulo de control necesitan de una serie de funcionalidades que debería proporcionar el módulo de comunicaciones y que no tienen sentido dentro de uno de los objetos anteriores. Por tanto se implementan un total de cuatro clases auxiliares para proporcionar éstas funcionalidades, que en resumen son las funciones correspondientes a la validación del formato de los mensajes y la generación de los mensajes a enviar, siempre respetando las especificaciones del protocolo de comunicación definido. De forma general, el formato se valida mediate la comparación de los mensajes con expresiones regulares, método que nos da la flexibilidad para definir reglas que deben cumplir los mensajes de forma eficiente y que posteriormente nos garantizará la validación también de los valores contenidos en los mensajes. Éste método de validación lo proporcionan las clases RegularExpression de la librería utilizada en éste proyecto. La primera de las clases auxiliares corresponde al ControlRequest, encargado de validar el formato y generar los mensajes con el formato correcto correspondientes a los mensajes de petición de control, es decir, los mensajes que se envían desde los jugadores al servidor: CONNECTA, INICI, GOL, FALTA, FIPART, FIPARTIT y XIULET. En la siguiente tabla se puede observar la relación de métodos públicos que ofrece el objeto ControlRequest: Método matchFormat Descripción Retorna cierto si el mensaje pasado como parámetro cumple las especificaciones del protocolo. Retorna 21 buildConnectaMessage buildIniciMessage buildFaltaMessage falso en cualquier otro caso. Retorna el mensaje CONNECTA formateado con la información adicional pasada por parámetros. Retorna el mensaje INICI formateado con la información adicional pasada por parámetros. Retorna el mensaje FALTA formateado con la información adicional pasada por parámetros. La segunda de las clases auxiliares corresponde al ControlResponse, encargado de validar el formato y generar los mensajes con el formato correcto correspondientes a los mensajes de respuesta de control, es decir, los mensajes que se envían desde el servidor a los jugadores: CONNECTA-ACK, INICI, GOL-ACK, FALTA-ACK, FIPART-ACK, y FIPARTIT-ACK. En la siguiente tabla se puede observar la relación de métodos públicos que ofrece el objeto ControlResponse: Método matchFormat buildConnectaAckMessage buildEstatIniMessage buildGolAckMessage buildFaltaAckMessage Descripción Retorna cierto si el mensaje pasado como parámetro cumple las especificaciones del protocolo. Retorna falso en cualquier otro caso. Retorna el mensaje CONNECTA-ACK formateado con la información adicional pasada por parámetros. Retorna el mensaje ESTATINI formateado con la información adicional pasada por parámetros. Retorna el mensaje GOL-ACK formateado con la información adicional pasada por parámetros. Retorna el mensaje FALTA-ACK formateado con la información adicional pasada por parámetros. La tercera de las clases auxiliares corresponde al StateRequest, encargado de validar el formato y generar los mensajes con el formato correcto correspondientes a los mensajes de petición de estado, es decir, los mensajes que se envían desde los jugadores al servidor. En la siguiente tabla se puede observar la relación de métodos públicos que ofrece el objeto StateRequest: Método buildMovementMessage Descripción Retorna el mensaje de movimiento formateado con la información adicional pasada por parámetros. La cuarta de las clases auxiliares corresponde al StateResponse, encargado de validar el formato y generar los mensajes con el formato correcto correspondientes a los mensajes de petición de estado, es decir, los mensajes que se envían desde el servidor a los jugadores. En la siguiente tabla se puede observar la relación de métodos públicos que ofrece el objeto StateResponse: Método buildStateMessage Descripción Retorna el mensaje de estado formateado con la información adicional pasada por parámetros. 22 5.2.4 Modificaciones sobre el protocolo Durante el proceso de implementación del proyecto se detectaron una serie de disfuncionalidades en la especificación del protocolo de comunicaciones. Estas disfuncionalidades han sido solucionadas mediante la modificación de la especificación de acuerdo con los compañeros de otros grupos. Las disfuncionalidades son: - En el flujo de mensajes correspondiente al envío desde el servidor al jugador de los mensajes de CONNECTA-ACK y ESTATINI se puede dar el hecho que se reciban los dos en un solo paquete, de tal forma que para la aplicación sea difícil separarlos de una forma eficiente. Para solucionarlo se decide terminar los mensajes añadiendo el carácter ‘$’, de tal forma que se usará el carácter ‘\n’ para separar líneas dentro de un mismo mensaje y el carácter ‘$’ para separar diferentes mensajes. - La especificación original no permite el envío de velocidades lineales y angulares negativas, por lo que los robots no podrán retroceder ni girar en sentido horario. Para solucionarlo se modifican los formatos de los mensajes en los que se incluye ésta información para aceptar el carácter ‘‘ delante del valor. 5.3 Módulo de Inteligencia Artificial 5.3.1 Introducción El módulo de Inteligencia Artificial se encarga de crear y establecer el comportamiento de los robots en la aplicación, con el objetivo final de simular una inteligencia tal que permita al jugador ganar el partido. Siguiendo el diseño de nuestra aplicación, este módulo pertenece exclusivamente al cliente. A partir de los diferentes datos referentes al partido que envía el servidor periódicamente, como las posiciones de los robots o sus velocidades, la Inteligencia Artificial estima los movimientos que debería realizar cada uno de los robots del jugador. Dichos movimientos serán enviados a una velocidad constante al servidor mediante el módulo de control y el de comunicaciones, el cual calculará el efecto que tienen sobre el campo mediante una física simulada. En un principio se estableció en las sesiones de la oficina técnica que los parámetros sobre los que trabajaría este módulo serían la fuerza lineal y la fuerza angular, sin embargo más adelante se decidió substituirlos por la velocidad lineal y la velocidad angular para así facilitar los cálculos. Si tratamos con robots reales y no con los simulados de la Fira Middle League Simurosoft, éstos suelen moverse mediante dos ruedas situadas en la parte izquierda y derecha del robot que pueden avanzar hacía adelante o hacía atrás. Se puede realizar una transformación entre la velocidad de cada rueda y los parámetros que calcula la Inteligencia Artificial: vl = (vi + vd ) , va = (vi − vd ) 2 L Donde L es la distancia entre cada rueda. 5.3.2 Diseño Hemos realizado el diseño del módulo de Inteligencia Artificial teniendo en cuenta el objetivo a conseguir, que no es otro que ganar en un partido de fútbol entre robots. Para ello es necesario que, como sucede en la vida real con jugadores humanos de 23 este deporte, los robots sean capaces de actuar en tiempo real tanto individual como colectivamente ante los estímulos que reciban del mundo exterior. De los diversos sistemas de Inteligencia Artificial, un sistema de multiagentes resulta especialmente adecuado ya que cumple con los requisitos de la aplicación. La base de todo sistema multiagente son los agentes. Un agente inteligente es un proceso computacional capaz de realizar tareas de forma autónoma y que se comunica con otros agentes para resolver problemas mediante cooperación, coordinación y negociación. Los agentes habitan en un entorno complejo y dinámico con el cual interaccionan en tiempo real para conseguir un conjunto de objetivos, en nuestro caso, derrotar al rival en un partido de fútbol de robots. Los agentes presentan una serie de características que resultan muy adecuadas para una aplicación de este tipo, como son la reactividad, la capacidad de reaccionar en tiempo real a los cambios en su entorno, la autonomía, pues un agente es capaz de actuar por su cuenta, la comunicación, pues en el caso de que un solo agente no puede realizar una tarea puede ser llevado a cabo por varios que trabajen conjuntamente, y el razonamiento, pues son capaces de tomar decisiones. En conclusión, Así pues, cada robot será un agente distinto, teniendo dos tipos de agentes claramente diferenciados según su funcionalidad: el portero y el jugador. El rol de portero lo llevará a cabo el robot que juega en dicha posición, teniendo así pues un comportamiento defensivo: su principal objetivo será proteger la portería. El rol de jugador es asumido por el resto de robots quiénes actuarán de forma ofensiva o defensiva según la situación, es decir, según los datos sobre el estado de juego que periódicamente recibimos del servidor. 5.3.2.1 Comportamiento de los agentes Los dos tipos de agentes, portero y jugador, tienen comportamientos claramente diferenciados, según los roles ya comentados anteriormente. Cada agente tomará sus propias decisiones y actuará por su cuenta o en combinación con sus compañeros si es necesario, según el estado del campo del juego. A continuación se detalla el comportamiento de los dos tipos de agente, indicando las acciones que realizan según las diferentes circunstancias en las que se puede encontrar durante el partido. Comportamiento del agente: Portero 1. Nuestro equipo tiene la posesión a. El portero controla el balón. i. Si es posible realiza un pase a un compañero, pasa a un compañero y protege el centro de la portería ii. Si no, es posible, despeja el balón b. El portero no controla el balón i. Proteger el centro de la portería 2. Nuestro equipo no tiene la posesión a. Defender Portería El objetivo de este agente es simple, como el de los porteros reales: evitar que los robots rivales marquen goles. Para ello evita realizar acciones arriesgadas, tomando siempre la decisión más segura de cara a minimizar las posibilidades de poner en peligro su portería. Un resumen breve y conciso de las diferentes acciones que puede adoptar éste agente es el siguiente: - Pasar: Pasa al jugador desmarcado situado en una posición más avanzada. - Despejar: Despeja el balón a una posición libre. 24 - Proteger el centro de la portería: Se sitúa en el centro de la portería. Defender Portería: Protege la portería de los tiros de los robots rivales. Comportamiento del agente: Jugador 1. Nuestro equipo tiene la Posesión a. El jugador controla el balón i. El jugador está desmarcado 1. Si puede tirar a puerta, tira a puerta 2. Si no, avanza hacía la portería rival ii. El jugador está marcado 1. Si puede pasar, pasa 2. Si no, despeja el balón b. El jugador no controla el balón i. Si el jugador es un Delantero, se desmarca ii. Si no, realiza una defensa especulativa 2. Nuestro equipo no tiene la Posesión a. Jugador está cerca del balón i. Intenta recuperarlo b. Jugador no está cerca del balón i. Jugador es el defensa más retrasado 1. Defiende la portería ii. Jugador no es el defensa más retrasado 1. Si puede cubrir un pase, cubre el pase 2. Si no, defiende la portería El comportamiento del agente jugador resulta más complejo que el del portero, ya que realiza tantos aspectos defensivos como ofensivos y es capaz de realizar un número de acciones considerablemente superior. Su objetivo es, básicamente, participar en el ataque ya sea directamente o apoyando al jugador con el balón, o defendiendo la portería cuando ésta se encuentra en peligro. Debido a este hecho este agente necesita conocer el estado del juego con una mayor precisión. Como en el caso anterior, explicamos brevemente las diferentes acciones que puede realizar este agente: - Tirar a puerta: Realiza un tiro a la portería rival. - Avanzar a portería rival: Avanza con el balón hacía la portería rival. - Pasar: Idéntico al agente Portero. - Despejar: Idéntico al agente Portero. - Desmarcarse: Se sitúa en una posición desde la que pueda recibir un pase sin ser interceptado por los robots rivales. - Defensa especulativa: Avanza lentamente mientras cubre posibles pases a robots rivales. - Recuperar el balón: Avanza hacía el balón para recuperarlo. - Defender portería: Retrocede a defender la portería. - Cubrir pase: Se sitúa cubriendo el pase a un jugador rival. 5.3.2.2 Algoritmo de encaminamiento Debido a los estrictos requisitos en cuanto a los tiempos de respuesta, consideramos más adecuada implementar una estrategia reactiva que no una que lleve a cabo grandes planificaciones de trayectorias que tarden mucho tiempo en obtener resultados, lo que llevaría a que el módulo obtuviese resultados para estados de juego pasados, y por tanto, no válidas. 1. Estamos en la posición deseada a. Si no estamos en la orientación adecuada, corregirla 25 2. No estamos en la posición deseada a. Si existe una trayectoria sin obstáculos hacia el punto, realizar dicha trayectoria b. Si no existe, dirigirse hacia el punto más cercano posible sin obstáculos c. Si no existe dicho punto, tomar una dirección sin obstáculos Mediante este algoritmo un robot puede acceder a cualquier punto del campo del juego, siempre y cuando exista una trayectoria desde su posición. Si se encuentra rodeado de obstáculos, permanecerá inmóvil a la espera de que cambie la situación. 5.3.3 Implementación Se utilizan los hilos que proporciona la librería POCO C++ para implementar el sistema de agentes. De esta manera, cada agente se ejecuta en un hilo independiente de manera concurrente y separada al del resto de agentes, tal como deseamos para cumplir los requisitos de la aplicación. Estos hilos son creados cuando el cliente se conecta al servidor y mientras el partido no acabe calculan las velocidades que debe tomar cada robot. Los distintos objetos generados y utilizados para este módulo pueden agruparse según su funcionalidad, siendo los siguientes: - IA: Ésta es el único objeto visible desde fuera del módulo. Se encarga de crear los agentes, inicializar sus hilos y destruirlos una vez se ha acabado el partido. - Agentes: Corresponde a las objetos Agentes, Jugador y Portero. Estas dos últimos implementan el comportamiento de los agentes de mismo nombre, heredando del objeto Agente los comportamientos comunes a ambos. - Mensajes: Los agentes se comunican entre sí dejándose mensajes en buzones implementados mediante este objeto. - Campo: Este objeto contiene una referencia a los datos globales de la aplicación, entre ellos las posiciones de la pelota y los robots de ambos equipos, así como sus velocidades. Implementa las diversas funciones matemáticas necesarias para calcular trayectorias de robots, detectar colisiones entre ellos y demás. Así pues, es accedido por los agentes para consultar el estado del juego Resulta especialmente interesante analizar con más profundidad el objeto Campo, pues es de vital importancia para el correcto funcionamiento de la Inteligencia Artificial, pues permite a los agentes tanto ser conscientes de su entorno como razonar cual es la mejor opción que pueden tomar entre las disponibles. A continuación mostramos la lista de métodos públicos que son accedidos desde los objetos Agentes, clasificándolos según su funcionalidad. Respecto a la reacción ante el entorno, los siguientes métodos son utilizados por los objetos agentes para consultar el estado del campo de juego y así poder reaccionar adecuadamente ante ellos. Informan de la situación del robot en relación a sus compañeros, rivales y balón. Método DetrasBalon getPosesion ControlaBalon Delantero Desmarcado CercaBalon Descripción Retorna cierto Retorna cierto posesión. Retorna cierto Retorna cierto delantero. Retorna cierto Retorna cierto si el jugador esta detrás del balón. si nuestro equipo tiene el balón en si el jugador controla el balón. si el jugador está en posición de si el jugador esta desmarcado. si el jugador esta cerca del balón. 26 UltimoDefensa getCampoBalon getCampoPlay Retorna cierto si el jugador es el defensa más retrasado de su equipo. Retorna cierto si el balón esta en el campo. Retorna 1 si jugamos en el campo izquierdo, 2 si jugamos en el campo derecho. Respecto a los cálculos matemáticos, todos los cálculos matemáticos necesarios para establecer las trayectorias de movimiento, detectar futuras colisiones así como evitarlas son implementados por el objeto Campo utilizando el lenguaje C++ sin usar librerías adicionales. Método BalonPeligroso TrayectoriaBalon TrayectoriaLibre TrayectoriaLibrePuntos TrayectoriaOrientacion TrayectoriaAzar TiroLibre AvanzarPorteria RetrocederPorteria DistanciaPJ DistanciaJPorteria getPosDespeje Descripción Retorna cierto si el balon es peligroso para nuestra porteria. Retorna cierto si el jugador puede interponerse en la trayectoria del balon. Retorna cierto si entre los dos jugadores se puede realizar un pase sin que sea interceptado. Retorna 0 si existe una trayectoria libre entre un jugador y un punto,1 si existe a la espalda del jugador,2 si no existe. Calcula con que orientacion podemos llegar a la posicion deseada.Devuelve la orientacion o -1 si no encuentra ninguna.detras es cierto si la trayectoria esta a la espalda del robot. Calcula una trayectoria al azar libre de obstaculos y que no se acerque a los limites del campo. back es true si la trayectoria esta a la espalda del robot. Retorna cierto si se puede realizar un buen tiro a la porteria enemiga. El jugador avanza a la porteria rival. salx y saly puntos a los que debe ir. El jugador retrocede a defender su porteria. salx y saly puntos a los que debe ir. Retorna la distancia entre dos puntos. Retorna la distancia de un punto a la porteria. xd e yd es el punto al cual debe despejar el pase. 5.4 Módulo de Gráficos 5.4.1 Introducción El módulo gráfico se encarga de todo lo que se refiere a visualización e interacción con el cliente. Como especificaciones iniciales se pedía que fuera en tres dimensiones y que permitiera cambios de vista. Se debería poder ver el juego desde una perspectiva cenital y desde la vista subjetiva de cada jugador. A parte de estas especificaciones iniciales también se ha de tener en cuenta el diseño de la interfaz de usuario, que sea manejable y sencilla. Para todo ello se ha utilizado un estilo de "videojuego" alejado de los típicos esquemas de ventanas de los sistemas operativos. De esta manera nuestro producto se desmarca del resto dando un aspecto mucho menos técnico pero igual de efectivo. Al ser la parte gráfica se deseaba que al usuario le llamase la atención. También se han tenido en cuenta posibles configuraciones de la máquina sobre la que ha de correr la aplicación. Esto se 27 puede solucionar gracias al motor utilizado, OGRE, que nos permite seleccionar las características básicas que deseamos en nuestra visualización. 5.4.2 Diseño El diseño de este módulo se puede dividir en dos partes. El diseño de objetos que utilizamos y el diseño de la programación 3d. 5.4.2.1 Diseño de objetos Esta parte del diseño hace referencia a muchos elementos que mostramos por pantalla ya que en nuestro desarrollo no generamos todos los objetos desde código. Para ello se diseñan los objetos más importantes que necesitamos con otras herramientas.Para empezar se realizan dos objetos que representan los robots que vemos por pantalla. Se han generado con 3d Studio y se han exportado a archivos mesh, formato que utiliza Ogre 3D. A estos objetos se le unen texturas realizadas con Gimp y scripts de los materiales que utilizaremos. También se realiza el diseño del campo siguiendo los parámetros especificados en los documentos de análisis. 5.4.2.2 Diseño de la programación 3D Una vez tenemos todos los componentes necesarios pasamos a describir la estructura del módulos. Al no realizar ninguna otra tarea que visualización y interficie gráfica, se puede realizar un modelo Vista-Control. Se diseña una clase principal llamada GameManager. Esta clase implementa una interficie que nos sirve para comunicarnos con el módulo de control y deriva de otras que harán que reaccione a todos los eventos de teclado y ratón, también es la encargada de cumplir todas las especificaciones para poder utilizar Ogre. Como veremos se encarga de todo el control gráfico gracias a una pila de GameStates encargada de redirigir la entrada a la clase GameState que se encuentre en el top. Así podemos hacer independientes los diferentes estados del módulo gráfico únicamente teniendo en cuenta que al entrar en un estado hay que crearlo todo como si no existiera nada previamente y al salir de un estado limpiar todo lo que se haya hecho. Una vez inicializada la clase GameManager lo que hace es apilar el primer estado IntroState que nos muestra la primera pantalla, reaccionando a los diferentes eventos podremos "navegar" por los distintos estados de juego realizando la interacción adecuada. Aquí se nos muestra la estructuración de las clases más importantes de este modulo y la relación entre ellas: 28 5.4.3 Implementación Una vez realizado el diseño modular la implementación se simplifica al poder comprobar cada estado por separado. Durante la implementación también se añaden a la estructura todas aquellas funciones que atienden eventos y se generan mediante código la interfaz de usuario. Como cada estado tiene sus propios eventos, cada uno 29 de ellos los atiende de forma independiente, así que la modularidad sigue intacta. También se añaden las llamadas necesarias al control. Para ello se referencia una clase del tipo ControlCore a la que se le llamarán las funciones necesarias. Se perdemos un poco de modularidad al hacer que la clase GameManager tenga que llamar funciones de unos GameStates específicos, pero la idea base sigue intacta. Además se configuran todos los archivos necesarios para el funcionamiento de OGRE. Así pues después de la implementación el sistema sigue el mismo patrón que el diseñado. La clase GameManager es la que realiza todas las operaciones de entrada y salida, redirigiendo estas al GameState activo. Estos GameStates trabajan de maneras distintas y se pueden explicar cada uno de ellos por separado: - IntroState: presenta la pantalla inicial, reaccionando a los botones mostrados y cambiando de GameState según el botón al que reaccione. Así pues si pulsamos "Créditos" iremos al GameState CreditsState, si pulsamos "Ayuda" iremos a AyudaState, si pulsamos "Unir a partida" nos dirigimos al UnirState y si pulsamos "Salir" cerraremos la aplicación. Todos estos eventos son controlados por los diferentes "handlers" de la clase. Cada uno de ellos hace referencia a un botón. Como se puede apreciar en el desarrollo de todo el módulo todas las funciones "handler" van seguidas del nombre del botón al que hacen referencia. - CreditsState: Muestra los créditos y al pulsar Aceptar vuelve al estado IntroState. - AyudaState: Muestra la ayuda en la aplicación. - UnirState: Este estado es el encargado de recoger la información de conexión y de parte de la visualización que tendremos durante el partido. Es el primero, en una ejecución normal de la aplicación, que utiliza el control para comunicarse con el resto de módulos cuando el usuario ordena conectarse. Una vez se ha hecho la conexión pasa al siguiente estado, PlayState, al ser avisado mediante la función gfxEstatIni(). - PlayState: es el estado encargado de cargar todos los elementos 3d diseñados y leer la información necesaria del estado del juego para mostrarla por pantalla. Es el más importante y crítico de todos. Como el resto reacciona por si mismo a los eventos necesarios. Además reacciona a muchos de los eventos generados por el control a la interfaz gráfica y a cada frame actualiza todo la información de pantalla. Gracias a la estructuración de OGRE en forma de árbol nos permite cambiar la cámara de posición ajustándola a las especificaciones y simplifica el posicionamiento de los robots y la pelota haciendo que estos elementos dependan del nodo campo. - PauseState: este estado se utiliza sobre el estado PlayState para desactivar todos los controles del anterior aunque lo podamos ver. Tiene un único botón que avisa al módulo de control del deseo de iniciar el partido. 6 Resultados 6.1.1 Módulo de Comunicaciones Para comprobar el correcto funcionamiento y validar el módulo de comunicaciones se ha desarrollado una aplicación de texto, que hemos nombrado TikitakaServerTestUnit, que emula el comportamiento del cliente gráfico, en éste cliente de texto se ha implementado una pequeña línea de comandos (shell) en la que poder ordenar las mismas acciones que se ordenarían desde el cliente gráfico a la vez que permite ver el flujo de mensajes. Adicionalmente, en el módulo de comunicaciones se ha implementado un sistema de registro (logging) personalizable mediante el fichero de configuración correspondiente que permite almacenar en fichero o mostrar en pantalla los mensajes 30 de error o de información durante el transcurso de una conversación entre el cliente y el servidor con el intercambio de mensajes especificados en el protocolo de comunicación. Así pues, para validar la implementación se han emulado múltiples partidas usando la implementación del servidor TikitakaServer con el sistema de registro activado en modo trace, dos clientes TikitatakaServerTestUnit también con el sistema de registro activado en modo trace, y ejecutando diversas combinaciones de órdenes que pudieran provocar un funcionamiento erróneo de la aplicación. En todos los casos, la simulación ha sido satisfactoria, aportando una implementación completamente determinista, robusta y estable del módulo de comunicaciones. 31 Anexos A Manual de usuario Este es el manual de usuario de “Tikitaka” el simulador de la FIRA middle league. A.1 Instalación Ejecute Tikitaka-setup.exe y siga las instrucciones. A.2 Uso Este software se divide en dos partes. Primero explicaremos la parte del servidor ya que es necesaria para que la parte del cliente funcione en su totalidad. A.2.1 Servidor Para hacer funcionar funcionar simplemente tiene que ejecutar el programa “TitakaServer.exe”. Este se encargará automáticamente de los procesos necesarios. Abrirá el puerto 10000 para recibir conexiones de los software cliente. Para que los clientes puedan conectarse solo han de saber la IP del ordenador en el que se encuentra el servidor. Cuando quiera detenerlo simplemente tiene que presionar Ctrl+c. A.2.2 Cliente La parte del cliente consta de los controles necesarios para que el jugador se conecte a cualquier servidor de juego del mismo tipo que el creado en esta aplicación. Cuando arranque la aplicación podrá ver las siguientes pantallas. A.2.2.1 Inicio En esta pantalla podemos ver los siguientes botones que actúan de la siguiente manera: 32 - Unirse a partida: Nos permitirá conectarnos a un servidor para poder jugar. Ayuda: Nos muestra un pequeño tutorial que nos recuerda como utilizar la aplicación. Créditos: Muestra el equipo que ha hecho posible este producto. Salir: Termina el juego. A.2.2.2 Unirse a partida Aquí podemos indicar donde nos queremos conectar y los nombres de los equipos. Cuando haya introducido los datos necesarios, dirección IP del servidor, puerto que utilizaremos para recibir información y el nombre de los equipos, podemos “Conectar”. Esta conexión preparará el inicio del juego. En caso de no querer siempre podemos volver “Atrás”. A.2.2.3 Iniciar el juego 33 Una vez conectados se nos mostrará una pantalla como la siguiente. Cuando quiera que empiece el juego clique Iniciar. Una vez que los dos jugadores hayan iniciado, que empiece el partido!! A.2.2.4 Durante el partido Durante el partido podrá ver el avance de este. Los jugadores que muestra la aplicación con banda amarilla son el equipo controlado por el cliente que utiliza, mientras que los que tienen una banda azul son los del contrario. Como puede apreciar se puede interactuar con la aplicación mediante los botones que aparecen y desaparecen o activan y desactivan. A continuación tiene una lista de los botones existentes y la utilidad de cada uno cada uno. En la zona destinada al arbitro y de arriba a abajo tenemos: - Goal: Marca un gol. Este gol subirá al marcador del equipo contrario al campo donde se encuentre el balón. - Free Ball: Se pita una falta de tipo Free Ball. Como no se indica equipo esta falta se lanzará en el punto de cuarto de campo más cercano. - Half Time: Se indica la media parte del partido. - End Game: Se finaliza el partido. En la zona destinada al equipo propio: - Penalty: Penalty en contra de nuestro equipo. - Free Kick: Se señala una falta del tipo Free Kick en contra nuestra. - Free Ball: Este Free Ball se lanzara desde el punto de cuarto más cercano al balon en nuestro campo. En la zona destinada al equipo propio: - Penalty: Se pita un penalti en contra del equipo contrario. - Free Kick: Free Kick a nuestro favor. - Free Ball: Free Ball que se lanzará en el punto de cuarto más cercano al balón en el campo contrario. 34 A.2.2.5 Xiulet Siempre que se pare el juego aparecerá un texto indicativo de porque y aparecerá un botón “Xiulet” con el que se puede indicar la reanudación del partido. A.2.2.6 Selección de Cámara Con esta lista usted puede elegir desde que cámara quiere ver la acción. La cámara seleccionada aparece con fondo amarillo. Puede seleccionar una cámara cenital o la correspondiente a lo que ve cada jugador. A.2.2.7 Cronómetro Puede ver como avanza el juego y mediante el crono situado en la parte superior derecha, junto a la parte del partido que se está disputando, saber en que momento se encuentra. En cualquier momento puede ver el marcador del partido situado en la parte superior central. A.2.2.8 Fin del partido Una vez el arbitro indique el final del partido usted podrá ver una pantalla como la siguiente: En ella se indica el marcador final así como el resultado del encuentro. También aparece un botón Aceptar que le conducirá a la pantalla de inicio. Y aquí finaliza el manual de la aplicación. Esperamos que les sea de utilidad. B Referencias - POCO C++ Libraries – http://www.appinf.com/poco/info/index.html OGRE3D: Open Source Graphics Engine – http://www.ogre3d.org/ 35 C Oficina Técnica C.1 Sesión 2 de Febrero Ordre - del dia: Física del joc. Arquitectura en xarxa. Mòduls. Acords: - La pilota i els jugadors només tenen 2 graus de llibertat, o sigui només es poden moure en el pla, i no poden xutar. - Els graus de llibertat del robot seran: o força lineal. o força angular. - S'utilitzaran llibreries físiques externes per a la simulació dels moviments i les interaccions. En la propera reunió es presentaran diferents alternatives i se'n votarà una. - En el joc multijugador, un ordinador farà de servidor i l'altre de client. El servidor serà l'encarregat de calcular els estats del joc (llibreria física) a partir de les dades que rebrà de la IA del client i de la seva pròpia IA. - S'annexa una imatge amb el diagrama general de comunicacions. - En cas que en el moment d'executar-se la física el servidor no hagi rebut moviments del client, usarà els últims moviments que havia rebut d'aquest. - El missatge d'estat estarà compost per 11 registres cada un dels quals constarà de: o Id o Posició o angle d'orientació o velocitat lineal o velocitat angular - El missatge de moviments constarà de 5 registres cada un dels quals constarà de: o Id o força lineal o força angular - Per unanimitat s'ha decidit que el missatge d'estat no inclogui informació sobre les forces aplicades. - Per normativa del joc, el servidor no podrà utilitzar la última acceleració coneguda del client per tal de calcular la seva IA. - El codi font de l'aplicació estarà disponible per als altres grups una vegada hagi acabat el desenvolupament. C.2 Sesión 8 de Febrero Acuerdos: - Libreria fisica : Cada grupo usara la libreria que quiera. - Libreria grafica: Cada grupo usara la libreria que quiera. - Parametros de la fisica: 36 - CAMPO : Fregamiento (sin perdida de energia en el rebote) PELOTA : Massa ROBOT : Massa, Fuerza Maxima ( Fuerza Lineal + Fuerza Angular) Unidad Metrica : velocidad* : mm/s fuerza* : mN posicion*: mm orientacio*/../velocitat angular : 0..360º Sin decimales(enteros) Sistema de coordenada : adjunto fichero PROTOCOL XARXA: - Se ha decidido crear dos conexiones: o TCP para control de la partida. o UDP comunicacion fisica. o Puerto de conexion UDP/TCP es el 10000 - Protocolo inicio de partida : o El servido espera 4 conexiones ( 2 por cliente), 1ª conexion a s servidor, 2ª preparado para empezar la partida. o Posicion inicial de los jugadores: Posiciones fijas elegidas por el servidor. 2 posiciones : ataque ,defensa. o La partida se inicia en cuando los dos equipos esten preparados, sin tiempo de espera. CONEXION UDP (SERVER --> CLIENTE) Por acuerdo entre grupos: sprintf(miss,"%d \n", milis); sprintf(miss,"%d,d,%d,%d,%d,%d \n",id_jugador, pos_x,pos_y, vel_lineal,vel_angular); X 11 orientacion, CONEXION UDP (CLIENTE --> SERVIDOR) sprintf(miss,"%d.%d \n",milis,id); id--> del client. sprintf(miss,%d ,%d,%d \n",id_jugador,força_lineal, força_angular); %d id (client)--> 4 caracteres sin 0 delante 0..9999 %d del resto enteros de 32 bits. C.3 Sesión 9 de Febrero Modificaciones del acta anterior 1.- orientacio*/../velocitat angular : 0..359º 2.- Se elimina el id de jugador en los mensajes UDP CONEXION UDP (SERVER --> CLIENTE) Por acuerdo entre grupos: sprintf(miss,"%d\n", milis); sprintf(miss,"%d,%d,%d,%d,%d\n", pos_x,pos_y, orientacion, vel_lineal,vel_angular); X 11 Ejemplo: tttttt = timestamp de la partida en milisegundos. Máximo 6 carácteres. xxxx = pos_x yyyy = pos_y ooo = orientación vl = velocidad lineal va = velocidad angular 37 tttttt\n <- timestamp xxxx,yyyy,ooo,vl,va\n xxxx,yyyy,ooo,vl,va\n xxxx,yyyy,ooo,vl,va\n xxxx,yyyy,ooo,vl,va\n xxxx,yyyy,ooo,vl,va\n xxxx,yyyy,ooo,vl,va\n xxxx,yyyy,ooo,vl,va\n xxxx,yyyy,ooo,vl,va\n xxxx,yyyy,ooo,vl,va\n xxxx,yyyy,ooo,vl,va\n xxxx,yyyy,ooo,vl,va\n <<<<<<<<<<<- pelota portero izquierda jugador 1 jugador 2 jugador 3 jugador 4 portero derecha jugador 1 jugador 2 jugador 3 jugador 4 CONEXION UDP (CLIENTE --> SERVIDOR) sprintf(miss,"%d,%d\n",milis,id); id--> del client. sprintf(miss,%d,%d\n",força_lineal, força_angular); Ejemplo: iiii = identificador del cliente proporcionado por el servidor fl = fuerza lineal fa = fuerza angular tttttt,iiii\n fl,fa\n <- portero fl,fa\n <- jugador fl,fa\n <- jugador fl,fa\n <- jugador fl,fa\n <- jugador 1 2 3 4 3.- Se elimina la linea: %d del resto enteros de 32 bits. Acta del dia: Se han acordado los siguientes puntos: 1 .- Como base se utilizarán las reglas de juego definidas en el documento de marzo de 2006 2 .- Se elimina el Goal Kick. 3 .- No hay timeout. 4 .- El cronometro será mantenido por el servidor ( Modificación de la regla 3.3 ) 5 .- Las fuerzas angulares y lineales pueden ser negativas 6 .- Las posiciones iniciales y de faltas son fijas, y para todos los grupos iguales, y serán establecidas por el sevidor a los clientes. Queda por concretar cuales serán. 7 .- Se utiliza el identificador del cliente más bajo para decidir el primer atacante. De esto se encarga el servidor. Propuestas para la siguiente sesión: Concretar posiciones fijas Tener en cuenta o no las porterias en el eje de cordenadas para no tener números negativos. Para agilizar la definición de mensajes los responsables de comunicaciones podrian reunirse a parte. 38 C.4 Sesión 15 de Febrero 1.- Ordre del dia 1.1.- Concretar posicions fixes 1.2.- Replantejar origen eixos de coordenades (porteria esquerra, té valors negatius?) 1.3.- Definir protocol comunicacions en alt nivell 2.- Conceptes clarificats 2.1.- En indicar una posició d'algun robot o de la pilota, el valor (x,y) d'aquesta es refereix al centre de la figura geomètrica que el representa (quadrat i circumferència respectivament). 2.2.- Els robots poden entrar dins les porteries. 3.- Acords 3.1.- Orientació dels robots: Els robots miren cap on apunta la fletxa segons aquesta imatge (van endavant si segueixen el sentit de la fletxa, i enrere en cas contrari): 3.2.- Les posicions fixes i corresponents orientacions dels jugadors per al sac inicial i els diferents tipus de faltes són les que hi ha representades en imatges al document “FIRA Middle League SimuroSot Game Rules (Mar 2006)”. Com que en les imatges no s'especifiquen valors exactes de les posicions, serà responsabilitat de cada grup donar uns valors numèrics raonables en els respectius servidors. 3.3.- Les línies del camp (que la normativa diu que són de 3 mm) també es consideren part del terreny de joc i per tant els robots les poden trepitjar, però no les poden sobrepassar (hi ha parets). 3.4.- L'origen dels eixos de coordinades queda fixats de forma que les posicions sempre siguin valors positius. Aquest punt és l'inferior esquerra del camp de joc, alineat verticalment amb la porteria i horitzontalment amb la banda inferior del camp: 39 3.5.- Quan l'arbitre pita una falta i fins que aquesta es treu, NO s'atura el cronòmetre. 3.6.- Les posicions dels jugadors i la pilota en els missatges UDP i TCP són sempre fixes i en aquest ordre: Pilota Jugador 1 (equip 1) Jugador 2 (equip 1) Jugador 3 (equip 1) Jugador 4 (equip 1) Jugador 5 (equip 1) Jugador 1 (equip 2) Jugador 2 (equip 2) Jugador 3 (equip 2) Jugador 4 (equip 2) Jugador 5 (equip 2) 3.7.- Protocol: connexió dels programes al servidor i inici del joc: El missatge ESTAT (que tindrà diferent contingut per a cada equip) conté els següents paràmetres -en aquest ordre-: Equip (int, p.ex 1 o 2) 40 Atacant (bool) Posicions x 11 (veure punt 3.6) En començar a rebre paquets UDP s'inicia la partida. 3.8.- Protocol de control: Format del missatge de GOL El missatge d'estat té el mateix format que al punt 3.7 3.9.- Protocol de control: Format del missatge de FALTA El missatge d'estat té el mateix format que al punt 3.7 41 3.10.- Protocol de control: Format del missatge de MITJA PART El missatge d'estat té el mateix format que al punt 3.7 3.11.- Protocol de control: Format del missatge de FI DE PARTIT El missatge d'estat té el mateix format que al punt 3.7 3.12.- S'ha acordat que farem servir els següents paràmetres de física en la configuració inicial (després de fer el CONNECT, el missatge ID a més de l'identificador d'equip passarà també aquests paràmetres, en aquest ordre), però es deixa per més endavant acordar els valors i/o rangs d'aquestos: - Pes robot - Pes pilota - Fregament amb el terra - Velocitat màxima angular - Velocitat màxima lineal - Força màxima angular - Força màxima lineal 42 C.5 Sesión 16 de Febrero Acords arribats: - Quan l'arbitre assenyala que hi ha hagut un gol, el servidor entendrà que el gol ha estat fet a la portaria la qual la pilota està més aprop en el moment de rebre el missatge - S'ha acordat també el protocol de comunicació que s'adjunta. Aquest protocol de comunicació és el que les diferents implementacions de la pràctica hauran de complir per tal de poder interactuar entre elles correctament. C.6 Fe de erratas 22 de Marzo Final del partit amb empat:: - En cas d'acabar el partit en empat, es considerarà aquest resultat com un resultat vàlid del partit sense necessitat de jugar temps de pròrroga o penals. - En cas de voler desempatar s'haurà de jugar una nova partida entre els dos equips. C.7 Aclaraciones 12 de Abril Els caps de grups presents a la tarda d'avui hem decidit els següents punts per aclarir alguns casos i facilitar el treball. - Existeix un cas no contemplat a l'actual definició de missatges, en cas de que l'arbitre xiuli un Free Ball sense ser falta de cap equip. Per solucionar-ho s'ha afegit al missatge de Free Ball l'opció d'equip 0 que indicarà aquest cas. Quan es xiula una falta d'aquest tipus el servidor decideix en quin quart del camp es xiulara, aquet quart ha de ser el més proper a la posició de la pilota. - Igualment si es xiula un Free Ball per part d'un equip, es treu al punt més proper del camp corresponent. Finalment per facilitar la feina s'ha decidit l'orientació inicial dels porters per tal de col·locar les cameres correctament si es vol. Els porters s'han d'orientar de la següent manera (veure fitxer adjunt) per tal de que tots parin amb la part esquerra. 43 C.8 Actualización especificaciones 20 de Abril Como ya se hablo el viernes pasado. se ha realizado el siguiente cambio en las especificaciones del proyecto: - En el protocolo de red los parámetros que les pasan los clientes al servidor se sustituyen la fuerza lineal y la angular por velocidad lineal y angular, respectivamente. - Se elimina la restricción de giro del 10% a velocidad máxima. - En los parámetros que les envian los clientes al servidor, con el fin de no modificar el protocolo, la fuerza lineal máxima y angular máxima se mantienen, aunque no sirvan para nada. Los cambios se han realizado para facilitar los cálculos de la IA. D Protocolo Simulador FIRA Middle League SimuroSot Protocol Simulador FIRA Middle League SimuroSot Sistemes Informàtics II '06/'07 Extracte Aquest document descriu els detalls de implementació del protocol de comunicació consensuat en les diferents reunions de oficina tècnica, que han de respectar les diferents implementacions del simulador de partits de futbol de robots proposat com a projecte en la assignatura Sistemes Informàtics II de la Enginyeria Informàtica de la Universitat Rovira i Virgili en el curs 2006/2007. Taula de Continguts 1. Protocol Client-Servidor 1.1 Interacció Client-Servidor TCP/IP 1.2 Interacció Client-Servidor UDP/IP 1.3 Interacció Client-Servidor TCP/IP 1.4 Interacció Client-Servidor TCP/IP 1.5 Interacció Client-Servidor TCP/IP 1.6 Interacció Client-Servidor TCP/IP 2. Especificació dels missatges 2.1 CONNECTA 2.2 CONNECTA-ACK 2.3 ESTATINI 2.4 INICI 2.5 ESTAT 2.6 MOVIMENT 2.7 GOL 2.8 GOL-ACK 2.9 XIULET 2.10 FALTA 2.11 FALTA-ACK 2.12 FIPART 2.13 FIPART-ACK 2.14 FIPARTIT 2.15 FIPARTIT-ACK 2.16 NACK - Registre a un joc Flux dades joc Interrupció joc per Gol Interrupció joc per Falta Finalització mitja part Finalització del joc 1. Protocol Client-Servidor 1. El servidor escoltarà peticions per dos ports: el 10000 TCP per als missatges de control i el 10000 UDP per als missatges de joc. 2. El client escoltarà per dos ports, un TCP (per rebre els missatges de control iniciats pel servidor) i un UDP (per rebre els missatges d'estat del joc) a lliure elecció, que en la fase de registre a un partit, comunicarà al servidor per a que aquest li pugui enviar els missatges de 44 estat del joc. 3. Es recomanació que el servidor enviï els missatges d'estat del joc a raó de 1 estat cada 40ms (o de 25 estats per segon). 4. El protocol està basat en missatges de text. 1.1 Interacció Client-Servidor TCP/IP - Registre a una joc 1. El client envia un missatge CONNECTA al servidor. El missatge contindrà el Port (TCP i UDP) que farà servir el client on el servidor enviarà els missatges de control (TCP) i els d'estat durant el joc (UDP). 2. El servidor envia un missatge CONNECTA-ACK al client. El missatge contindrà el Id (número aleatori entre de 0x0 a 0xFFF que assigna el servidor al client per identificar-ne posteriorment els missatges UDP de moviment) i els paràmetres de la física: FLM (força lineal màxima), FAM (força angular màxima), PR (pes robot), PP (pes pilota), FT (fregament terra), VLM (velocitat lineal màxima) i VAM (velocitat angular màxima). Si el servidor no pot atendre satisfactòriament al missatge CONNECTA (ex: ja hi han dos client connectats, el joc està en un estat en el que no s'espera un CONNECTA, etc), el servidor contestarà al client amb un missatge NACK i s'atura la interacció. En aquest moment el client està connectat al servidor. Quan el servidor rebi les CONNECTA de dos clients, reanudarà el flux de missatges: 3. El servidor envia un missatge ESTATINI al client. El missatge contindrà el Equip (número entre 1 i 2, més endavant es veu el significat), el Atacant (número entre 0 i 1, indicant si el client comença el joc com atacant o defensor), 11 x Posició (posició d'inici de joc de la pilota i dels 10 robots jugadors, és a dir, 0 = pilota, 1-5 = jugadors equip amb el codi Equip 1, 6-10 = jugadors equip amb el codi Equip 2). 4. El client envia un missatge INICI al servidor. El missatge contindrà el Id assignat en el missatge CONNECTA-ACK. Indica que està preparat per començar el joc. En aquest moment s'inicia pel port UDP l'enviament dels paquets d'estat del joc i de moviments de jugadors. Exemple: Client Servidor Client v v v | | | |\ | _____________/| | \_________ |/ CONNECTA | | CONNECTA\ |\ | | \ | \____________ | | \ | CONNECTA-ACK\| | \| Espera | _____________/| . |/ CONNECTA-ACK | . Espera | . . /|\ . . ___________/ | \___________ . . / ESTATINI | ESTATINI \ . ./ | \. | | | .\_____________ | /. . INICI \| ____________/ . Espera |/ INICI . . | Espera 45 . Comença flux UDP . 1.2 Interacció Client-Servidor UDP/IP - Flux dades joc 1. El servidor envia un missatge ESTAT al client. El missatge contindrà el Cronòmetre (temps que es porta de joc en milisegons), 11 x Posició (posició en joc de la pilota i dels 10 robots jugadors, és a dir, 0 = pilota, 1-5 = jugadors equip amb el codi Equip 1, 6-10 = jugadors equip amb el codi Equip 2). 2. El client envia un missatge MOVIMENT al servidor. El missatge contindrà 5 x Moviment (forces lineals i angulars de cada un dels robots jugadors). Exemple: Client Servidor Client v v v | /|\ | | ___________/ | \___________ | | / ESTAT | ESTAT \ | |/ | \| | | | |\_____________ | /| | MOVIMENT \| ____________/ | | |/ MOVIMENT | | | | 1.3 Interacció Client-Servidor TCP/IP - Interrupció joc per Gol 1. El client envia un missatge GOL al servidor. 2. El servidor envia un missatge GOL-ACK als clients. El missatge contindrà l'Equip (codi Equip que ha marcat el gol), Marcador (resultat del partit en aquest moment, indicant gols equip 1 - gols equip 2). Si el servidor no pot atendre satisfactòriament al missatge GOL (ex: no hi ha joc en curs, el joc està en un estat en el que no s'espera un GOL-ACK, etc), el servidor contestarà al client amb un missatge NACK i s'atura la interacció. En aquest moment el joc està aturat, tot i que el cronòmetre continua, i per tant el servidor descarta qualsevol paquet que arribi al port UDP i els clients queden a la espera de la reanudació del joc. 3. El servidor envia un missatge ESTATINI al client. El missatge contindrà el Equip (número entre 1 i 2, més endavant es veu el significat), el Atacant (número entre 0 i 1, indicant si el client comença el joc com atacant o defensor), 11 x Posició (posició d'inici de joc de la pilota i dels 10 robots jugadors, és a dir, 0 = pilota, 1-5 = jugadors equip amb el codi Equip 1, 6-10 = jugadors equip amb el codi Equip 2). 4. El client envia un missatge XIULET al servidor. En aquest moment es reanuda pel port UDP l'enviament dels paquets d'estat del joc i de moviments de jugadors. Exemple: Client Àrbitre Servidor v v | | |\ | | \___________ | | GOL \ | | \| Client v | | | | | 46 | _____________/|\_____________ | |/ GOL-ACK | GOL-ACK \| Espera | Espera . /|\ . . ___________/ | \___________ . . / ESTATINI | ESTATINI \ . ./ | \. Espera | | . | /. Àrbitre . | ____________/ . . |/ XIULET . . | . . Comença flux UDP . 1.4 Interacció Client-Servidor TCP/IP - Interrupció joc per Falta 1. El client envia un missatge FALTA al servidor. 2. El servidor envia un missatge FALTA-ACK als clients. El missatge contindrà l'Equip (codi Equip al qui se li ha xiulat la falta) i el Tipus (tipus de falta comesa). Si el servidor no pot atendre satisfactòriament al missatge FALTA (ex: no hi ha joc en curs, el joc està en un estat en el que no s'espera un FALTA, etc), el servidor contestarà al client amb un missatge NACK i s'atura la interacció. En aquest moment el joc està aturat, tot i que el cronòmetre continua, i per tant el servidor descarta qualsevol paquet que arribi al port UDP i els clients queden a la espera de la reanudació del joc. 3. El servidor envia un missatge ESTATINI al client. El missatge contindrà el Equip (número entre 1 i 2, més endavant es veu el significat), el Atacant (número entre 0 i 1, indicant si el client comença el joc com atacant o defensor), 11 x Posició (posició d'inici de joc de la pilota i dels 10 robots jugadors, és a dir, 0 = pilota, 1-5 = jugadors equip amb el codi Equip 1, 6-10 = jugadors equip amb el codi Equip 2). 4. El client envia un missatge XIULET al servidor. En aquest moment es reanuda pel port UDP l'enviament dels paquets d'estat de joc i de moviments de jugadors. Exemple: Client Servidor Client v v v | | | Àrbitre |\ | | | \___________ | | | FALTA \ | | | \| | | _____________/|\_____________ | |/ FALTA-ACK | FALTA-ACK \| Espera | Espera . /|\ . . ___________/ | \___________ . . / ESTATINI | ESTATINI \ . ./ | \. Espera | | . | /. Àrbitre . | ____________/ . . |/ XIULET . . | . . Comença flux UDP . 47 1.5 Interacció Client-Servidor TCP/IP - Finalització mitja part 1. El client envia un missatge FIPART al servidor. 2. El servidor envia un missatge FIPART-ACK als clients. Si el servidor no pot atendre satisfactòriament al missatge FIPART (ex: no hi ha joc en curs, el joc està en un estat en el que no s'espera un FIPART, etc), el servidor contestarà al client amb un missatge NACK i s'atura la interacció. En aquest moment el joc està aturat, i el cronòmetre de joc es posa a 0, per tant el servidor descarta qualsevol paquet que arribi al port UDP i els clients queden a la espera de la reanudació del joc. 3. El servidor envia un missatge ESTATINI al client. El missatge contindrà el Equip (número entre 1 i 2, més endavant es veu el significat), el Atacant (número entre 0 i 1, indicant si el client comença la part com atacant o defensor), 11 x Posició (posició d'inici de joc de la pilota i dels 10 robots jugadors, és a dir, 0 = pilota, 1-5 = jugadors equip amb el codi Equip 1, 6-10 = jugadors equip amb el codi Equip 2). 4. El client envia un missatge XIULET al servidor. En aquest moment es reanuda pel port UDP l'enviament dels paquets d'estat de joc i de moviments de jugadors. Exemple: Client Servidor Client v v v | | | Àrbitre |\ | | | \___________ | | | FIPART \ | | | \| | | _____________/|\_____________ | |/ FIPART-ACK | FIPART-ACK \| Espera | Espera . /|\ . . ___________/ | \___________ . . / ESTATINI | ESTATINI \ . ./ | \. Espera | | . | /. Àrbitre . | ____________/ . . |/ XIULET . . | . . Comença flux UDP . 1.6 Interacció Client-Servidor TCP/IP - Finalització de joc 1. El client envia un missatge FIPARTIT al servidor. 2. El servidor envia un missatge FIPARTIT-ACK als clients. Si el servidor no pot atendre satisfactòriament al missatge FIPARTIDA (ex: no hi ha joc en curs, el joc està en un estat en el que no s'espera un FIPARTIT, etc), el servidor contestarà al client amb un missatge NACK i s'atura la interacció. En aquest moment el joc està aturat, i el cronòmetre continua es posa a 0, per tant el servidor descarta qualsevol paquet que arribi al port UDP i els clients queden a la espera de la reanudació del joc. 48 3. El servidor envia un missatge ESTATINI al client. El missatge contindrà el Equip (número entre 1 i 2, més endavant es veu el significat), el Atacant (número entre 0 i 1, indicant si el client comença la part com atacant o defensor), 11 x Posició (posició d'inici de joc de la pilota i dels 10 robots jugadors, és a dir, 0 = pilota, 1-5 = jugadors equip amb el codi Equip 1, 6-10 = jugadors equip amb el codi Equip 2). 4. El client envia un missatge XIULET al servidor. En aquest moment es reanuda pel port UDP l'enviament dels paquets d'estat de joc i de moviments de jugadors. Exemple: Client Servidor Client v v v | | | Àrbitre |\ | | | \___________ | | | FIPART \ | | | \| | | _____________/|\_____________ | |/ FIPART-ACK | FIPART-ACK \| | | | 2. Especificació dels missatges 2.1 CONNECTA Descripció: Flux: Transport: Interacció: Petició de connexió Del client al servidor TCP/IP 1.1 +----------+ |CONNECTA\n| |Port: p | +----------+ on p = número de fins a 4 xifres sense zeros davant i codificat en hexadecimal amb les lletres en majúscules 2.2 CONNECTA-ACK Descripció: Flux: Transport: Interacció: Confirmació d'una petició de connexió Del servidor al client TCP/IP 1.1 +--------------+ |CONNECTA-ACK\n| |Id: iii\n | |FLM: flm\n | |FAM: fam\n | |PR: pr\n | |PP: pp\n | |FT: ft\n | |VLM: vlm\n | |VAM: vam | +--------------+ on iii = número de fins a 3 xifres sense zeros davant i codificat en hexadecimal amb les lletres en majúscules flm, fam, pr, pp, ft, vlm i vam = número sense zeros davant i codificat en hexadecimal amb les lletres en majúscules 49 2.3 ESTATINI Descripció: Flux: Transport: Interacció: Estat inicial Del servidor al client TCP/IP 1.1, 1.3 +-------------------+ |ESTATINI\n | |Equip: e\n | |Atancant: a\n | |xxx,yyy,ooo,vl,va\n| |xxx,yyy,ooo,vl,va\n| |xxx,yyy,ooo,vl,va\n| |xxx,yyy,ooo,vl,va\n| |xxx,yyy,ooo,vl,va\n| |xxx,yyy,ooo,vl,va\n| |xxx,yyy,ooo,vl,va\n| |xxx,yyy,ooo,vl,va\n| |xxx,yyy,ooo,vl,va\n| |xxx,yyy,ooo,vl,va\n| |xxx,yyy,ooo,vl,va | +-------------------+ on e a xxx yyy ooo vl va <- pilota <- porter equip 1 <jugador 1 equip 1 <jugador 2 equip 1 <jugador 3 equip 1 <jugador 4 equip 1 <- porter equip 2 <jugador 1 equip 2 <jugador 2 equip 2 <jugador 3 equip 2 <jugador 4 equip 2 = número, 1 ó 2 = número, 0 = no atacant, 1 = atacant = pos_x (0 .. 2499), número de fins a 3 xifres sense zeros davant i codificat en hexadecimal amb les lletres en majúscules = pos_y (0 .. 1799), número de fins a 3 xifres sense zeros davant i codificat en hexadecimal amb les lletres en majúscules = orientació (0 .. 359), número de fins a 3 xifres sense zeros davant i codificat en hexadecimal amb les lletres en majúscules = velocitat lineal, valor absolut de la velocitat lineal, número sense zeros davant i codificat en hexadecimal amb les lletres en majúscules = velocitat angular, valor absolut de la velocitat angular, número sense zeros davant i codificat en hexadecimal amb les lletres en majúscules 2.4 INICI Descripció: Flux: Transport: Interacció: Indica preparat per iniciar el joc Del client al servidor TCP/IP 1.1 +-------+ |INICI\n| |Id: iii| +-------+ on iii = número de fins a 3 xifres sense zeros davant i codificat en hexadecimal amb les lletres en majúscules 2.5 ESTAT Descripció: Flux: Transport: Interacció: Mostra l'estat d'un joc en un instant de temps concret Del servidor al client UDP/IP 1.2 +-------------------+ |tttt\n | |xxx,yyy,ooo,vl,va\n| |xxx,yyy,ooo,vl,va\n| |xxx,yyy,ooo,vl,va\n| |xxx,yyy,ooo,vl,va\n| <- pilota <- porter equip 1 <jugador 1 equip 1 <jugador 2 equip 1 50 |xxx,yyy,ooo,vl,va\n| |xxx,yyy,ooo,vl,va\n| |xxx,yyy,ooo,vl,va\n| |xxx,yyy,ooo,vl,va\n| |xxx,yyy,ooo,vl,va\n| |xxx,yyy,ooo,vl,va\n| |xxx,yyy,ooo,vl,va | +-------------------+ <jugador 3 equip <jugador 4 equip <- porter equip 2 <jugador 1 equip <jugador 2 equip <jugador 3 equip <jugador 4 equip 1 1 2 2 2 2 on tttt = cronòmetre, temps de joc en milisegons, número de fins a 4 xifres sense zeros davant i codificat en hexadecimal amb les lletres en majúscules xxx = pos_x (0 .. 2499), número de fins a 3 xifres sense zeros davant i codificat en hexadecimal amb les lletres en majúscules yyy = pos_y (0 .. 1799), número de fins a 3 xifres sense zeros davant i codificat en hexadecimal amb les lletres en majúscules ooo = orientació (0 .. 359), número de fins a 3 xifres sense zeros davant i codificat en hexadecimal amb les lletres en majúscules vl = velocitat lineal, valor absolut de la velocitat lineal, número sense zeros davant i codificat en hexadecimal amb les lletres en majúscules va = velocitat angular, valor absolut de la velocitat angular, número sense zeros davant i codificat en hexadecimal amb les lletres en majúscules 2.6 MOVIMENT Descripció: Flux: Transport: Interacció: Accions de moviment aplicats als robots jugadors Del client al servidor UDP/IP 1.2 +----------+ |tttt,iii\n| |fl,fa\n | |fl,fa\n | |fl,fa\n | |fl,fa\n | |fl,fa | +----------+ <- porter <jugador <jugador <jugador <jugador 1 2 3 4 on tttt = segell de temps de l'últim missatge de ESTAT rebut, número de fins a 4 xifres sense zeros davant i codificat en hexadecimal amb les lletres en majúscules iii = número de fins a 3 xifres sense zeros davant i codificat en hexadecimal amb les lletres en majúscules fl, fa = números sense zeros davant in codificat en hexadecimal amb les lletres en majúscules 2.7 GOL Descripció: Flux: Transport: Interacció: L'àrbitre indica gol Del client al servidor TCP/IP 1.3 +---+ |GOL| +---+ 2.8 GOL-ACK Descripció: Flux: Transport: Interacció: Confirmació missatge de l'àrbitre indicant gol Del servidor al client TCP/IP 1.3 51 +-------------+ |GOL-ACK\n | |Marcador: g-g| +-------------+ on g = gols equip 1, caràcter '-', gols equip 2, números sense zeros davant i codificat en hexadecimal amb les lletres en majúscules 2.9 XIULET Descripció: Flux: Transport: Interacció: L'àrbitre indica reanudar el joc Del client al servidor TCP/IP 1.3, 1.4 +------+ |XIULET| +------+ 2.10 FALTA Descripció: Flux: Transport: Interacció: L'àrbitre indica falta Del client al servidor TCP/IP 1.4 +----------+ |FALTA\n | |Equip: e\n| |Tipus: t | +----------+ on e t = número, 1 ó 2 = número, 0 = Penalty, 1 = Free-Kick, 2 = Free-Ball 2.11 FALTA-ACK Descripció: Flux: Transport: Interacció: Confirmació missatge de l'àrbitre indicant falta Del servidor al client TCP/IP 1.4 +-----------+ |FALTA-ACK\n| |Equip: e\n | |Tipus: t | +-----------+ on e t = número, 1 ó 2 = número, 0 = Penalty, 1 = Free-Kick, 2 = Free-Ball 2.12 FIPART Descripció: Flux: Transport: Interacció: L'àrbitre indica fi de la primera part Del client al servidor TCP/IP 1.5 +------+ |FIPART| +------+ 2.13 FIPART-ACK Descripció: Flux: Transport: Confirmació missatge de l'àrbitre indica fi de la primera part Del servidor al client TCP/IP 52 Interacció: 1.5 +----------+ |FIPART-ACK| +----------+ 2.14 FIPARTIT Descripció: Flux: Transport: Interacció: L'àrbitre indica fi del joc Del client al servidor TCP/IP 1.6 +--------+ |FIPARTIT| +--------+ 2.15 FIPARTIT-ACK Descripció: Flux: Transport: Interacció: Confirmació missatge de l'àrbitre indica fi de joc Del servidor al client TCP/IP 1.6 +------------+ |FIPARTIT-ACK| +------------+ 2.16 NACK Descripció: Flux: Transport: Interacció: Confirmació negativa a un missatge de control Del servidor al client TCP/IP 1.1, 1.3, 1.4, 1.5 +----+ |NACK| +----+ 53