UC3M

Grado en Ing. Telemática/Sist. Audiovisuales/Sist. de Comunicaciones

Arquitectura de Sistemas

Septiembre 2017 - Enero 2018

Gestor de Jedis (Jedi_Manager)

1. Recursos

2. Vista General

Basándose en la experiencia acumulada con la aplicación encargada de detección de Wifis, se recibe en la empresa SAUCEM S.L. un encargo de un cliente que quiere una aplicación para la gestión de guerreros Jedis, denominada informalmente Jedi_Manager. El cliente quiere una aplicación que le permita la inserción, borrado y modificación de un conjunto de Jedis, que se caracterizan con parámetros. También quiere que la applicación exporte e importe a un fichero en formato binario sus datos, se incluya soporte al combate Jedi_Manager y cierta funcionalidad de autosalvado que una vez activada guarde la información del sistema a un fichero.

Por cada Jedi, la información que debería de incluir es:

  • Identificador único del Jedi. Este es de tipo entero: int id, más grande de cero.Este identificador se usa para identificar a un guerrero Jedi y realizar operaciones sobre él.

  • Nombre del Jedi, representado como una cadena de texto de tamaño libre: char* s_full_name. En principio no hay límites sobre la longitud del nombre de un Jedi.

  • Longitud del nombre del Jedi: int size_name. Se corresponde siempre con el tamaño de s_full_name.

  • Los características internas del Jedi han de estar guardadas en una estructura llamada struct points* ptr_points que contendrá los siguientes campos:

    • Puntos de vida del Jedi representados como: int hit_points. Un Jedi con hit_points de zero o negativo está muerto y tras ello no puede participar en más combates.

    • Puntos de ataque de tipo: int attack_array[2]. Se utiliza en el combate para infligir daño al rival. Tiene ataque tipo aprendiz que se define con el siguiente enumerado: T_APPRENTICE=0 o especial definido como: T_MASTER=1.

    • Puntos de la defensa defensa de un Jedi: int defense_array[2]. Se usa en el combate Jedi. Se tienen tanto ataques normales: T_APPRENTICE=0 como especiales de maestro: T_MASTER=1

    • La velocidad del Jedi: double speed_array [2]. Se include tanto la velocidad del aprendiz como del maestro: T_APPRENTICE=0 y T_MASTER=1.

    • Nivel actual enum level_jedi del Jedi, que puede ser T_APPRENTICE=0 o T_MASTER=1.

