Tarea 2
Tarea 2
Tarea 2
Instituto de Computación
2022
Información general
Se sugiere leer con mucha atención todo el texto antes de comenzar la tarea.
Es muy importante que se respeten todos los requisitos especificados en esta
sección y las siguientes. Si surgen dudas, solicitamos que las formulen en el foro
correspondiente a la tarea.
Individualidad
Esta tarea se deberá realizar en grupos de hasta 2 estudiantes. Los distintos
grupos no deben compartir código entre sí. Para todas las tareas rige el Regla-
mento del Instituto de Computación ante Instancias de No Individualidad en los
Laboratorios (lectura obligatoria).
Calendario
Entrega: La entrega de la tarea puede realizarse hasta las 20:00 del 16 de
noviembre. Los trabajos deberán ser entregados dentro de los plazos establecidos.
No se aceptarán trabajos fuera de plazo.
Re-Entrega: Todos los estudiantes que realizaron la entrega pueden hacer
modificaciones y realizar una segunda entrega (re-entrega). La re-entrega puede
realizarse hasta las 20:00 del 18 de noviembre.
Forma de entrega
Se debe entregar un único archivo de nombre tarea2.pas que debe contener
únicamente el código de los subprogramas pedidos y eventualmente el de
subprogramas auxiliares que se necesiten para implementarlos. Es suficiente con
que uno de los miembros del grupo realice la entrega.
1
definiciones.pas - Definición de constantes y tipos de datos utilizados
en la tarea.
principal.pas - Programa principal para probar todos los subprogramas
interactivamente.
test y casos de prueba - para ejecutar y verificar todos los subprogramas.
interfaz gráfica para ejecutar el juego.
Estos archivos todavía no están disponibles. Serán publicados en el correr de
esta semana con las instrucciones correspondientes.
Introducción
El objetivo de esta tarea es la implementación de una versión simplificada del
juego arcade Puzzle Bobble.
2
Figura 2: Ejemplo de disparo
Como se puede ver, el balín choca contra una pelota de su mismo color y por lo
tanto elimina todas las pelotas rojas que se tocan en la zona.
Si el balín impacta contra una pelota de otro color, desaparece y la zona de
pelotas queda sin modificaciones.
La siguiente sección describe los tipos de datos que se utilizarán para la
programación del juego.
Escenario
El escenario (o “playing arena”) debe ser entendido como un cuadrante cartesiano
de eje horizontal X = (0..ANCHO) y eje vertical Y = (0..ALTO). Por lo
tanto, las coordenadas horizontales son numeradas en forma ascendente de
izquierda a derecha y las verticales son numeradas en forma ascendente de
abajo hacia arriba. Los vértices del escenario quedan determinados, a partir del
vértice inferior izquierdo y numerados en sentido horario, por las coordenadas
(0, 0), (0, ALTO), (ANCHO, ALTO), (ANCHO, 0).
3
Pelota y Balín
El tipo TPelota especifica la información sobre una pelota: posición en el
escenario x,y, y su color. El tipo TBalin especifica la noción de pelota con
velocidad Vx,Vy.
TColor = (Verde, Rojo, Azul);
TPosicion = record
x, y: integer
end;
TVelocidad = record
Vx, Vy: integer
end;
TPelota = record
posicion: TPosicion;
color: TColor
end;
TBalin = record
pelota: TPelota;
velocidad: TVelocidad
end;
Zona de pelotas
La zona de pelotas está representada como una matriz de dimensión
CANT_FILAS × CANT_COLUMNAS, con CANT_FILAS < ALTO y
CANT_COLUMNAS < ANCHO. Las celdas de la matriz serán valores de tipo
TCeldaPelota, que especifica la información correspondiente a una pelota o
que la celda se encuentra vacía.
TCeldaPelota = record
case ocupada: boolean of
True: (pelota: TPelota);
False:();
end;
RangoFilas = 1..CANT_FILAS;
RangoColumnas = 1..CANT_COLUMNAS;
TZonaPelotas = array [RangoFilas, RangoColumnas] of TCeldaPelota;
En el ejemplo que estamos usando para ilustrar el juego, la zona de pelotas está
definida como una matriz con 5 filas y 8 columnas. Las filas son numeradas en
forma ascendente de arriba hacia abajo y las columnas en forma ascendente de
izquierda a derecha.
4
Secuencia de pelotas
Este tipo de dato representa una secuencia de pelotas. Cada elemento de la
secuencia registra los índices de la zona de pelotas donde se encuentra la
correspondiente pelota.
TIndicePelota = record
i: 1..CANT_FILAS;
j: 1..CANT_COLUMNAS
end;
TSecPelotas = record
sec : array [1..CANT_PELOTAS] of TIndicePelota;
tope: 0..CANT_PELOTAS
end;
Subprogramas
La tarea consiste en la implementación de algunos subprogramas que serán
utilizados para el desarrollo del juego. En esta sección damos una descripción de
estos.
Dar un paso
El procedimiento darUnPaso recibe un balín como parámetro y actualiza su
posición dependiendo de su velocidad.
procedure darUnPaso(var balin: TBalin);
Este subprograma se comporta de manera similar al procedimiento del mismo
nombre de la primera tarea. Sin embargo, se debe prever que el balín puede
rebotar contra un borde y cambiar de dirección.
Explicamos cómo funciona el rebote:
Una vez que se calculó un paso según la velocidad del balín (tal como se hizo
en la primera tarea) se deberá controlar si la pelota queda parcial o totalmente
fuera del escenario. En caso afirmativo, se produce un cambio en la velocidad
del balín. Más precisamente, cambiará el signo de una o ambas componentes de
la velocidad (vx, vy).
Si suponemos que luego de dar el paso, el balín queda en la posición (x, y), se
aplicarán las siguientes reglas para implementar el rebote:
1. Si x + RADIO > ANCHO o x < RADIO la coordenada vx cambia de
signo.
2. Si y + RADIO > ALTO la coordenada vy cambia de signo.
Observar entonces que:
5
El rebote solo afecta a la velocidad, no cambia la posición del balín luego
del paso.
Los cambios de las componentes de la velocidad solo afectan el signo y no
la magnitud de estas.
Puede darse el caso que ambas coordenadas vx y vy cambien de signo en
el rebote.
No hay rebote contra el borde inferior.
El comportamiento anterior no es una representación fiel de un rebote de
una pelota contra una pared, pero se considera una aproximación válida
en el contexto de esta tarea.
Ejemplo:
Si un balín tiene velocidad (vx = 10, vy = 10) y está en contacto con el borde
de la derecha del escenario (x + RADIO > ANCHO), la nueva velocidad de este
balín deberá ser (vx = −10, vy = 10).
Están chocando
La función estanChocando recibe dos pelotas p1 y p2 y retorna true si la
distancia euclidiana entre ellas es menor a la suma de sus radios. Esto equivale a
detectar si las pelotas están en contacto.
dist(p1, p2) < RADIO + RADIO
function estanChocando(p1, p2: TPelota): boolean;
6
Obtener frontera
La función obtenerFrontera toma como parámetro la zona de pelotas y retorna
una secuencia ordenada de las pelotas que forman la frontera, tomando en
cuenta la definición de pelota frontera dada anteriormente.
procedure obtenerFrontera(zonaPelotas: TZonaPelotas;
var frontera: TSecPelotas);
Los índices dentro de la secuencia deben estar ordenados de forma ascendente
según la siguiente relación de orden definida para los índices:
Decimos que (i1 , j1 ) es menor o igual que (i2 , j2 ) si se cumple alguna de
estas condiciones:
• (i1 < i2 )
• (i1 = i2 ) y j1 ≤ j2
Observación: Para obtener la secuencia ordenada, basta con recorrer la matriz
zonaPelotas por filas en orden creciente, es decir, primero se recorre la fila 1,
pasando por los elementos (1,1), (1,2), (1,3) hasta completar la fila, luego la fila
2 y así sucesivamente.
Disparar
El procedimiento disparar toma como parámetro el balín y una secuencia de
pelotas que representa la frontera de la zona de pelotas.
Este procedimiento desplaza el balín, un paso por vez, hasta que choque con
alguna de las pelotas de la frontera o se vaya por el borde inferior sin chocar
ninguna pelota.
procedure disparar(b: TBalin;
frontera: TSecPelotas;
zona : TZonaPelotas;
var indicePelota: TIndicePelota;
var chocaFrontera: boolean);
En el caso en que el balín choca alguna pelota de la frontera de su mismo color,
el procedimiento retorna en el parámetro indicePelota el índice de la primera
pelota chocada y el parámetro chocaFrontera en true. En caso contrario,
chocaFrontera debe ser false y no importa con qué valor queda el parámetro
indicePelota
Podría darse el caso en que el balín colisiona con más de una pelota de la frontera.
En ese caso se retorna la primera que aparece en la frontera (la de índice más
bajo en el arreglo con tope).
7
Eliminar pelotas
Este procedimiento es el encargado de eliminar las pelotas de la zona de pelotas
al final de cada turno.
Recibe como parámetros la zona de pelotas y la secuencia de pelotas a eliminar.
Como resultado, las celdas cuyos índices estén en la lista deberán ser marcadas
como vacías.
procedure eliminarPelotas(var zonaPelotas: TZonaPelotas;
aEliminar: TSecPelotas);
Es zona vacia
La función esZonaVacia será la encargada de indicar cuándo el juego ha termi-
nado.
Toma como parámetro la zona de pelotas y determina si no queda ninguna celda
que contenga una pelota. Es decir, retorna el valor true si no existe una celda
de la zona de pelotas que contenga una pelota.
function esZonaVacia(zonaPelotas: TZonaPelotas): boolean;
Ejemplos
Para ilustrar el comportamiento de algunos de los subprogramas pedidos, se
presentan algunos ejemplos sobre ejecuciones del juego.
Procedimiento disparar
En la figura 4 se presenta el funcionamiento del procedimiento disparar. En
este se puede observar el movimiento de la pelota, dando pasos y rebotando
cuando toca un borde. En este caso, el procedimiento debería devolver i = 4, j
= 4, los índices de la pelota azul que es chocada.
8
Figura 4: Ejemplo de funcionamiento de disparar
Procedimiento eliminarPelotas
Siguiendo el ejemplo anterior, en la figura 5, se presenta el resultado de llamar
al procedimiento eliminarPelotas con el arreglo con tope resultante de pelotas
a eliminar.
Se pide
Escribir un archivo con todos los subprogramas solicitados. Los encabezados de
los subprogramas deben coincidir exactamente con los que aparecen en esta
9
letra. Si el estudiante realiza algún cambio se considerará que el subprograma no
fue implementado. Si el estudiante lo desea, puede implementar subprogramas
auxiliares adicionales (además de los subprogramas pedidos).
Para la corrección, las tareas se compilarán con una versión igual o posterior
a 3.0.4 para Linux. La compilación y la ejecución se realizarán en línea de
comandos. El comando de compilación se invocará de la siguiente manera:
fpc -Co -Cr -Miso -gl principal.pas
principal.pas será el programa principal entregado por el equipo docente.
NO se debe compilar con el IDE de Free Pascal.
No está permitido utilizar facilidades de Free Pascal que no forman parte del
estándar y no se dan en el curso. Así por ejemplo, no se puede utilizar ninguna de
las palabras siguientes: uses, crlscr, gotoxy, crt, readkey, longint, string,
break, etcétera.
En esta tarea, como en todos los problemas de este curso, se valorará, además de
la lógica correcta, la utilización de un buen estilo de programación de acuerdo a
los criterios impartidos en el curso. De esta manera, se hará énfasis en buenas
prácticas de programación que lleven a un código legible, bien documentado y
mantenible, tales como:
indentación adecuada,
utilización correcta y apropiada de las estructuras de control,
código claro y legible,
algoritmos razonablemente eficientes,
utilización de comentarios que documenten y complementen el código,
utilización de constantes simbólicas,
nombres mnemotécnicos para variables, constantes, etcétera.
Para resolver la tarea se pueden utilizar todos los conocimientos vistos en el
curso.
10