Programación 2 Curso 2015/2016 Práctica 1 Imperial Commander (parte 1) Esta práctica consiste en la realización de un programa que permita gestionar la flota de cazas imperiales que lleva un destructor imperial en sus bodegas. 1. 1.1. Normas generales Entrega 1. El último dı́a para entregar esta práctica es el viernes 26 de febrero, hasta las 23:59. No se admitirán entregas fuera de plazo. 2. La práctica debe tener sólo un fichero llamado “imperialCommander.cc”. 1.2. Detección de plagios/copias En el Grado en Ingenierı́a Informática, la Programación es una materia fundamental, que se aprende programando y haciendo las prácticas de las diferentes asignaturas (y otros programas, por supuesto). Si alguien pretende aprobar las asignaturas de programación sin programar (copiando), obviamente tendrá serios problemas en otras asignaturas o cuando intente trabajar. Concretamente, en Programación 2 es muy difı́cil que alguien que no ha hecho las prácticas supere el examen de teorı́a, por lo que copiar una práctica es una de las peores decisiones que se puede tomar. La práctica debe ser un trabajo original de la persona que la entrega; en caso de detectarse indicios de copia de una o más prácticas se suspenderá la asignatura a todos los alumnos implicados (tanto al que copia como al que se deja copiar), y se enviará un informe a la dirección de la EPS, para que se tomen las medidas disciplinarias oportunas. 1.3. Otras normas 1. La práctica se debe entregar exclusivamente a través del servidor de prácticas del departamento de Lenguajes y Sistemas Informáticos, al que se puede acceder desde la página principal del departamento ( www.dlsi.ua.es, “Entrega de prácticas”) o directamente en la url http://pracdlsi.dlsi. ua.es. No se admitirán entregas por otros medios (correo electrónico, Campus Virtual, etc.). El usuario y contraseña para entregar prácticas es el mismo que se utiliza en el Campus Virtual. La práctica se puede entregar varias veces, pero sólo se corregirá la última entrega (las anteriores entregas no se borran). 2 INTRODUCCIÓN 2 2. El programa debe poder ser compilado sin errores con el compilador de C++ existente en la distribución de Linux de los laboratorios de prácticas; si la práctica no se puede compilar su calificación será 0. Se recomienda compilar y probar la práctica con el autocorrector inmediatamente antes de entregarla. 3. La corrección de la práctica se hará de forma automática, por lo que es imprescindible respetar estrictamente los textos y los formatos de salida que se indican en este enunciado. 4. Al principio de todos los ficheros fuente entregados se debe incluir un comentario con el nombre y el NIF (o equivalente) de la persona que entrega la práctica, como en el siguiente ejemplo: // NIF 12345678X GARCIA GARCIA, JUAN MANUEL 5. El cálculo de la nota de la práctica y su influencia en la nota final de la asignatura se detallan en las transparencias de la presentación de la asignatura. 2. Introducción Esta práctica consiste en realizar un programa para ayudar al comandante de un destructor imperial a gestionar la flota de cazas imperiales del destructor en el transcurso de una batalla con una nave rebelde de similares caracterı́sticas. Podrá añadir más cazas, reparar y mejorar las caracterı́sticas de los cazas, y lanzar un caza a luchar contra un caza rebelde. En posteriores prácticas se añadirán más funcionalidades a este programa. 2.1. Caracterı́sticas de los cazas espaciales Tanto los cazas imperiales como los rebeldes tienen las siguientes caracterı́sticas: velocidad (velocity) : la velocidad máxima del caza ataque (attack ) : poder de ataque sobre otras naves escudo (shield ) : poder defensivo de los campos deflectores coste (cost) : coste en créditos del caza Los cazas imperiales, junto con los valores de sus caracterı́sticas son: Tipo TIE-Fighter TIE-Bomber TIE-Interceptor TIE-Advanced Abreviatura tf tb ti ta Velocity 150 80 180 160 Attack 75 150 65 80 Shield 30 45 30 90 Cost 45 75 55 95 Los cazas rebeldes son: Tipo X-Wing Y-Wing A-Wing B-Wing Abreviatura xw yw aw bw Velocity 175 90 200 120 Attack 90 150 60 200 Shield 75 90 50 90 Cost 65 90 45 100 En el destructor imperial solamente se puede almacenar 30 cazas, y el co- 3 FUNCIONAMIENTO DEL PROGRAMA 3 mandante dispone inicialmente de 2000 créditos en la caja fuerte del destructor para comprar cazas, o bien para reparar y mejorar los cazas disponibles. El programa debe almacenar también el número de victorias y derrotas del destructor en los combates que se produzcan. Cuando un caza imperial destruya al caza rebelde oponente, el Emperador recompensará automáticamente al comandante con el coste del caza rebelde destruido, que incrementará la cantidad de créditos disponible en la caja fuerte del destructor. La Alianza Rebelde recompensará de la misma manera al comandante de la nave rebelde enemiga. 3. Funcionamiento del programa Inicialmente, el programa debe crear e inicializar dos naves, el destructor imperial que gestionará el usuario, y una nave rebelde que gestionará el propio programa. En la sección de implementación se describe con más detalle los datos de cada nave: ambas naves partirán de la misma cantidad de créditos inicial, 2000 créditos, para comprar su dotación inicial de cazas, comprar más cazas, y para mejorarlos. cada una tendrá diferente capacidad según sea una nave imperial o una nave rebelde. Cada nave tendrá inicialmente una dotación de cazas que deben añadirse (en el orden que se indica) al crear la nave. El destructor imperial tendrá 10 TIE-Fighters, 5 TIE-Bombers, 5 TIE-Interceptors y 5 TIE-Advanced. La nave rebelde tendrá 10 X-Wing, 5 Y-Wing, 8 A-Wing y 5 B-Wing (véase la sección de implementación para más detalles acerca de cómo inicializar la dotación de cazas). Una vez creadas las naves e inicializadas (incluyendo las dotaciones de cazas iniciales), el programa debe mostrar el siguiente menú: 1- List ship info 2- Add fighters 3- Repair/improve fighter 4- Launch fighter 5- List enemy info q- Quit Option: La opción será siempre un único carácter, no es necesario comprobarlo (aunque irá seguido de un carácter de fin de lı́nea). Si el usuario introduce una opción incorrecta, el programa debe mostrar el mensaje de error UNKNOWN_OPTION (véase la sección de implementación para más detalles sobre los mensajes de error). Si el usuario elige la opción Quit, el programa terminará sin emitir ningún mensaje. Después de ejecutar alguna de las opciones (que pueden ir bien o generar algún error), el programa volverá a mostrar el menú. 3.1. Descripción de las opciones List ship info/List enemy info : en ambas opciones se debe mostrar la información de la nave correspondiente por pantalla (utilizando exactamente 3 FUNCIONAMIENTO DEL PROGRAMA 4 la misma función). Por ejemplo, al comenzar el programa la información del destructor imperial debe ser:1 Ship info: max. capacity=30, side=IMPERIAL, credits=425, wins=0, losses=0 [1] TIE-Fighter (v=150, a=75, s=30, c=45) [2] TIE-Fighter (v=150, a=75, s=30, c=45) ... [25] TIE-Advanced (v=160, a=80, s=90, c=95) En el caso del jugador rebelde, la cadena a mostrar después de “side=” será “REBEL”. Add fighters : en esta opción se añadirán uno o más cazas del mismo tipo al destructor imperial. Para ello, se debe pedir el tipo de caza, mostrando el siguiente mensaje: Enter fighter type (tf/tb/ti/ta): A continuación, si el tipo introducido por el usuario (una cadena) coincide con la abreviatura de alguno de los cazas definidos en la tabla de datos de cazas y es un caza imperial (en otro caso se mostrará por pantalla el mensaje de error WRONG_FIGHTER_TYPE y saldrá de la función, volviendo al menú), entonces se pedirá el número de cazas mostrando el siguiente mensaje: Number of fighters: Si el coste de los nuevos cazas es mayor que el número de créditos disponible en la caja fuerte de la nave, se mostrará el mensaje de error NO_FUNDS. Si los nuevos cazas caben en la nave (en otro caso se mostrará el error CAPACITY_EXCEEDED), se añadirán al final del vector de cazas de la nave, y se descontará su coste de los créditos de la caja fuerte. Repair/improve fighters : esta opción permite al comandante mejorar o reparar alguna de las caracterı́sticas de un caza. Para ello, se pedirá el número de caza a reparar o mejorar con el siguiente mensaje: Select fighter number: Si el número de caza es incorrecto se mostrará el error WRONG_NUMBER; si es correcto, se pedirá el aspecto a mejorar o reparar con el siguiente mensaje: What to improve (v/a/s)? Se leerá la opción elegida (un carácter, seguido de un carácter de retorno de carro), y, si es correcta (en caso contrario se emitirá el error UNKNOWN_OPTION y se saldrá de la función, volviendo a continuación al menú), se pedirá la cantidad en que se quiere aumentar ese aspecto mediante el mensaje: 1 Por brevedad, solamente se muestran los 2 primeros cazas y el último, pero la práctica debe mostrar todos los cazas. 3 FUNCIONAMIENTO DEL PROGRAMA 5 Amount: Una vez leı́da la cantidad c (se puede asumir que c será mayor o igual que cero, no es necesario comprobarlo), se calculará el coste de dicha mejora, que será: velocidad ataque escudo 2*c (2 créditos por unidad) 3*c (3 créditos por unidad) (c+1)/2 (1 crédito por 2 unidades, redondeo al alza) El coste de la mejora del escudo se redondea al alza porque en caso contrario las cantidades impares costarı́an lo mismo que la cantidad par inmediatamente inferior. En la implementación, la división debe ser entera (si los dos operandos son enteros, la división será entera). Si el coste no es mayor que los créditos disponibles en la caja fuerte de la nave (en otro caso se mostrará el error NO_FUNDS y se saldrá de la función), se mostrará el siguiente mensaje, y se pedirá confirmación: That will cost you <cost> credits. Confirm? (y/n) donde <cost> es el coste de la mejora. Si el usuario introduce el carácter “y”, se realizará la mejora en el caza, se incrementará el coste del caza, se restará el coste de los créditos de la caja fuerte, y se mostrará un mensaje como el del siguiente ejemplo (en el que se ha aumentado 20 unidades la velocidad de un TIE-Fighter): Fighter improved: TIE-Fighter (v=170, a=75, s=30, c=85) Si se introduce cualquier otro carácter (incluso “Y” o “s”) en la pregunta de confirmación, se entenderá que no se ha confirmado y por tanto no se realizará la mejora, y se saldrá de la función y se volverá al menú principal sin mostrar ningún mensaje. Launch fighter : en esta opción el comandante de la nave elige un caza de los que tiene disponibles en la nave y lo envı́a a combatir con otro caza de la nave enemiga. Antes de empezar el combate, se debe comprobar que ambas naves, la imperial y la rebelde, tienen al menos un caza. Si no es ası́, se emitirá el error NO_FIGHTERS y se volverá al menú. Una vez hecha esta comprobación, lo primero que se debe hacer es seleccionar el caza, mostrando el siguiente mensaje: Select fighter number: Si el número del caza es correcto (en caso contrario se emitirá el error WRONG_NUMBER y se saldrá de la función, volviendo al menú), se almacenará en una variable el caza elegido y se eliminará del vector de cazas. A continuación, se elegirá aleatoriamente un caza enemigo (generando un número al azar entre 0 y el número de cazas enemigos menos 1), y se eliminará también del vector de cazas de la nave enemiga, y comenzará la lucha 3 FUNCIONAMIENTO DEL PROGRAMA 6 entre los dos cazas. Antes de comenzar el combate se debe mostrar los dos cazas, con el mismo formato que en las opciones de 1 y 5 del menú (pero sin el número de caza), y al terminar también. El combate entre los dos cazas (el primero imperial y el segundo rebelde) se simula de la siguiente manera: 1. Se genera un número aleatorio n entre 0 y 99, 0 ≤ n ≤ 99 2. Si n es menor que 5 o mayor que 95, el combate termina (se simula que han intervenido otros cazas, o se ha alcanzado un campo de asteroides, o que alguno de los cazas se retira). 3. Se calcula qué caza acierta en su ataque al caza contrario, obteniendo un umbral u, que se calcula de la siguiente manera: u= 100v1 v1 + v2 donde v1 es la velocidad del primer caza, y v2 la del segundo. Si n es menor o igual que el umbral u, se supone que el caza que ha acertado es el primero (el caza imperial), en caso contrario el caza que ha acertado es el segundo. 4. Se calcula el daño d ocasionado al caza contrario, que se restará directamente de su escudo. La fórmula para calcular el daño es: d= (na1 )/f ((100 − n)a2 )/f si n ≤ u si n > u donde a1 es el ataque del primer caza, y a2 el del segundo. El valor f es una constante de valor 300. 5. Si el escudo de alguno de los cazas es 0 o negativo, el combate termina, y se considera que dicho caza ha sido destruido. Solamente puede resultar destruido uno de los dos cazas, no pueden destruirse los dos en el mismo combate. 6. Si ambos cazas tienen todavı́a un valor positivo en su escudo, el combate continua volviendo al paso 1. Por ejemplo, si al principio del programa se lanza el primer caza imperial de la nave (un TIE Fighter), la salida por pantalla deberı́a ser: -- begin fight TIE-Fighter (v=150, a=75, s=30, c=45) B-Wing (v=120, a=200, s=90, c=100) -TIE-Fighter (v=150, a=75, s=-4, c=45) B-Wing (v=120, a=200, s=81, c=100) -- end fight Cuando termine el combate, se actualizarán los datos de créditos (se sumará a cada nave el coste de los cazas enemigos destruidos), victorias y derrotas de las dos naves, y se devolverán los cazas supervivientes (puede ser uno o los dos) a su nave, añadiéndose al final del vector de cazas correspondiente. 4 IMPLEMENTACIÓN 4. 7 Implementación Para implementar la práctica debes tener en cuenta las siguientes observaciones: 1. En la web de la asignatura se publicarán varios ficheros: imperialCommander.cc : debes basarte en este fichero para realizar tu práctica. Puedes añadir más funciones y constantes si lo consideras necesario. Este fichero contiene lo siguiente: a) Tipos definidos que es necesario utilizar, entre los que están los registros (struct) para los cazas (Fighter) y la nave (Ship). b) La tabla de datos de cazas (4 imperiales y 4 rebeldes), y las abreviaturas de los tipos de caza (que se utilizarán en la opción Add fighter). c) Constantes de las naves como la capacidad de cada nave, y las dotaciones iniciales de cazas; en estos vectores se indica cuántos cazas de la tabla tiene cada nave. d ) Constantes y una función para emitir mensajes de error. e) Una función para generar números aleatorios (que no debes modificar). f ) Los prototipos de las funciones que se debe implementar2 . g) Una función main que debes completar. autocoP2p1.tgz : autocorrector para probar la práctica con algunas pruebas. La corrección automática de la práctica se realizará con un corrector similar. 2. La generación de números pseudo-aleatorios se realiza usando las funciones estándar de C/C++ rand (para generar números) y srand (para establecer la semilla). Aunque se ha probado en varias versiones de Linux, es posible que en otros sistemas (especialmente en Windows) no funcione exactamente de la misma manera, es decir, no se genere exactamente la misma secuencia de números aleatorios, por lo que los autocorrectores podrı́an fallar. Por tanto, es recomendable desarrollar la práctica en Linux (preferiblemente en la distribución usada en los laboratorios), y se debe probar con el autocorrector en las máquinas de los laboratorios antes de entregarla. 3. Las funciones que se debe implementar son (están incluidas en el fichero imperialCommander.cc): void initializeShip(Ship &ship,bool side); // Inicializa los datos de la nave void listFighter(const Fighter &f); // Muestra los datos de un caza void listFighters(const vector<Fighter> &vf); 2 Seguramente necesitarás implementar alguna función adicional para que el código sea más sencillo y legible. 4 IMPLEMENTACIÓN 8 // Muestra un vector de cazas void listShip(const Ship &ship); // Muestra los datos de una nave y de sus cazas bool addFighter(Ship &ship); // A~ nade uno o más cazas a la nave. Devuelve true si los ha a~ nadido bool improveFighter(Ship &ship); // Mejora o repara un caza. Devuelve \texttt{true} si lo ha mejorado o reparado int fight(Fighter &fg1,Fighter &fg2); // Simula un combate entre dos cazas. Devuelve -1 si gana el primero, 1 si gana el // segundo, 0 si hay empate void launchFighter(Ship &imperial,Ship &rebel); // Simula el combate entre un caza imperial y uno rebelde 4. En la corrección de la práctica se introducirán datos del tipo correcto siempre, aunque con valores que pueden ser incorrectos. Por ejemplo, si se pide el número de cazas, se introducirá siempre un valor entero, que podrı́a ser -1237 o 0, pero nunca se introducirá un valor de otro tipo (carácter, string o número real). 5. El resto de decisiones en la implementación de la práctica quedan a tu criterio, pero ten en cuenta que el código fuente de la práctica será revisado por tu profesor de prácticas siguiendo la guı́a de estilo publicada en la web de la asignatura, y parte de la nota de la práctica depende de dicha revisión. Ten en cuenta especialmente estas recomendaciones:3 El sangrado del código debe ser adecuado, siguiendo uno de los estilos recomendados en la guı́a de estilo. Usa 2 o 3 espacios en vez de tabuladores. Los ficheros fuente deben estar adecuadamente documentados, con comentarios donde se considere necesario, en aquellos puntos del código que sean más oscuros (pero sin poner comentarios obvios).4 En Programación 2 no se pueden utilizar variables globales de ninguna clase, los únicos sı́mbolos globales permitidos son las funciones, los tipos definidos por el programador y las constantes. Tampoco se permite usar break para salir de bucles, ni usar return para salir de funciones en mitad del código.5 Los nombres de constantes, variables y funciones deben ser adecuados, y deben informar sobre su contenido. Las funciones deben tener un tamaño adecuado; si una función es demasiado grande (p.ej. no cabe en una pantalla normal), probablemente se deberı́a dividir en dos o más funciones. Nunca se debe duplicar (copy/paste) código. 3 Recuerda una cita famosa de John Woods: Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. 4 Muchos programadores consideran que los comentarios no deberı́an existir, si el código está bien escrito no es necesario poner comentarios. 5 El objetivo de estas normas es afianzar el aprendizaje, en asignaturas de cursos superiores sı́ se permite usar estas caracterı́sticas del lenguaje.