3. Requisitos del cliente

  1. Aplicación de consola: La aplicación se arranca desde un terminal de comandos y se manipula enteramente con el teclado.

  2. Para organizar el código, el fichero principal de la aplicación se llamará my_jedi_manager.c y los prototipos estarán en my_jedi_manager.h. Puede añadir otros ficheros adicionales si los necesita.

  3. Tras arrancar, la aplicación muestra un menú principal de texto con las posibles operaciones, cada una de ellas identificada con un número o letra diferente. Si cuando se está esperando una orden del usuario se pulsa la combinación de teclas CTRL-D, la aplicación debe terminar.

     
          
            =========================================
            [*][2017][SAUCEM APPS][JediManager]======
            =========================================
            [1] Salir
            [2] Insertar Jedi
            [3] Mostrar Jedis
            [4] Mostrar Jedi por ID
            [5] Modificar un Jedi por ID
            [6] Borrar Jedi por ID
            [7] Exportar Jedis a fichero binario
            [8] Importar Jedis de fichero binario
            [9] Simulador de combate Jedi
            [10] Ordenar Jedis por puntos de vida 
            [11] Autosalvado Jedi (5 segundos, si ha habido cambios)
                             #INFO:   1 veces mostrado el menú principal
    
            Dame una opción: 	
  4. Las operaciones que debe incluir el menú principal son (al menos):

    1. Salir de la aplicación. La aplicación debe ofrecer la posibilidad e preguntar al usuario si desea salir. Al salir se borrarán los datos temporales almacenadas en memoria así como otros recursos reservados.

      ¿Está seguro de que desea salir del programa?[s/N]: 
    2. Insertar. Esta función se encarga de introducir un Jedi a través de la línea de comandos. El nuevo elemento será creado en memoria dinámica para así poder ser manipulado en tiempo de ejecución.

      		 Insertando Jedi
                              Dame el ID del Jedi: 1
                              Dame el nombre del Jedi: Yoda
                              Dame la vida: 45
                              Dame el ataque de aprendiz: 53
      
                              Dame la defensa de aprendiz: 70
                              Dame la velocidad de aprendiz: 42,5 
                              Dame el ataque de maestro:400
      			Dame la defensa de maestro: 600
      			Dame la velocidad de maestro: 425,0
      			Es un maestro (s/N): s
    3. Mostrar resumen. Esta opción muestra el identificador de todos los Jedis incluídos en el sistema. Incluye el identificador del Jedi seguido de los 10 caracteres más significativos del título del Jedi, seguido de la vida, el ataque y la defensa.

              ================================
              |  ID|    Nomb. |Vida|Ata.|Def.|
              ================================
              |  1 |   Yoda   |  45|  53|  70|
              ================================
            
    4. Mostrar la información de un Jedi. Esta opción muestra toda la información de un Jedi incluido en el sistema. La forma de acceder a la información es mediante el identificador (ID) asociado al Jedi.

              = Información completa de Jedi
              = id: 1
              = vida: 45
              = nombre: Yoda, Maestro
      
              = ataque de aprendiz: 53
              = defensa de aprendiz: 70
              = velocidad de aprendiz: 42,5
              = ataque de maestro: 400
              = defensa de maestro: 600
      	= velocidad de maestro: 425,0
    5. Modificación de un Jedi. Esta opción permitirá modificar todos los campos de un Jedi, cuyo ID se pasará a través de la línea de comandos. Esto también incluye el identificador del Jedi.

    6. Borrar un Jedi a partir de su identificador. Esta opción del menú se encargará de eliminar el identificador que se pasa a través de la línea de comandos. En caso de haber varias ocurrencias se eliminará sólo la primera.

    7. Exportar Jedis a fichero. Esta opción se encarga de almacenar todos los Jedis en memoria a almacenamiento persistente. En esta versión se le pide el nombre del fichero al usuario. Los datos se almacenarán en formato binario (con fwrite), siguiéndose el orden prescrito en la descripción de este documento. El nombre del fichero se le pedirá al usuario.

    8. Importar desde fichero. Esta opción se encargará de tomar los datos que han sido almacenados persistentemente (por ejemplo con la opción de exportar) y de cargarlos en memoria (típicamente para su manipulación), mediante fread. Se le pedirá al usuario que diga el nombre del fichero donde se guardan los Jedis. Los datos leídos se añadiran al principio de la tabla, en memoria.

    9. En el combate Jedi se le pide al usuario que elija dos Jedis por identificador. Si existen los Jedis y tienen vida se puede empezar y combate hasta que uno de los dos muere. En el primer turno ataca el primer Jedi y después el segundo ataca al primero y así sucesivamente. Tras las dos mangas a los dos Jedis se les quitan tantos puntos de vida como daños han recibido. Para calcular los daños del primer Jedi_1 sobre el Jedi_2 se usa la siguiente fórmula: daño=(Jedi_1->velocidad/Jedi_2->velocidad)(((86+rand()%15)*Jedi_1->attack)/(Jedi_2->defense)/10. Dependiendo de si es master o aprendiz, estos usan como vector de ataque sus puntos de ataque o defensa normales o de maestro.

      A modo de ejemplo, asumamos que combaten dos Jedi no maestros Jedi 1 con hp:100, attack[T_APPRENTICE]: 10, defense[T_APPRENTICE]: 10 y velocidad [T_APPRENTICE]:2 y Jedi 2 tambien aprendiz con hp: 18, ataque attack[T_APPRENTICE]: 5, defensa defense[T_APPRENTICE]: 5 y velocidad[T_APPRENTICE]: 2. Con estos dos Jedis un posible ejemplo combate sería el siguiente: Jedi 1 ataca con fuerza máxima y daña a Jedi 2 con ((2/2)(((86+15)*10)/5)/10) =20 puntos. Tras ello, y asumiendo que se usa su máxima fuerza en la réplica, Jedi 2 ataca a Jedi 1 con un daño de: ((2/2) (((86+15)*5)/10)/10)=5 puntos. Tras el combate la vida actualizada de los dos Jedis sería Jedi 2:(18-20)=-2 no pudiendo combatir más y Jedi 1 pierde 5 puntos de vida quedándose en: (100-5)=95.

      Al final de un combate, si un aprendiz derrota a un maestro, cambia de status a maestro. Así mismo, si un maestro es derrotado por un aprendiz, cambia su estatus a aprendiz.

    10. Ordenar Jedis. Se ordenaran de forma creciente con sus puntos de vida que tengan.

    11. Activar autosalvado Jedi. Activa un salvado, implementado con hilos POSIX, automático cada 5 segundos de la que ha sido creada en el fichero ##auto_jedi_save.dat de todos los datos de los Jedis. Sólo se guardarán estos Jedis cuando haya cambios en la estructuras almacenadas en memoria. Una vez activada la función de autosave, esta permanece activa hasta que finaliza el programa.

  5. Al seleccionar una operación, esta puede requerir que se introduzcan datos adicionales por el teclado. Al acabar la operación se vuelve a mostrar el menú principal a la espera un nuevo comando del usuario. Si el usuario desea volver al menú principal antes de acabar la operación, pulsará Crtl-D.

  6. La aplicación debe ser robusta, es decir, debe poder recuperarse sin problemas si en algún punto el usuario no introduce los datos adecuados (letras cuando se espera un número, una cadena vacía, una línea vacía, un nombre de fichero incorrecto, un fichero vacío, etc.).

¡Aviso!

Tal y como suele suceder más a menudo de lo deseable en el contexto industrial, un cliente puede hacer ajustes a esta especificación mientras se está desarrollando el proyecto. Por tanto, si tal circunstancia se produce, el equipo debe tratarla con normalidad.

4. Requisitos de la empresa

Además de los requisitos del cliente que tienen que ver con el producto terminado, SAUCEM S.L. tiene su propia política de desarrollo de productos orientada a mantener su imagen corporativa de empresa fiable, y a conseguir un ciclo de desarrollo eficiente. Estos requisitos son:

  1. La solución del proyecto debe utilizar algún tipo de estructura de datos dinámica.

  2. No se permite que la solución utilice variables globales. Las variables que usará tendrán que ser creadas en memoria dinámica o de pila (stack).

    int variable_global; //NO PERMITIDA
    int mi_funcion(int input)
    { 
      return input;
    }	 
  3. El código debe estar dividido en ficheros de tal forma que se agrupen funciones similares. Los nombres de las funciones deben ser elegidos para facilitar su entendimiento y localizar rápidamente la funcionalidad buscada. Cada función debe de tener un desarrollador @dev_nia, un probador @tester_nia, un integrador de sistema (@int_nia) y probador (@test_int_nia) del sistema. El desarrollador y probador garantizan lo que hay dentro de la funcion y su integrador su integracion dentro del ecosistema externo.

    	//@dev_nia 10000000 @tester_nia 10000002 @int_nia 10000003 @test_int_nia 10000003  
    	int funcion(int input)
    	  { ...
    	
    	  }	 
  4. Todos los ficheros de código (*.c) y de definiciones (*.h) deben tener la estructura de las plantillas CFile.templ y CHeaderFile.templ respectivamente que encontraréis en el directorio Plantillas. En la cabecera se debe incluir una descripción detallada de las funciones o definiciones que contiene el fichero. Todos aquellos campos de la plantilla que no tengan contenido deberán borrarse. Por ejemplo, si tu código no contiene macros, deberás borrar esta parte de la plantilla.

    Además, aquellas partes del código más delicadas, deben ir precedidas de un bloque de comentario que lo explique. No incluyas comentarios línea a línea, sino en bloques al comienzo de un conjunto de pasos.

  5. Todas las funciones, variables globales, #define, definiciones de estructuras y definiciones de enumeraciones debe estar documentadas precediendo su definición con texto de las plantillas en los ficheros con nombres Function.templ, Variable.templ, Macro.templ, Struct.templ y Enum.templ respectivamente. En el caso de las funciones se debe explicar el papel de cada parámetro así como el resultado que devuelve. Los fragmentos a incluir con sus campos por completar los puedes encontrar todos en la carpeta Plantillas de tu directorio de trabajo.

  6. Si el símbolo DEBUG está definido al compilar, la aplicación muestra mensajes de depuración por pantalla con las principales operaciones que realiza.

  7. El código debe compilar sin ningún tipo de error ni advertencia cuando se utiliza la opción -Wall del compilador gcc.

  8. El código debe escribirse siguiendo las pautas descritas en la siguiente guía.

  9. La aplicación debe hacer una gestión correcta de la memoria dinámica, es decir, sin fugas, accesos a porciones sin inicializar, liberaciones incorrectas, etc.

  10. En la carpeta Actas del espacio de trabajo del grupo debe haber un acta para cada una de las reuniones de grupo que se han realizado. En ella debe constar el orden del día, los asistentes, quién ha realizado de moderador, quién ha escrito el acta y las decisiones que se han tomado.

  11. El código debe estar creado de manera equilibrada por todos los miembros del equipo. Se exige una contribución equilibrada de todos los miembros del equipo.

5. Hitos del proyecto

Para facilitar la ejecución, el proyecto se divide en hitos. Un hito marca el final de una fase y el comienzo de otra. A menudo los hitos de un proyecto llevan asignados también una serie de entregables que son fragmentos de programa, documentos, o cualquier elemento relacionado con el proyecto que debe estar listo para ser entregado. Los hitos que te describimos a continuación son orientativos y pretenden ser una guía de cómo se debe desarrollar el proyecto de forma gradual. Puede que tu equipo no siga estrictamente estos hitos, pero no es importante siempre y cuando el proyecto se haga de forma gradual y el producto final esté terminado en el plazo acordado. Si un equipo completa un hito antes de lo planificado no debe detenerse y debe continuar con el siguiente hito. Los hitos semanales propuestos para el proyecto son:

  • Hito 1. Crear un documento que incluye la descripción de los módulos en los que se dividirá la aplicación así como de las estructuras de datos que se precisan. Cada módulo debe tener una descripción de la funcionalidad que se le encarga y de los datos que manipula. El equipo debe asignar a un miembro como responsable de cada módulo y mencionarlo en el documento. A lo largo del desarrollo del proyecto esta división puede ser ajustada cuanto sea necesario.

  • Hito 2. Implementación de las funcionalidades 1 a 3 de las requeridas por el cliente. Aquellos lugares en la aplicación en los que todavía no se disponga de los datos o funcionalidad adecuada, deben incluir una solución temporal mínima.

  • Hito 3. Implementación de las funcionalidades 4 y 6 de las requeridas por el cliente.

  • Hito 4. Implementación de las funcionalidades 7 a 10 de las requeridas por el cliente.

  • Hito 5. Implementación de la funcionalidad 11 y pruebas finales.

6. Entregango la versión final

A través de Aula Global.

7. Cómo compilar el proyecto

Para compilar el proyecto debes añadir a tu comando de compilación las siguientes opciones:

gcc -pthread -Wall -g [TUS FICHEROS] 

Para evitar teclear varias veces estas líneas escribe los comandos de compilación en ficheros de texto ejecutables con bash.

8. Aspectos de Evaluación

La siguiente tabla muestra la guía que se utiliza para evaluar las entregas del proyecto. Aquellas categorías que ocupan dos casillas, se evalúan con la de la nota más alta.

Aspecto

Excelente (100%) Aceptable (75%) Discreto (50%) Insuficiente (0%)

1 Compilación del código con la opción -Wall

El código compila sin ningún tipo de advertencia o error.

El código compila con dos avisos.

El código no compila, o compila con más de dos avisos.

2 Ejecución del programa

El programa ejecuta con normalidad y acorde a la especificación.

El programa termina abruptamente en una ocasión o no cumple con la especificación en uno o dos aspectos.

El programa falla en dos pruebas o no cumple con la especificación en más de dos aspectos.

El programa falla con frecuencia o el programa no cumple con la especificación.

3 Gestión de memoria

La aplicación ejecuta sin ningún tipo de anomalía cuando se analiza con Valgrind.

Se detecta o una fuga de memoria, o una liberación de memoria incorrecta.

Valgrind detecta dos anomalías al ejecutar la aplicación.

Se detectan más de dos anomalías al ejecutar con Valgrind.

4 Mensajes de depuración

Los principales pasos de la aplicación imprimen mensajes de depuración cuando se define el símbolo DEBUG.

La aplicación imprime pocos mensajes de depuración.

El programa no imprime ningún mensaje de depuración

5 Código en múltiples ficheros, definiciones y prototipos en .h

El código está dividido en varios ficheros y las definiciones y prototipos incluidos en uno o varios ficheros con extensión .h.

El código está en un único fichero, o el fichero con las definiciones y prototipos está incompleto (o incorrecto).

El código está dividido de forma arbitraria, y el fichero .h contiene información incorrecta y no se incluye de forma adecuada.

6 Uso de las plantillas de ficheros y documentación en la cabecera.

Todos los ficheros siguen la plantilla, tienen todos los campos obligatorios rellenos y la documentación en la cabecera es intuitiva.

Uno o dos ficheros no siguen la plantilla, no tienen todos los campos de documentación rellenos, o la documentación en la cabecera no es suficiente.

Mas de dos ficheros no siguen la plantilla, tienen algunos campos sin rellenar, o la documentación en la cabecera no es suficiente.

7 Documentación de variables globales, estructuras y funciones

Todas las variables globales, estructuras y funciones están perfectamente documentadas.

En un fichero hay una variable, una función o una definición de estructura sin comentar.

Hay dos ficheros con variables, funciones o declaraciones de estructuras sin documentar.

Hay más de dos ficheros con carencias en la documentación de funciones, declaración de estructuras o variables globales.

8 Estilo de codificación

Todos los ficheros cumplen con todos los requisitos de la guía de estilo.

Algunos ficheros no cumplen con los requisitos de la guía de estilo. O algún criterio de la guía de estilo es ignorado completamente.

La mayoría de los ficheros no respetan la guía de estilo. O la mayor parte de criterios de estilo se ignoran.

9 La aplicación es intuitiva

El usuario entiende sin problemas las funciones, los datos a introducir y cómo introducirlos.

Los mensajes en general están bien, pero en alguna ocasión no se entiende bien qué hay que hacer.

El usuario se atasca frecuentemente por no saber cómo ejecutar la aplicación.

10 Actas de las reuniones

El equipo se ha reunido con frecuencia (al menos una vez a la semana) y las actas detallan su contenido.

El equipo no se ha reunido con la frecuencia deseada y/o las actas no reflejan la actividad real.

Las actas tienen muchas carencias, o hay un número muy bajo de ellas.

11 Trabajo distribuido igualmente entre los miembros del equipo.

Todos los miembros del equipo por igual han subido ficheros al depósito y contribuido a su escritura.

Sólo una parte del equipo ha subido ficheros al depósito y contribuido a su escritura.

Solo una persona del equipo ha subido ficheros al depósito y contribuido a su escritura.

Los criterios están ordenados en orden de importancia. Tener correctos los dos primeros es condición esencial para aprobar el proyecto. Si el programa no compila o falla con frecuencia, no se considera acabado y la nota es un cero.

9. Fuentes de inspiración

Cuando se emprende un proyecto de estas características es muy común el obtener información de múltiples fuentes que contribuyen a su desarrollo. Cuando el proyecto empieza y los plazos de entrega están lejos, no hay problema de este tipo. Pero cuando nos vemos con el tiempo encima, la desesperación nubla la capacidad de decisión. Lo mejor para evitar problemas es tener muy claro en todo momento cuando esas fuentes son de uso razonable y cuando se pueden considerar una copia del trabajo. Te incluimos a continuación una serie de sugerencias.

  • Comentar en el pasillo, en un aula, entre clase y clase cómo estamos resolviendo un aspecto especial de la práctica (no hay problema)

  • Estoy estudiando con compañeros en la biblioteca y uno saca un papel para dibujar su problema en el proyecto y yo dibujo lo que hemos hecho en nuestro proyecto (no hay problema)

  • Tras tener una de estas conversaciones, mi amigo me escribe y me dice que no le ha quedado claro. Le mando por correo una descripción textual más detallada de lo que hemos hecho (no hay problema).

  • Recibo otro correo y todavía no lo ve claro. Corto y pego un trozo de nuestro código en el correo que le envío como respuesta (si, tenemos un problema). Fácil de detectar por la estructura del código. Por pequeño que sea el fragmento.

  • Encuentro un trozo de código en Internet que hace lo que yo quiero, lo corto y pego, y tras unos cambios, ya funciona (no hay problema). Asegúrate de incluir la referencia en el propio código como un comentario.

  • (Basado en caso real) Trabajo en una empresa y le muestro el enunciado a mis colegas. A alguno de ellos le emociona y me manda parte de la solución (si, tenemos un problema). Fácil de detectar, cada persona escribe código de forma especial, es difícil que tu colega tenga el mismo nivel de C que tú. Además, seguramente ese colega presuma de haber resuelto esto y se puede llegar a comentar a los profesores (ha pasado)

  • (Basado en caso real) Mi mejor amigo ha tenido la mala suerte de que le ha tocado en otro equipo que no avanza y está desesperado. Me pide que, por favor, le mande el código, pero me promete solemnemente que solo lo va a utilizar para leerlo y que no va a copiar nada. Es mi colega, somos como hermanos, no puedo decir que no. Se lo mando (sí, tenemos un problema). Tu colega incluirá algún fragmento en la entrega o lo que es peor, entregará uno de tus ficheros por error (ha sucedido).

  • Trabajo en el proyecto en una academia. El profesor me explica algunos aspectos de la solución pero sin mostrar código (nosotros sin problemas, tú verás).

  • En la academia se ilustra la solución del proyecto con código ejemplo (si, tenemos un problema). Recibiremos varias entregas casi idénticas, signo inequívoco de la resolución en cooperativa.

Todas estas situaciones se pueden resumir en dos consejos fundamentales. Tu código solo lo pueden ver los miembros de tu equipo, y tú no debes ver otro código que no sea el tuyo. Y cuando utilices fuentes de información, cítalas en la documentación que se incluye en la cabecera de cada fichero. En cualquier caso, ante la duda, ¡pregunta!.

En caso de que se detecte un caso de copia, como ya ha sucedido en ocasiones anteriores, se notificará a la dirección de la escuela para que abra las diligencias correspondientes y expediente a los alumnos involucrados. La nota del curso en tal caso será cero.