Programación I Práctica septiembre: el juego de los barquitos III En esta práctica tendréis que implementar una nueva variante del juego de los barquitos o “hundir la flota” para dos jugadores. Para ello vamos a introducir varias modificaciones al juego que se implementó en la práctica final. En primer lugar cambia la forma en que se hace un disparo, introduciéndose el concepto de “disparo desviado” que se explicará más abajo, lo cual también afecta al formato del fichero de disparos y resultados. En segundo lugar se introducen nuevas estadísticas. Se incluyen en rojo los cambios respecto a la versión de diciembre. Ficheros de barcos y disparos Cada jugador tendrá un panel de 10x10 casillas donde se situarán sus barcos. La disposición de los barcos de cada jugador deberá leerse respectivamente de los ficheros barcos1.txt y barcos2.txt, según el formato que se describirá más abajo. En este caso hay un número fijo de barcos, de diferentes tipos según su tamaño: - 2 submarinos (barcos de 1 casilla) 3 fragatas (barcos de 2 casillas) 3 destructores (barcos de 3 casillas) 2 acorazados (barcos de 4 casillas) 1 portaviones (barco de 5 casillas) Para identificar el tipo utilizaremos la inicial en mayúsculas (por ejemplo ‘F’ para fragatas). Además, cada barco concreto tiene un nombre para poder identificarlo. Dicho nombre consta de la inicial del tipo y un número del 1 al 3 (por ejemplo “F2”). Los disparos de cada jugador también están pre-generados y deberán leerse respectivamente de los ficheros disparos1.txt y disparos2.txt. Nótese que para esta práctica se ha introducido el concepto de “disparo desviado”. El formato también se describirá más abajo. Formato del fichero de barcos Cada barco se representa mediante una línea del fichero de la siguiente manera: t x y d Donde: - t es un carácter que indica el tipo de barco - x e y determinan la casilla en la que se sitúa una esquina del barco. x es una letra que indica la fila (de ‘A’ a ‘J’) e y un número que indica la columna (de 1 a 10) - d es un carácter que indica la dirección en que situamos el barco a partir de la casilla anterior: ‘a’ hacia arriba, ‘b’ hacia abajo, ‘i’ hacia la izquierda, ‘d’ hacia la derecha - cada uno de los elementos están separados por un único espacio en blanco - al final del barco hay un único carácter de salto de línea (‘\n’) no hay ningún espacio en blanco ni antes del tipo ni después de la dirección El nombre de cada barco se determina por orden. Así, el primer destructor que aparece en el fichero será el “D1”, el segundo el “D2” y el tercero el “D3”. Podéis suponer que el fichero está bien construido, siguiendo el formato adecuado, que contiene todos los barcos del juego y que las posiciones y direcciones están introducidas sin errores. No es necesario, por tanto, introducir un control de errores. Formato del fichero de disparos Mientras que en las versiones anteriores cada línea de este fichero contenía una casilla sobre la que se hacía cada disparo, ahora cada disparo puede ser aleatoriamente desviado. En el fichero de disparos aparecerá, además de una casilla, un rango de filas y columnas que determinan un área donde ese disparo puede caer (a esa área le llamaremos “área de desvío”). Así, cada disparo se representa mediante una línea del fichero de la siguiente manera: x y rx ry Donde: - x es una letra que indica la fila (de ‘A’ a ‘J’) - y es un número que indica la columna (de 1 a 10) - rx y ry son dos números enteros que determinan el área de desvío, es decir, indican el rango en el que puede caer el disparo aleatoriamente desviado - hay un único espacio en blanco entre ellos y un salto de línea al final - no hay ningún espacio en blanco ni antes de la x ni después de la ry Y donde el orden de aparición en el fichero determina el orden en que se realizan los disparos. Veamos un ejemplo de una fila del fichero de disparos: D432 Esto indica que el disparo inicialmente apuntaba a la casilla D4 (casilla en rojo), pero que puede desviarse hasta 3 casillas arriba o abajo y hasta 2 casillas a la izquierda o la derecha (área verde, incluyendo la casilla roja): 1 2 3 4 5 6 7 8 9 10 A B C D E F G H I J Para determinar en qué casilla exactamente cae el disparo se generará un número aleatorio entre -rx y rx y otro entre -ry y ry. En la página web de la asignatura se incluirá una función para generar números aleatorios. Como ejemplo, consideremos que los números generados son -1 y 2. En este caso, el disparo finalmente caería sobre la casilla con fila C (ya que hemos restado 1) y columna 6 (ya que hemos sumado 2). Nótese que dependiendo de los rangos rx y ry, el disparo podría caer fuera del tablero. Por ejemplo, si la fila del fichero fuera D455 Y los números generados aleatoriamente son -5 y -5, vemos que el disparo caería fuera del tablero. En tal caso se generará un nuevo número aleatorio y así sucesivamente hasta que se genere un disparo dentro del tablero. Por otra parte, nótese también que puede ocurrir que un disparo caiga sobre una casilla sobre la que ya se había disparado. Incluso podría ocurrir que en todo el rango aleatorio, todas las casillas ya hayan sido disparadas y por tanto que ese disparo no pueda realizarse. Por ello, antes de generar los números aleatorios, el programa deberá comprobar si hay alguna casilla no disparada dentro del área de desvío (determinado por rx y ry. Si no hay ninguna el juego acaba automáticamente sin ganador. Si la hay, se procederá a generar la pareja de números aleatorios hasta que se consiga un disparo correcto (que caiga dentro del tablero y sobre una casilla no disparada previamente). El fichero contendrá 100 disparos (100 líneas). Podéis suponer que el fichero está bien construido, siguiendo el formato adecuado. No es necesario, por tanto, introducir un control de errores. Dinámica del juego Comenzando por el jugador 1, los jugadores irán haciendo alternativamente los disparos en el orden que figura en los ficheros disparos1.txt y disparos2.txt. El juego acaba en el momento en que ocurre una de las siguientes circunstacias: - uno de los jugadores consiga destruir la flota del adversario - uno de los dos jugadores ya no puede hacer su disparo porque todas las casillas en su área de desvío ya han sido disparadas Presentación de los resultados Los resultados del programa se escribirán en dos ficheros de texto, uno que contendrá la secuencia de disparos de cada jugador y su resultado (resultados.txt), y otro con una serie de estadísticas que después se describen (estadisticas.txt). Estos dos ficheros se ajustarán al formato que se indica más abajo. Fichero de resultados El programa debe generar la secuencia de resultados, siguiendo el siguiente formato para cada disparo (cada disparo en una línea diferente): j n x0 y0 x y r b Donde: - j es el número de jugador (1 ó 2) - n es el número de disparo del jugador (comenzando por 1 y como máximo 100) - x0 es una letra que indica la fila (de ‘A’ a ‘J’) a la que originalmente apuntaba el disparo (antes de ser desviado) - y0 es un número que indica la columna (de 1 a 10) a la que originalmente apuntaba el disparo (antes de ser desviado) - x es una letra que indica la fila (de ‘A’ a ‘J’) sobre la que finalmente se ha disparado - y es un número que indica la columna (de 1 a 10) sobre la que finalmente se ha disparado - r es un carácter que indica el resultado del disparo: o ‘A’ para agua o ‘T’ para tocado o ‘H’ para tocado y hundido o ‘D’ para tocado, hundido y flota destruida - b es una cadena de dos caracteres que contiene el nombre del barco que se ha tocado. Este datos sólo se rellena en el caso de acierto y no el caso de “agua”. El resultado de cada disparo aparecerá en una línea diferente (entre dos disparos hay un único carácter de salto de línea). Los diferentes elementos de una línea estarán separados por un único carácter en blanco. No debe haber ningún carácter ni antes del número de jugador, ni después del nombre del barco tocado (o después del resultado si el disparo no tocó ningún barco). Repetimos que una vez que un disparo produzca el fin del juego (flota destruida), o bien un jugador no pueda realizar disparos dentro de su área de desvío, ya no se deben procesar el resto de disparos. Fichero de estadísticas Una vez se haya acabado el juego (se haya destruido una de las dos flotas), se guardarán en este fichero una serie de datos y estadísticas relacionadas con el desarrollo de la partida que se enumeran a continuación. El formato en que deben escribirse se explica más abajo. 0) 1) 2) 3) 4) 5) 6) 7) 8) 9) Jugador ganador Porcentaje de aciertos del jugador 1 Porcentaje de aciertos del jugador 2 Porcentaje de fallos del jugador 1 Porcentaje de fallos del jugador 2 Longitud de la secuencia de aciertos más larga del jugador 1 Longitud de la secuencia de aciertos más larga del jugador 2 Longitud de la secuencia de fallos más larga del jugador 1 Longitud de la secuencia de fallos más larga del jugador 2 Nombre del barco más “resistente” del jugador 1 y número de disparos necesarios para hundirlo (ver explicación después). Entre el nombre y el número de disparos habrá un único espacio en blanco 10) Nombre del barco más “resistente” del jugador 2 y número de disparos necesarios para hundirlo (ver explicación después). Entre el nombre y el número de disparos habrá un único espacio en blanco 11) Tipo de barco más “resistente” del jugador 1 y número de disparos necesarios para hundir todos los barcos de ese tipo (ver explicación después). Entre el nombre y el número de disparos habrá un único espacio en blanco 12) Tipo de barco más “resistente” del jugador 2 y número de disparos necesarios para hundir todos los barcos de ese tipo (ver explicación después). Entre el nombre y el número de disparos habrá un único espacio en blanco Respecto a la estadística 0, jugador ganador, si se ha dado una situación de empate ya que no se puede realizar un disparo al estar todas las casillas de desvío ya ocupadas, en esta estadística se escribirá un ‘0’. Nótese que aciertos se consideran los disparos que tocan un barco, independientemente de si lo hunden o no, y fallos los disparos que caen al agua. Tened también en cuenta que los disparos después de que se destruya la flota no deben tenerse en cuenta para las estadísticas. El barco más resistente es aquel que ha costado más disparos en ser hundido. Es decir, el barco que ha pasado más número de disparos desde el primero que lo tocó hasta el que lo hundió. Por ejemplo, si el primer disparo que lo toca es el 10 y el barco se hunde en el 15, decimos que el barco ha resistido 6 disparos (del 10 al 15, ambos inclusive). Nótese que entre medias pueden haberse tocado otros barcos también. Aquí hay que hacer una aclaración respecto a las situaciones de empate por el hecho de no poder concluir un disparo con desvío: los barcos no hundidos en el momento de finalizar el juego no se contabilizan para la estadística. Además, en el improbable caso en que se acabe la partida sin ningún barco hundido, esta estadística se dejará en blanco (se escribirá el número seguido del carácter de salto de línea), ya que no ha habido ningún barco más resistente que los demás. En cuanto a las estadísticas 11 y 12, el tipo de barco más resistente es el tipo de barco para el que más disparos ha habido desde la primera vez que se tocó un barco de ese tipo hasta que se hundió el último de los barcos ese tipo. Nótese que mientras que un submarino concreto nunca podrá ser el barco más resistente en las estadísticas 9 y 10(*), (*) Aquí hay también que hacer una precisión: en realidad un submarino sí podría ser el barco más resistente en las estadísticas 9 y 10 en el caso en que se produzca un empate y al jugador sólo se le ha destruido un submarino. sí podría ocurrir que los submarinos fueran los barcos más resistentes en su conjunto (estadísticas 11 y 12). Además, de un modo similar a las estadísticas 9 y 10, en caso de empate sólo se tendrán en cuenta en las estadísticas 11 y 12 aquellos tipos de barco que hayan sido destruidos al completo (es decir, todos los barcos de un mismo tipo han de haber sido hundidos). En el caso en que ningún tipo de barco haya sido destruido, la estadística se dejará en blanco (se escribirá el número seguido del carácter de salto de línea). En cuanto al formato del fichero, cada una de las 13 estadísticas aparecerá en una línea diferente (separadas por un único carácter de fin de línea, ‘\n’). La estadística 0 se escribirá un único carácter, correspondiente al número del jugador que ha ganado (‘1’ o ‘2’), o bien ‘0’ en el caso de que el juego haya acabado sin ganador (en el caso en que un jugador no pueda realizar su disparo en el área de desvío). En las estadísticas 1 a 8, se seguirá el siguiente formato: n v Donde: - n es el número de estadística (del 1 al 8) - v es el valor (real o entero dependiendo del caso) de dicha estadística - entre el número y el valor hay un único espacio en blanco En las estadística 9 y 10 el formato es ligeramente diferente, ya que además hay que escribir el nombre del barco: n b v Donde: - n es el número de estadística (9 ó 10) - b es una cadena de dos caracteres que contiene el nombre del barco - v es el valor entero correspondiente al número de disparos necesarios para hundirlo - hay un único espacio en blanco entre los valores En las estadística 11 y 12 el formato es casi igual que el anterior: n b v Donde: - n es el número de estadística (9 ó 10) - b es un carácter que indica el tipo de barco (‘S’, ‘F’, ‘D’, ‘A’ o ‘P’) - v es el valor entero correspondiente al número de disparos necesarios para hundir todos los barcos de ese tipo - hay un único espacio en blanco entre los valores Documentación Además del correcto funcionamiento del programa, se valorará: - Estructuración en funciones (y facilidad para la reutilización) Documentación del código (y legibilidad) Así mismo, hay que entregar una memoria (documento en Word o RTF) en la que se incluya una explicación del funcionamiento general del código, y se justifiquen los tipos de datos y funciones utilizadas. Además, cada función debe ser descrita brevemente, especificando sus parámetros y valor retornado. Normas adicionales El uso de variables globales está prohibido. Sí pueden definirse constantes y tipos globales. Revisión de la práctica Los profesores pueden convocar a los alumnos a hacer una defensa de su práctica. En dicha defensa los alumnos deberán responder una serie de preguntas acerca de su práctica, tanto de la estructura como del código. La nota de la práctica quedará completamente condicionada al resultado de la defensa. Indicaciones para la entrega Esta práctica se realizará en parejas. Alternativamente puede realizarse individualmente, aunque eso no supondrá una mayor nota. Bajo ninguna circunstanciase permitirán grupos de más de dos alumnos. La fecha límite de entrega es el 2 de septiembre a las 12:00 del mediodía. Depositad la carpeta con vuestra memoria y código fuente, sin el ejecutable, (el nombre de la carpeta será vuestros nias, separados por un guión bajo, por ejemplo “12345_12346”) en la carpeta de vuestro grupo de práctica correspondiente (P11, P12, P13, P21 o P22), dentro de \\rec-c1au\public\FOLDERS\3371-3372\12406\alumnes\practica_setembre Si una vez copiada tenéis algún problema o tenéis que hacer algún cambio, volvedlo a copiar desde una carpeta nueva añadiendo "_b" al nombre, por ejemplo "12345_12346_b" Recordad que el compilador a utilizar es gcc, en Linux o en Cygwin. Los ficheros que no puedan compilarse con gcc no se corregirán y tendrán una nota de 0. Reiteramos que, para la evaluación, tan importante como el que el programa funcione es que esté bien estructurado en funciones y que sea legible y esté bien documentado. La nota de la práctica consta de dos partes: 50% ejecución y 50% de estructura y legibilidad (donde también se incluye la memoria). Es fundamental que los ficheros con los que trabajéis sigan los formatos y nombres que se detallan en este enunciado. La corrección de la parte de ejecución se realizará mediante un script automático. Si los formatos y nombres de ficheros no son correctos la parte de ejecución tendrá una nota de 0. El hecho de no cumplir cualquiera de los demás requerimientos (máximo de dos alumnos por grupo, poder compilar la práctica con gcc, prohibición del uso de variables globales y entrega de la memoria) supondrá un cero como nota de la práctica. Como es lógico, la copia está terminantemente prohibida, ya sea de todo o de parte del código o de la memoria. Además, os recordamos que la detección de una copia de trabajos ajenos conlleva el suspenso automático de la asignatura para todos los alumnos involucrados en la copia, además de la iniciación del consiguiente procedimiento disciplinario.