Una longeva radioemisora va a transmitir su programación por Internet (streaming). Está digitalizando su repertorio al formato de audio Opus, pero el software de reproducción no respeta las pautas de la emisora y las elecciones al azar son terribles. Por ejemplo, a veces repite la misma canción o anuncio dos veces seguidas, lo cual da la impresión de un error de quien está a cargo. Escriba un programa en Java que ayude a generar listas de reproducción (playlists) respetando las reglas de la radioemisora.
El programa recibirá en la entrada estándar una acción por línea. Las acciones constan de campos que están separados por barras verticales (|). El primer campo indica el tipo de acción y se explican a continuación.
Las acciones jingle
, song
, y ad
, registran una nueva grabación en el repertorio de la emisora. Un jingle es un trozo de audio que da identidad a la emisora. Cuando una persona escucha este sonido, reconoce de inmediato que se trata de esta emisora y no otra. Son audios creados por encargo para la emisora misma. Una canción (song
) es una grabación musical realizada por artistas. Un anuncio (ad
) es una grabación con fines publicitarios de una organización que paga a la radioemisora por reproducir el anuncio durante un periodo de tiempo. Los anuncios son la principal fuente de ingresos de la emisora.
Indiferentemente de su tipo, toda grabación tiene los mismos campos: (1) Un número identificador (id
) no necesariamente secuencial. Dos grabaciones pueden tener el mismo número identificador si son de tipos diferentes. (2) El artista u organización que creó la grabación. (3) Un título que ayuda a los humanos a reconocer la grabación. (4) El año en que se publicó la grabación. (5) La duración de la grabación en formato minutos:segundos
.
Ejemplo de entrada:
jingle|21|Radio X|Lema 1|1957|0:03
song|329|Ben E. King|Stand By Me|1961|2:55
jingle|25|Radio X|Interludio|1968|0:01
song|1301|Paul Mauriat|L'amour est bleu|1968|2:31
song|1488|Arturo Benavides|Desiderata|1971|4:02
song|2478|Vicente Fernández|La ley del monte|1975|3:23
song|2790|Willie Colón & Rubén Blades|Plástico|1978|6:37
song|4917|Simply Red|Holding Back The Years|1985|4:28
song|6083|Néctar|Amor, amor vida mía|1987|3:25
ad|4488|MegaSuper|Viernes negro|2023|0:28
ad|4482|JPS|Rifa 100 enteros/viernes|2023|0:20
song|6240|Tony Camargo|El año viejo|1953|3:05
playlist|Sin anuncios|jingle song song song|15:00|2312051
Ejemplo de salida:
#EXTM3U
#PLAYLIST:Sin anuncios (18:34)
#EXTINF:1,Radio X - Interludio [1968]
jingle/25.opus
#EXTINF:205,Néctar - Amor, amor vida mía [1987]
song/6083.opus
#EXTINF:397,Willie Colón & Rubén Blades - Plástico [1978]
song/2790.opus
#EXTINF:268,Simply Red - Holding Back The Years [1985]
song/4917.opus
#EXTINF:1,Radio X - Interludio [1968]
jingle/25.opus
#EXTINF:242,Arturo Benavides - Desiderata [1971]
song/1488.opus
La acción playlist
solicita generar una lista de reproducción. Sus campos son: (1) Un título para la lista, (2) una pauta, (3) su duración en formato minutos:segundos, y (4) una semilla. Una pauta es un patrón repetitivo de tipos de grabaciones. Es un texto que se forma con las palabras jingle
, song
, y ad
separadas por espacios en blanco. Puede pensarse como una plantilla de un programa de radio. Este patrón se repite una y otra vez durante la duración del programa radial. El sistema toma la pauta y reemplaza cada tipo de grabación por una grabación de ese tipo escogida al azar. Sin embargo, dados los terribles resultados del azar de otros software, se necesita que su sistema aplique las reglas de programación de la emisora, como las dos siguientes:
-
Una canción no puede repetirse en menos de 3 horas. Si una canción fue escogida, podrá aparecer hasta después de 3 horas más adelante en la misma lista de reproducción. Para esta versión del sistema, los jingles y anuncios no se afectan por esta regla.
-
Si una canción B va a sonar inmediatamente después que otra canción A, la canción B tiene que estar en un rango máximo de 10 años antes o después de la canción A. Por ejemplo, si tras reproducir una canción de 1983, y la pauta indica que continúa otra canción (no un anuncio ni jingle), sólo una canción entre 1973 (inclusive) y 1993 (inclusive) podría ser seleccionada al azar. Esta regla evita cambios bruscos de estilo.
Cuando el sistema agrega una grabación a la lista de producción, incrementa la duración de la lista en la duración de la grabación. Si la duración de la lista es mayor o igual a la duración solicitada en la entrada, el sistema se detiene. En caso contrario continúa con el siguiente tipo de grabación indicado en la pauta. Si la pauta se acaba y no ha alcanzado la duración esperada, repite otra vez la pauta seleccionando grabaciones al azar de cada tipo, y así repetitivamente hasta alcanzar o sobrepasar la duración solicitada.
La acción playlist
es la única que genera texto en la salida estándar. La lista de reproducción debe imprimirse en el popular formato EXTended Mp3 Url (EXTM3U
). Su primera línea, conocida como encabezado, siempre es el comentario #EXTM3U
. Es seguida por el comentario #PLAYLIST:título (mm:ss)
que indica el título de la lista, y a petición de la emisora, su duración real medida en minutos (mm
) y segundos (ss
). Continúan las grabaciones que el sistema escogió al azar.
Cada grabación se compone de dos líneas. La primera es un comentario con información en la forma #EXTINF:duracion_en_segundos,Artista - Título [Año]
. La segunda línea contiene la dirección (URL) para encontrar el archivo de audio en formato tipo_grabacion/id.opus
, donde id
es el identificador numérico de la grabación. Si en la entrada aparecieran varias acciones playlist
, generarán varias secciones #PLAYLIST
en la salida estándar. Sin embargo, el encabezado #EXTM3U
no debe repetirse, es decir sólo aparece una vez.
A la hora de escoger una grabación, su programa debe identificar todas las grabaciones que cumplen las dos reglas de la emisora, y escoger una al azar. Para efectos de hacer coincidir la salida con la del juez en línea, cree un objeto java.util.Random(semilla)
. Use la semilla provista en el último campo de la acción playlist
. Genere luego números pseudoaleatorios con el método nextInt(n)
, que retorna un entero en el rango {0, …, n-1}.
1. Evaluación
En todos los rubros se evalúan las buenas prácticas de programación, la convención de estilos, indentación y modularización. Para efectos de esta prueba no puede utilizar colecciones de la biblioteca estándar de Java ni de terceros, excepto arreglos dinámicos (ArrayList<>). No es necesario que haga las importaciones de las clases en su solución en papel. En su solución en papel puede suponer que los datos en la entrada estándar son válidos (no es necesario realizar validaciones). Su solución debe ser orientada a objetos, con al menos las clases que se detallan a continuación:
-
[20%] Diseño orientado a objetos en UML: diagrama de clases con sus atributos, métodos, y relaciones.
-
[15%] Implementación de una clase controladora. Sus atributos son modelos, colecciones de modelos, u otros campos que requiera para resolver el problema. Inicia la ejecución del programa. Analiza las acciones. Pide a los objetos modelo cargarse de la entrada estándar. Genera listas de reproducción en memoria. Imprime las listas en la salida estándar. Delega en otras clases. Maneja excepciones.
-
[25%] Implementación de la clase modelo para representar listas de reproducción. Carga sus atributos desde la entrada estándar. Llena la lista de reproducción escogiendo al azar entre las grabaciones candidatas siguiendo la pauta. Delega responsabilidad en otras clases modelo.
-
[20%] Dado que una lista de reproducción de una emisora sigue el orden "primero en llegar, primero en ser atendido" y los arreglos (estáticos o dinámicos) no aseguran este orden, implemente de una estructura de datos simplemente enlazada y eficiente para almacenar grabaciones imponiendo este orden. Provea métodos para crear esta estructura de datos vacía, determinar si está vacía, agregar grabaciones al final, y extraer la primera grabación en la cola. Puede permitir acceder al primer o último elemento sin modificar la estructura de datos. Sugerencia: dado que es una estructura de datos de grabaciones, en lugar de la cantidad de elementos almacenados en ella, puede llevar control de su duración.
-
[20%] Implementación de la clase modelo para representar grabaciones. Carga sus atributos de un archivo (Scanner). Se imprime en la salida estándar en formato M3U o se convierte a un texto en este formato con toString(). Indica si puede o no ser seleccionada como la próxima entrada en una lista de reproducción. En caso de ser una canción, lleva rastro de cuándo fue la última vez que fue seleccionada.
-
[+10%] Transcribe y corrige su diseño (UML) y código Java. Pasa los casos de prueba en el juez en línea.