Programaci´ on 2 Curso 2014/2015 Pr´

Anuncio
Programación 2
Curso 2014/2015
Práctica 2
Halcón Milenario (parte 2)
Esta práctica consiste en completar la práctica anterior, almacenando los datos
de los viajes y permitiendo guardar y recuperar los datos de la nave desde
ficheros binarios.
Entrega
1. El último dı́a para entregar esta parte de la práctica es el viernes 24 de abril,
hasta las 23:59. No se admitirán entregas fuera de plazo.
2. La práctica debe tener un único fichero fuente llamado “millenniumFalcon.cc”.
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.
Normas generales comunes a todas las prácticas
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.
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.
Programación 2, 2014/2015
2
3. Los ficheros fuente deben estar adecuadamente documentados, con comentarios
donde se considere necesario. Además, no se pueden utilizar variables globales
de ninguna clase, los únicos sı́mbolos globales permitidos son las funciones, los
tipos y las constantes.
4. La corrección de la práctica se hará de forma automática, por lo que es imprescindible respetar estrictamente los formatos de salida que se indican en este
enunciado. Además, al principio de todos los ficheros fuente entregados se debe
incluir un comentario con el DNI de la persona que entrega la práctica, con el
siguiente formato:
// DNI
tuDNI Nombre
donde tuDNI es el DNI del alumno correspondiente (sin letras), tal y como
aparece en el Campus Virtual, y Nombre es el nombre completo; por ejemplo, el comentario podrı́a ser:
// DNI
12345678 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.
Introducción
En esta práctica se implementarán las opciones del menú que no se implementaron en la práctica anterior, y además, se deben implementar dos ampliaciones sobre la práctica anterior:
1. Añadir dos bodegas de carga más, de manera que la nave en total dispondrá de 3 bodegas. Este cambio afecta principalmente a la opción Load
container, pero también a otras opciones. Cuando se introducen correctamente los datos de un contenedor, se almacenará provisionalmente en la
bodega con menor número de contenedores (en caso de empate en la que
tenga un número menor), para luego invocar al algoritmo para balancear
la carga.
Inicialmente, los contenedores se irán colocando en la primera bodega
vacı́a. A partir del momento en que todas las bodegas tengan al menos un
contenedor, el algoritmo tomará el peso total de cada bodega, y hará un
intercambio de contenedores entre las bodegas con mayor y menor peso;
en caso de igualdad de peso, se tomará la que tenga un número menor. En
el caso de que las tres bodegas tengan el mismo peso (se puede detectar
este caso porque la bodega con mayor peso es la misma que la bodega con
menor peso) no se hará ningún intercambio, como tampoco se hará intercambio cuando alguna bodega esté vacı́a.
El intercambio consistirá en extraer el último contenedor metido en la
bodega con mayor peso, extraer el último de la de menor peso, y meter
cada uno en la otra bodega, actualizando los pesos (y precios) de cada
bodega.1 Este intercambio solamente se hará una vez, en caso contrario
podrı́a producirse un bucle infinito.
Por ejemplo, después de introducir el contenedor 8 en la bodega 2 (la que
menos contenedores tiene junto con la 3) tenemos la siguiente situación
de las bodegas:
1 Este algoritmo de balanceado de carga no es óptimo, pero es el mejor que se le ocurrió a
Chewie.
Programación 2, 2014/2015
Bodega
1
2
3
Contenedores (id,peso)
(1, 100 Kg) (5, 15 Kg) (6, 22 Kg)
(4, 67 Kg) (7, 55 Kg) (8, 33 Kg)
(2, 120 Kg) (3, 27 Kg)
3
Peso
137 Kg
155 Kg
147 Kg
El programa intercambiarı́a los contenedores 8 (de 33 Kg) y 6 (de 22 Kg),
quedando las bodegas de esta forma:
Bodega
1
2
3
Contenedores (id,peso)
(1, 100 Kg) (5, 15 Kg) (8, 33 Kg)
(4, 67 Kg) (7, 55 Kg) (6, 22 Kg)
(2, 120 Kg) (3, 27 Kg)
Peso
148 Kg
144 Kg
147 Kg
Para evitar que la nave se desequilibre, cuando se elimine un contenedor
(en la opción Unload container o en Remove passenger si se baja un
pasajero que llevaba un contenedor de equipaje) se volverá a invocar al
algoritmo de balanceado de carga para recolocar de forma adecuada los
contenedores, siempre que no haya bodegas vacı́as.
Un ejemplo de la salida de la opción Show data con 3 bodegas serı́a:
Hold 1 (400 Kg, 402 credits)
(3,300,301) (1,100,101)
Hold 2 (200 Kg, 201 credits)
(2,200,201)
Hold 3 (400 Kg, 401 credits)
(4,400,401)
Seat 1: 123456,Luke Skywalker,1000,0
Seat 2: 987654,Obi wan Kenobi,1500,3
2. Almacenar los datos de los viajes en un registro de viajes: una vez se
hayan calculado y mostrado los datos del viaje (en la opción de Travel),
se guardarán en el registro de viajes de la nave, almacenando los datos
primero en un struct como el siguiente:
typedef struct {
int km;
int time;
int consumption;
int kminitial,kmhv,kmfinal;
int tinitial,thv,tfinal;
} Trip;
Los datos de los viajes se almacenarán en una lista simplemente enlazada
en la que siempre se insertará el nuevo viaje al principio de la lista. Cada
nodo de la lista contendrá un registro Trip y un puntero al siguiente nodo.
Al finalizar el programa la lista debe borrarse, liberando adecuadamente
la memoria dinámica reservada.
Programación 2, 2014/2015
4
Descripción de las opciones restantes
Lo que debe hacer el programa en cada una de las opciones que quedaban
por implementar es:
Trip log : cuando se elija esta opción, el programa permitirá consultar los datos
de los viajes realizados, para lo que mostrará el siguiente menú:
1- Show all
2- Filter km
3- Filter time
4- Filter consumption
5- Save log
6- Load log
q- Quit
Option:
Si se elige la opción 1, se mostrarán todos los viajes tal y como están
almacenados en la lista. Si se elige la opción 2, 3 o 4, se pedirán dos
números enteros, el lı́mite inferior y el lı́mite superior (con los mensajes
“Lower limit: ” y “Upper limit: ”), y a continuación se mostrarán
todos los viajes cuyo kilometraje, tiempo o consumo se encuentre entre
dichos lı́mites (ambos valores incluı́dos, y si ningún viaje encaja con esos
lı́mites no saldrá nada). Si el usuario introduce un lı́mite superior menor
que el lı́mite inferior, se debe emitir el siguiente mensaje de error:
Error, wrong limits
En las opciones 1 a 4 los viajes se mostrarán con un formato más compacto,
con todos los datos del viaje en una sola lı́nea. Por ejemplo, para el viaje
del ejemplo de la práctica anterior se mostrarı́a:
1357 km, 797 s, 75555 litres, (79 1200 78) [395 12 390]
Si se elige la opción 5, el programa debe pedir un nombre de fichero (con
el mensaje “Filename: ”), y almacenar en ese fichero de texto los datos
de todos los viajes en el orden en el que aparecen en la lista, escribiendo
en cada lı́nea todos los datos un viaje, en el mismo formato que en las
opciones 1 a 4.
Si el fichero no se puede abrir, se debe emitir el siguiente mensaje de error:
Error, can’t open file
Si al elegir alguna de las opciones 1, 2, 3, 4 o 5 todavı́a no hay viajes
se debe emitir el siguiente error (sin llegar a pedir ningún dato adicional
como los lı́mites o el nombre del fichero):
Error, no trips in the log yet!
Programación 2, 2014/2015
5
Si se elige la opción 6, el programa debe pedir un nombre de fichero y, si el
fichero se puede abrir, borrar la lista y leer los datos de los viajes del fichero
para meterlos en la lista insertando por la cabeza, lo cual provocará que
la nueva lista esté invertida con respecto a la que se usó para generar el
fichero, pero es absolutamente normal y no se debe hacer nada al respecto.
Como en la opción anterior, si el fichero no se puede abrir se debe emitir
el error de apertura del fichero. La lista se debe borrar solamente después
de haber abierto el fichero con éxito.
Finalmente, si se introduce una opción incorrecta en este menú se mostrará el mismo mensaje de error que en el menú principal.
Save data : si se elige esta opción, el programa debe almacenar en el fichero
binario “mfdata.dat” todos los datos de las bodegas y de los pasajeros
(pero no el registro de viajes). Para ello deben emplearse los siguientes
registros:
typedef struct {
double weight;
int price;
int ncontainers;
} HoldBinary;
const int MAXGIN=12;
const int MAXNAME=20;
typedef struct {
char GIN[MAXGIN];
char name[MAXNAME];
int price;
int idLuggage;
int seat;
} PassengerBinary;
En el fichero binario “mfdata.dat” se almacenará la siguiente información:
todas las bodegas, con sus datos. Además, después del registro de
cada bodega (HoldBinary) se almacenarán todos los registros de sus
contenedores (antes de los datos de la siguiente bodega)
el identificador del siguiente contenedor, idNextContainer (int)
los datos de cada pasajero, en el mismo orden que tienen en el vector
de pasajeros. Si el GIN o el nombre de alguno de los pasajeros no cabe
en el vector del registro PassengerBinary, se debe recortar para que
quepa (con el “\0”).2
Si el fichero no puede abrirse se debe emitir el error de apertura del fichero.
Load data : si el usuario elige esta opción, se debe pedir confirmación con el
siguiente mensaje:
Load data (current data will be deleted)? (Y/N)
2 En
las transparencias del tema de ficheros se explica cómo hacerlo correctamente.
Programación 2, 2014/2015
6
Si la respuesta del usuario es una “Y” entonces se intentará abrir el fichero
“mfdata.dat”, y si se puede abrir el fichero se borrarán todos los datos de
las bodegas y de los asientos de la nave (pero no de los viajes), y se leerán
los datos del fichero binario. Como en la opción anterior, si el fichero no
puede abrirse se debe emitir el error de apertura del fichero, y no debe
borrarse nada si no se ha podido abrir el fichero, es decir, solamente se
debe borrar los datos después de haber abierto el fichero con éxito.
En el registro Spaceship, el identificador del siguiente contenedor será el
que se lea desde el fichero, no debe dejarse el valor que tuviera (que podrı́a
ser mayor o menor, en cuyo caso podrı́an generarse contenedores con el
mismo identificador).
Los contenedores se supone que fueron almacenados de forma balanceada
en las bodegas, por lo que no es necesario invocar al algoritmo de balanceado de carga al leer los contenedores, simplemente se leen y almacenan
en la bodega que les corresponda.
Por otro lado, al leer los datos de los pasajeros es necesario ir actualizando
el vector de asientos para evitar que los nuevos pasajeros que suban a la
nave ocupen el mismo asiento que un pasajero leı́do del fichero.
Uso del programa con argumentos
El usuario puede invocar el programa desde la lı́nea de comandos con los
siguientes argumentos (opcionales), o bien sin argumentos:
Opción -bf : cuando se invoca el programa con esta opción, lo primero que debe
hacer el programa es recuperar los datos del fichero binario “mfdata.dat”,
pero sin pedir confirmación para borrar los datos actuales, puesto que al
iniciar el programa no hay datos. Si el fichero puede abrirse, se leerán los
datos (utilizando la función implementada en la opción correspondiente
del menú), y a continuación se iniciará el programa como si no hubiera
habido argumentos, mostrando el menú.3 Si el fichero no se puede abrir,
después de emitir el mensaje correspondiente el programa terminará (sin
hacer nada más ni emitir ningún mensaje más).
Opción -lt <fichero> : al poner esta opción se asumirá que el argumento
siguiente es un nombre de fichero, y el programa intentará abrir ese fichero, cargar los datos de los viajes en la lista (como en la opción Load log
del menú de Trip log), e iniciar el programa como si no hubiera habido
argumentos, mostrando el menú. Como en la opción anterior, si el fichero no puede abrirse se emitirá el correspondiente mensaje de error y se
terminará el programa.
Ambas opciones son compatibles, es decir, el usuario puede invocar el programa con una de las opciones, con las dos, o con ninguna. Si se produce algún
error en los argumentos del programa, se debe emitir el siguiente mensaje de
error (y salir del programa):
Error in arguments, syntax: millenniumFalcon [-lt <filename> | -bf]
3 La implementación es muy sencilla: en la función main se debe comprobar y gestionar los
argumentos justo antes del bucle do-while que implementa el menú.
Programación 2, 2014/2015
7
Si el usuario introduce ambas opciones en la lı́nea de comandos, primero se
debe leer el fichero binario y a continuación el fichero de los viajes.
Implementación
Para implementar la práctica debes tener en cuenta:
1. El menú de la opción de Trip log, como el menú principal, debe implementarse con una instrucción do-while con un switch en su interior.
2. Para almacenar los datos de los viajes se utilizará una lista simplemente
enlazada en la que los datos del nuevo viaje se insertarán por la cabeza
de la lista, tal y como se ha explicado en las clases de teorı́a
3. En el registro de la nave (Spaceship) debes sustituir la declaración de la
bodega por un vector de 3 posiciones (declarando el “3” como constante):
typedef struct {
...
Hold holds[NUMHOLDS];
...
} Spaceship;
4. En general, se asumirá que no hay errores de lectura o de escritura, es
decir, si se consigue abrir el fichero (para lectura o para escritura), se
podrá leer/escribir sin problemas.
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.
Descargar