Ejercicio obligatorio 4
Fecha de entrega: Domingo 27 de junio
Introducción
El archivo
Un juego codifica sus niveles en un archivo binario. Este archivo contiene una sucesión de niveles, donde cada nivel se compone de una determinada cantidad de obstáculos. Cada uno de los obstáculos tiene un tipo, un movimiento, un color, y parámetros que dependerán de su tipo.
Un archivo de niveles tendrá entonces este aspecto:
+---------+---------+---------+---------+---------+
| Nivel 1 | Nivel 2 | Nivel 3 | ... | Nivel M |
+---------+---------+---------+---------+---------+
es decir, una sucesión de un largo desconocido de niveles.
Luego cada nivel tendrá este aspecto:
+--------+--------+--------+-------+--------+
| N obst | Obst 1 | Obst 2 | ... | Obst N |
+--------+--------+--------+-------+--------+
es decir, el nivel empieza con un número (de 16 bits) N que indica la cantidad de obstáculos contenidos en dicho nivel y luego sigue una sucesión de estos obstáculos.
Los obstáculos
Como se dijo, los obstáculos pueden ser de diferentes tipos. La estructura de cada uno de ellos será:
+------------+------------+-----------+
| Encabezado | Movimiento | Geometría |
+------------+------------+-----------+
donde el encabezado es un byte que codifica el tipo, movimiento y color y los parámetros son una sucesión de valores y su cantidad y significado dependerá del tipo.
El byte de encabezado tiene el siguiente patrón:
MSB LSB
+----+----+----+----+----+----+----+----+
| C1 | C0 | M1 | M0 | T3 | T2 | T1 | T0 |
+----+----+----+----+----+----+----+----+
donde los bits C representan el color, los bits M el movimiento y los bits T el tipo.
Hay 4 tipos de color:
Valor |
Color |
---|---|
0 |
Azul |
1 |
Naranja |
2 |
Verde |
3 |
Gris |
Hay tres tipos de movimiento:
Valor |
Movimiento |
---|---|
0 |
Inmóvil |
1 |
Circular |
2 |
Horizontal |
Y, finalmente, se conocen (de momento) 3 tipos de objetos:
Valor |
Geometría |
---|---|
0 |
Círculo |
1 |
Rectángulo |
2 |
Polígono |
Luego del encabezado vendrán los valores del movimiento y de la geometría. Todos estos valores son de tipo entero de 16 bits.
Dependiendo del tipo de movimiento se esperan estos parámetros:
- Inmóvil:
Ningún parámetro.
- Circular:
3 parámetros: x, y, velocidad.
- Horizontal:
4 parámetros: x0, x1, xi, velocidad.
Dependiendo del tipo de geometría se esperan estos parámetros:
- Círculo:
3 parámetros: x, y, radio.
- Rectángulo:
5 parámetros: x, y, ancho, alto, ángulo.
- Polígono:
El primer parámetro es la cantidad de puntos, y luego vienen las coordenadas de los puntos como pares x e y. Por ejemplo, si el primer parámetro es 3, entonces se espera luego 6 valores correspondientes a sus coordenadas x0, y0, x1, y1, x2, y2.
Tipos
Se pide declarar tres tipos enumerativos color_t
, movimiento_t
y
geometria_t
que codifiquen los colores y tipos de movimiento de las
tablas.
Además se tienen las siguientes definiciones:
struct poligono;
typedef struct poligono poligono_t;
que declaran el TDA polígono del EJ3. Si bien hace falta la definición del tipo el mismo no se usará en este ejercicio dado que el ejercicio anterior aún no está cerrado.
Lectura
Encabezado
Desarrollar una función
bool leer_encabezado(FILE *f, color_t *color, movimiento_t *movimiento, geometria_t *geometria);
que dado un archivo f
lea de él un byte y devuelva su color
, movimiento
y
geometria
. Debe devolver true
si todo es correcto.
Movimiento
Desarrollar una función
bool leer_movimiento_inmovil(FILE *f, int16_t parametros[], size_t *n_parametros);
que... no haga nada. Pero devuelva true
por el nombre y 0
en
n_parametros
.
Desarrollar una función
bool leer_movimiento_circular(FILE *f, int16_t parametros[], size_t *n_parametros);
que lea del archivo f
los 3 parámetros que representan el movimiento circular
y los almacene en parametros
, debe devolver por el nombre true
en caso de
estar todo correcto y por la interfaz n_parametros
con la cantidad de
parámetros leída.
Desarrollar una función
bool leer_movimiento_horizontal(FILE *f, int16_t parametros[], size_t *n_parametros);
análoga a las anteriores pero para el movimiento horizontal.
Se pide implementar una función
bool leer_movimiento(FILE *f, movimiento_t movimiento, int16_t parametros[], size_t *n_parametros);
que dado el archivo f
lea de él el movimiento correspondiente al movimiento
dado.
Nota
Deben usarse tablas de búsqueda con las funciones previamente desarrolladas para resolver esta función.
Cualquier solución basada en lógica de ifs, switch, etc. será considerada inválida.
Polígonos
Como se dijo previamente, dado que todavía no se encuentran terminados los EJ3
se evitará interactuar con el tipo polígono. La idea de las funciones que
generan la forma es poder generar el poligono_t
que representa al tipo de
obstáculo dado.
Es decir, todas las funciones de lectura de parámetros del obstáculo serán de la forma:
poligono_t *leer_xxxxxx(FILE *f) {
// Extraer de f la información sobre la geometría del polígono y sobre
// su centro, rotación, etc.
poligono_t *p = poligono_crear(...); // Crear en el origen
if(p == NULL) return NULL;
poligono_rotar(p, rotacion); // Del EJ2
poligono_trasladar(p, cx, cy); // Del EJ2
return p;
}
Como no se tiene funcional al poligono_t
entonces nos centraremos en este
trabajo en la parte de la extracción de los parámetros y el completado de las
funciones quedará para más adelante.
Es decir, la función será del estilo:
poligono_t *leer_xxxx(FILE *f) {
// Extraer de f la información sobre la geometría del polígono y sobre
// su centro, rotación, etc.
printf("XXXX: Centro: %d, %d, Rotacion: %f, ...\n", ...);
return NULL;
}
y se completará después.
Las funciones deben extraer los parámetros leídos correctamente.
Se pide implementar las funciones:
poligono_t *leer_geometria_circulo(FILE *f);
,poligono_t *leer_geometria_rectangulo(FILE *f);
,poligono_t *leer_geometria_poligono(FILE *f);
,
que lean en base a los formatos especificados. (Todas ellas deben imprimir lo leído y devolver NULL.)
Se pide implementar una función
poligono_t *leer_geometria(FILE*f, geometria_t geometria);
que dado el archivo f
lea de él la geometría correspondiente a un obstáculo
del tipo
dado.
Nota
Deben usarse tablas de búsqueda con las funciones previamente desarrolladas para resolver esta función.
Cualquier solución basada en lógica de ifs, switch, etc. será considerada inválida.
Aplicación
Se provee el siguiente main()
:
const char *colores[] = {
// Completar adecuadamente
};
int main(int argc, char *argv[]) {
if(argc != 2) {
fprintf(stderr, "Uso: %s <archivo>\n", argv[0]);
return 1;
}
FILE *f = fopen(argv[1], "rb");
if(f == NULL) {
fprintf(stderr, "No pudo abrirse \"%s\"\n", argv[1]);
return 1;
}
int nivel = 0;
while(1) {
nivel++;
int16_t obstaculos;
if(! fread(&obstaculos, sizeof(int16_t), 1, f)) break;
printf("Nivel %d, Cantidad de obstaculos: %u\n", nivel, obstaculos);
for(size_t obstaculo = 0; obstaculo < obstaculos; obstaculo++) {
color_t color;
movimiento_t movimiento;
geometria_t geometria;
assert(leer_encabezado(f, &color, &movimiento, &geometria));
printf("Obstaculo %zd, color = %s\n", obstaculo, colores[color]);
int16_t parametros[4];
size_t n_parametros;
assert(leer_movimiento(f, movimiento, parametros, &n_parametros));
printf("Movimiento: Parametros = %zd", n_parametros);
for(size_t i = 0; i < n_parametros; i++)
printf(", %d", parametros[i]);
putchar('\n');
assert(leer_geometria(f, geometria) == NULL);
}
}
fclose(f);
return 0;
}
Y además se provee el siguiente juegos de archivos: archivos_20211_ej4.tar.gz
de una entrada con su respectiva salida.
Este main()
, sin alteraciones, debe ser entregado como parte del ejercicio y
el mismo debe correr para el archivo de entrada generando la salida pedida.
Nota
Para este trabajo no es necesario modularizar el problema, pero se recomienda hacerlo para practicar modularización y Makefile.
En el caso de modularizar en archivos entregar tanto los archivos como el Makefile que compila el proyecto.
Entrega
Deberá entregarse el código fuente del programa desarrollado o los fuentes y el Makefile en caso de haber modularizado.
El programa debe:
Compilar correctamente con los flags:
-Wall -Werror -std=c99 -pedantic
validar la salida contra los ejemplos dados.
La entrega se realiza a través del sistema de entregas.
El ejercicio es de entrega individual.