PRO2

L2: Uso de clases

Esta práctica tampoco utiliza el Jutge! De nuevo deberás ser tú mismx quien compruebe que todo funciona como debe 😉. Recuerda que lx profesorx te puede ayudar en todo lo que necesites.

Objetivos de esta sesión:

  • Documentar-se sobre los métodos de una clase de diversas maneras.
  • Usar clases con métodos documentados sin conocer/entender su implementación.

Parte I: La clase string

Usar una clase es como usar una máquina con botones, hace falta un manual que diga qué botones hay, y qué hace cada uno. El manual de la clase string es la documentación de referencia. Lo más importante es la lista de métodos (o "Member Functions").

La clase string tiene muchos métodos, pero para simplificar, nos podemos quedar con los 3 siguientes:

MétodoDocumentación
findEncuentra un trozo de texto en el string
substrDevuelve una copia de una parte del string
replaceReemplaza una parte del string por otro string

Ejemplos:

find:

// int string::find(const char *a_buscar, int desde);
string s = "a bb ccc bb";
int pos1 = s.find("bb", 0); // desde 0: pos1 -> 2
int pos2 = s.find("bb", 5); // desde 5: pos2 -> 9

substr:

// string string::substr(int desde, int longitud);
string s = "1234567";
string tros = s.substr(2, 3); // tros -> "345"

replace:

// void string::replace(int pos, int num_borra, string inserta);
string s = "bar???ona";
s.replace(3, 3, "cel"); // s -> "barcelona"

Partir un string en trozos

Una operación común que algunos lenguajes tienen (pero C++ no 😕), es la siguiente. Dado un string formado por un texto con separadores, como "a; b; c; d", devolver un vector con cada uno de los trozos resultantes de dividir el string por el separador. Si éste fuese "; ", el resultado sería el vector {"a", "b", "c", "d"}.

Así pues, descarga este programa:

split.tgz

Compílalo y observa cómo está hecho. En particular:

  • La función split con su documentación (y el hecho de que al colocar el cursor sobre las llamadas a la función, aparece la documentación).
  • Qué métodos utiliza el código para poder realizar las operaciones.
  • El operator<<, que permite imprimir vectores. (Úsalo en tus propios programas.) Es un template para permitir que se pueda aplicar en vectores de cualquier tipo.
  • Los resultados que se devuelven para cada caso (sobretodo con el separador vacío).

Ejercicio 1: Un dictador llamado Trumpf ha decidido que para que haya auténtica libertad de expresión, se deben prohibir todas las ocurrencias de la palabra "trumpet" de todos los textos del mundo. Es evidente que semejante palabreja es ofensiva e intolerable en el mundo actual. Documéntate sobre el método replace (mira la versión 8, hay demasiadas 😅) y la acción getline y hazle un programa a Trumpf que lea cada línea de la entrada y reemplace "trumpet" por "[redacted]". Haz la versión más simple de detectar cualquier ocurrencia como palabra o subpalabra, al principio o al final.

¿Sin el Jutge, cómo vas a saber cuándo el programa funciona correctamente?

Ejercicio 2: Haz la función complementaria a split, llamada join, que recibe un vector<string> y concatena los strings (los trozos) con un separador entre cada pareja de trozos y devuelve el string resultante. Piensa qué parámetros tiene, qué pre-condiciones tienen, y escríbela con documentación Doxygen, tomando a split como modelo.

Parte II: Fecha reloaded

La práctica anterior trataba sobre un grupo de funciones para trabajar con fechas. En esta sesión trabajaremos con la clase Fecha.

Descarga el .tar y descomprímelo en un directorio (el mismo tar creará un directorio fecha):

fecha.tgz

Sitúate en el directorio descomprimido con un terminal y haz:

make

Deberías ver una salida como

g++ -c main.cc
g++ -c fecha.cc
g++ -o demo_fechas main.o fecha.o

Ejecuta el programa demo_fechas para ver qué hace y luego familiarízate con el programa principal (main.cc). Para poder ver qué hace un método, coloca el cursor del ratón encima de cada método y lee la documentación que aparece:

Ejemplo de ayuda para un método

Ejercicio 3: Usa la clase Fecha para hacer un programa que lee una secuencia de fechas de la entrada y las muestra por orden después. Usa la ordenación que sea menos esfuerzo pero piensa en qué opciones tienes dados los métodos de Fecha.

Ejercicio 4: Haz una función dias_diferencia que recibe dos Fechas y devuelve el número de días que las separan (piensa qué ocurre si te las pasan en el orden inverso a cómo las esperas y qué se le puede hacer). El ejercicio debe hacerse sin cambiar la clase Fecha en absoluto, y solamente usando los métodos disponibles, incluso si tu implementación te parece muy ineficiente.

