Tarea 2

Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1de 10

Programación 1 - 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.

Archivos provistos y ejecución de pruebas


Al igual que en la primera tarea, se dejará a disposición de los estudiantes los
siguientes archivos:

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.

Figura 1: Versión simplificada del juego Puzzle Bobble

Puzzle Bobble es un juego basado en turnos, donde el objetivo es quitar del


escenario todas las pelotas en la menor cantidad de turnos posible.
Al inicio de cada turno, aparece una nueva pelota a disparar (balín) con un color
seleccionado al azar. El jugador debe elegir la dirección con la que disparará al
balín (ilustrado con la flecha negra en el ejemplo) para impactar en la zona de
pelotas. Cuando el balín choca con alguna pelota de la zona de pelotas, elimina
todas las pelotas que sean de su mismo color y se estén tocando. Un ejemplo de
un turno se presenta en la figura 2.

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.

Constantes y tipos de datos


Las constantes y tipos de datos son provistos por los docentes en el archivo
definiciones.pas. Este archivo no se debe modificar.
Se definen las siguientes constantes, todas de valor entero positivo, para repre-
sentar el escenario y la zona de pelotas:
ALTO = ...; {Altura del escenario}
ANCHO = ...; {Ancho del escenario}
RADIO = ...; {Radio de las pelotas}
CANT_FILAS = ...; {Cantidad de filas de la zona de pelotas}
CANT_COLUMNAS = ...; {Cantidad de columnas de la zona de pelotas}
CANT_PELOTAS = CANT_FILAS * CANT_COLUMNAS; {Cantidad máxima de pelotas en frontera}

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;

Es frontera (o pertenece a la frontera)


En un turno cualquiera, se dice que una pelota es frontera si esta puede puede
ser colisionada por el balín en ese turno.
Como la condición de frontera tiene que ver con la ubicación de la pelota dentro
de la zona de pelotas hablaremos más específicamente de celda frontera.
function esFrontera(indicePelota: TIndicePelota;
zonaPelotas: TZonaPelotas): boolean;
La función esFrontera toma como parámetros la zona de pelotas y un índice de
pelota. Retorna un valor de tipo boolean que indica si ese índice corresponde a
una celda frontera.
Más formalmente, diremos que una celda de la zona de pelotas es frontera si
está ocupada y además cumple alguna de las siguientes condiciones:
Se encuentra en los límites de la zona de pelotas. Esto es: la celda está en
la primera o última fila o en la primera o última columna de la zona.
Tiene al menos una celda vecina que está vacía.
Se considera que dos celdas son vecinas si comparten un lado horizontal o vertical.
No se consideran vecinas cuando comparten solo un vértice (contacto diagonal).

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.

Frontera de una Zona de pelotas


En la figura 3 se muestra una zona de pelotas y el resultado esperado al llamar
a la función obtenerFrontera sobre la zona.

Figura 3: Ejemplo de resultado de obtenerFrontera

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.

Figura 5: Ejemplo de resultado de eliminarPelotas

Observación: La pelota que está en la posición i = 4, j = 6 no es eliminada


porque no se considera adyacencia solamente diagonal.

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

También podría gustarte