Si recuerdas, la representación de la Fecha utiliza los campos dia, mes, y anyo. Con esta representación, se podría hacer un algoritmo mucho más eficiente, si dispusiéramos de métodos públicos como dias_mes o es_bisiesto que no se han hecho públicos en fecha.hh. Aún así, sería complejo gestionar toda la casuística del algoritmo para asegurar que sea correcto.

Ejercicio 5: Investiga sobre el "epoch" y la forma de almacenar el tiempo en Unix y reflexiona sobre el problema anterior nuevamente. De las siguientes operaciones, indica cuáles son eficientes y cuáles no:

OperaciónDia+Mes+AnyoEpoch
Mostrar la fecha como DD/MM/AAAA
Sumar una cantidad de días
Diferencia entre días
Comparar dos fechas
Determinar si una fecha es menor

Parte III: Ventanas!

Las dos secciones siguientes usan una clase Window que permite abrir una ventana pintar en ella y detectar teclas y clicks del ratón. La clase dispone de los siguientes métodos:

  • Window::Window(titulo, ancho, alto, zoom): Constructor, abre una ventana con un titulo, de ancho ×\times alto píxeles, y con una amplificación de zoom (cada pixel de Window es de zoom ×\times zoom píxeles reales).

  • bool Window::next_frame(): Procesa eventos, refresca la ventana y espera hasta el siguiente fotograma. Devuelve false si el usuario ha cerrado la ventana.

  • void Window::clear(color): Pinta toda la ventana con un color (por defecto, el negro).

  • void Window::set_pixel(pt, color): Pinta un solo pixel con un color(pt es una tupla con dos campos x e y).

  • bool Window::is_key_pressed(key): Devuelve true si una tecla está presionada.

  • bool Window::is_mouse_pressed(): Devuelve true si el botón izquierdo del ratón está presionado.

  • Pt Window::mouse_pos(): Devuelve la posición del ratón (una tupla con x e y).

  • void Window::sleep(ms): Pausa el programa ms milisegundos.

  • int Window::frame_count(): Devuelve el número de fotogramas transcurridos hasta el momento.

La documentación de los métodos está en formato Doxygen en window.hh, así que para los detalles, consultad la documentación que aparece en VSCode al ir utilizando los métodos.

Stop Motion

window1-stop-motion.tgz

Descarga el .tgz y descomprímelo. Compila y ejecuta para ver qué hace el programa. El código demuestra cómo hacer bastantes cosas, revisa que las entiendes y consulta con el profesor todo aquello que no veas claro.

Ejercicio 6: Busca en el código el sitio donde se decide el tamaño de la ventana y cambia tanto la anchura como la altura y prueba cómo afecta al programa. Cambia también el "zoom" y observa qué ocurre.

Ejercicio 7: Explica porqué hay un if en las dos funciones progress_bar_up y pixel_down como este:

if (!window.next_frame()) {
   return false;
}

Ejercicio 8: ¿Qué ocurrirá si quitamos la instrucción window.clear() de la línea 29? Piénsalo antes sin probarlo! 😉.

Animación

window2-animation.tgz

Como de costumbre, descarga, compila y ejecuta el ejemplo. En este caso, la ventana muestra una línea que sube y baja y si clicas con el ratón, muestra una línea amarilla allí donde cliques. Pregunta al profesor lo que no entiendas del código.

Ejercicio 9: Haz que la línea roja solo se muestre si estás apretando la barra espaciadora.

Ejercicio 10: Haz que la línea amarilla se muestre siempre que el ratón esté encima de la ventana, no solo si clicas.

Ejercicio 11: Cambia las dos barras, roja y amarilla, para que sean barras verticales, en vez de horizontales, manteniendo la misma funcionalidad del programa.

Mario

window3-mario.tgz

Descarga, compila... ya sabes, lo de siempre.

Ejercicio 12: Haz que Mario se pueda controlar con el teclado, de forma que al presionar las teclas de flechas arriba, abajo, derecha e izquierda, el personaje se mueva en la dirección apropiada. Ignora los límites de la ventana, por ahora.

Ejercicio 13: Haz que Mario choque al llegar a los límites de la ventana y no pueda traspasarlos.

Parte IV: Impresora a Color

Descarga el .tar siguiente y descomprímelo en una carpeta:

color-printer.tgz

La clase ColorPrinter sirve para mostrar mensajes en color en el terminal. Los terminales de Linux son emuladores de terminales físicos anteriores que tenían formas de mostrar colores y cambios en la fuente.

Compila demo_color_printer usando el Makefile y comprueba lo que hace. Documéntate sobre lo que hace la clase y como se utiliza mirando la documentación y leyendo el programa principal.

Ejercicio 14: Muestra una bandera multicolor hecha de asteriscos en el terminal.

Ejercicio 15: Cambia el ejercicio del señor Trumpf para que la palabra [redacted] salga en rojo, y facilite el hecho de encontrar las ocurrencias eliminadas.