Fork me on GitHub

Memorias II Concurso de Programación de la Carrera de Computación

Jaime Salvador M.
Quito, Ecuador

Zoila Ruiz Ch.
Quito, Ecuador

Sandra Navarrete P.
Quito, Ecuador

© 2025 por Jaime Salvador, Zoila Ruiz, Sandra Navarrete.

Este documento, así como el software descrito en el mismo, se entrega bajo licencia y puede ser utilizado y copiado de acuerdo a los términos de su respectiva licencia. La información contenida en este documento puede estar sujeta a cambios sin previo aviso. El autor no asume ningún tipo de responsabilidad por cualquier omisión, error o cambios que puedan darse en el presente manual. Se prohíbe prestar, vender, alquilar o entregar este documento y el software descrito en este documento de ninguna forma sin el permiso previo por escrito del autor, excepto en la medida permitida por la ley.

Los artes, imágenes o logotipos que constan en este documento también se encuentran protegidas por las leyes de derecho de autor. Cualquier otro nombre o nombres de productos usados en este documento son marcas registradas o marcas comerciales de sus respectivos propietarios.

Este documento podría incluir imprecisiones técnicas o errores tipográficos. Periódicamente, se realizan cambios en la información contenida en este documento. Estos cambios pueden incorporarse en nuevas ediciones de este documento. El autor puede realizar mejoras o cambios en el software descrito en este documento en cualquier momento.

Este documento hace referencia a marcas comerciales registrados por terceras personas o instituciones.

Publicado en julio de 2025

Agradecimientos

Gracias a todos quienes contribuyeron…​

Introduccion

La Carrera de Computación ha sido diseñada con un alto componente en desarrollo de software de alto rendimiento (HPC), este enfoque no solo abarca los fundamentos teóricos, sino que también pone un énfasis particular en las aplicaciones prácticas y avanzadas en áreas clave como la Programación y la Programación de Alto Rendimiento, que son esenciales para enfrentar los desafíos actuales en el campo tecnológico y profesional.

El plan de estudios está estructurado para ofrecer una formación profunda y especializada a los estudiantes, orientada a la creación de software que maximice la eficiencia y el rendimiento en entornos que requieren altas demandas de procesamiento y recursos, tales como el análisis de problemas relacionados con procesamiento de grandes volúmenes de datos, aplicación de arquitecturas y sistemas distribuidos.

Tomando en consideración que los fundamentos conceptuales en programación en Java son esenciales para alcanzar una formación profesional de excelencia en el desarrollo de software, ya que proporcionan las bases necesarias para comprender cómo funcionan los lenguajes de programación y sus estructuras subyacentes. Estos principios permiten a los programadores no solo escribir código eficiente y funcional, sino también resolver problemas complejos de manera lógica y estructurada. El dominio de conceptos como la programación orientada a objetos, el manejo de excepciones, la gestión de memoria, el diseño de algoritmos y programación funcional, entre otros, es crucial para crear aplicaciones robustas y escalables. Sin estos conocimientos fundamentales, los desarrolladores podrían enfrentarse a dificultades a la hora de optimizar sus soluciones o de adaptarse a nuevas tecnologías, limitando así su capacidad para enfrentar los retos de la industria del software con creatividad y eficiencia.

Zoila Ruiz, Jaime Salvador

Control de versiones

Versión Fecha Autor Observación

1.0

2025-07-05

Jaime Salvador

Versión inicial

Versión 1.0

  • Versión inicial del documento.

Reglamento del Concurso

Este concurso consiste en que los estudiantes de los distintos semestres puedan mostrar sus habilidades en las dos áreas de la Carrera: Programación y Programación de Alto Rendimiento, a través del desarrollo de aplicaciones de acuerdo con los niveles establecidos para el concurso:

  • Básica

  • Media

  • Avanzada

Las materias que corresponden a cada nivel se las describe a continuación:

Básica:

  • Programación I

  • Programación II

  • Estructura de Datos

Media:

  • Base de Datos I

  • Patrones de diseño de Software

  • Programación Avanzada I

  • Programación Avanzada II

  • Programación Avanzada III

Avanzada:

  • Dispositivos Móviles

  • Programación Web

  • Programación Concurrente y Paralela

  • Programación Distribuida

Objetivos

  1. Incentivar la difusión y el interés por la programación en los estudiantes de la Carrera.

  2. Organizar concursos para distinguir y premiar a los mejores programadores.

  3. Dar accesibilidad a todos los estudiantes interesados de la Carrera de Computación, para demostrar sus destrezas en el campo de desarrollo de software.

Participantes

Se invita a todos los estudiantes de la Carrera de Computación y Sistemas de Información de la Facultad de Ingeniería y Ciencias Aplicadas a participar del concurso.

Los estudiantes deben estar matriculados en la Carrera de Computación o Sistemas de Información.

Cronograma

El concurso se realizará el viernes 27 de junio de 2025, desde las 7:00 hasta las 17:00 en los laboratorios de Post grado (Edificio de Aulas, 4to piso) (POST A, POST B) y los laboratorios de computadoras (SALA A y SALA B).

El concurso (parte práctica) está dividido en 3 etapas o retos, de tal forma que, en cada etapa se presenta a los estudiantes en cada categoría un reto a ser desarrollado en un tiempo establecido, se califica y se informa sobre los resultados y quienes pasan a la siguiente etapa.

A la tercera etapa o final se presentarán los n estudiantes que alcancen el más alto puntaje en cada categoría. Más detalles en la Modalidad.

  • G1: nivel básico

  • G2: nivel medio

  • G3: nivel avanzado

El cronograma del concurso es el siguiente:

Tabla 1. Cronograma del Concurso
HORA SALA A SALA B POST A POST B

7:00

G1: reto 1

G1: reto 1

G1: reto 1

G1: reto 1

7:50

8:20

REVISIÓN Y CALIFICACIÓN

8:30

G2: reto 1

G2: reto 1

G2: reto 1

G2: reto 1

9:20

9:50

REVISIÓN Y CALIFICACIÓN

10:00

G3: reto 1

G3: reto 1

10:50

11:20

REVISIÓN Y CALIFICACIÓN

12:00

G1: reto 2

G2: reto 2

G3: reto 2

13:30

14:00

REVISIÓN Y CALIFICACIÓN

14:30

G1, G2, G3: reto 3

16:30

16:50

REVISIÓN Y CALIFICACIÓN

Se debe considerar los horarios y estar listos en los laboratorios con un mínimo de 10 minutos antes de lo mencionado en el calendario. SI LOS ESTUDIANTES NO ESTAN EN EL HORARIO INDICADO SERÁN DESCALIFICADOS (07:00).

Modalidad

La modalidad del concurso (parte práctica) se basa en la resolución de retos presentados a los estudiantes de cada nivel, poniendo en práctica sus conocimientos y habilidades en desarrollo de software. Basada en un enfoque estructurado y práctico que permite evaluar las habilidades técnicas y creativas de los participantes.

Las soluciones a los retos SERAN CALIFICADAS en los equipos de cómputo asignados a los participantes.

Se ha definido las siguientes fases a desarrollarse en el transcurso del concurso el viernes 27 de junio:

  1. Inicio de Competencia: Durante esta fase, a las 7:00 am, se da la bienvenida a los participantes y se brinda las indicaciones sobre reglas generales a seguir durante la competencia en cada uno de los laboratorios.

  2. Desarrollo y resolución de retos: A partir de las 7:00 am, los concursantes trabajan de manera individual para resolver los problemas de programación presentados. Los retos pueden variar en dificultad y abarcar diferentes temas de acuerdo con el nivel y semestre al que pertenezca. Los participantes deben analizar, diseñar y desarrollar una solución a un problema de programación dentro del plazo determinado.

  3. Monitoreo y Soporte Técnico: Durante la competencia, los docentes brindan apoyo técnico y resuelven incidencias que los participantes puedan encontrar mientras trabajan en los retos.

  4. Selección y clasificación de participantes: La competencia consta de tres retos por categoría, en el: PRIMER RETO: participan todos los estudiantes inscritos, sus respuestas son valoradas y clasifican al SEGUNDO RETO (20 ALUMNOS POR CADA CATEGORÍA): nivel básico: los 20 estudiantes que hayan obtenido el mejor puntaje, nivel medio: los 20 estudiantes que hayan obtenido el mejor puntaje y nivel avanzado los 20 estudiantes que hayan obtenido el mejor puntaje. TERCER RETO: Pasan a la final los 5 estudiantes con mejor puntaje en cada nivel, en este reto se obtiene al GANADOR de cada categoría.

  5. Cierre de la Competencia: Al finalizar el tiempo estipulado para el tercer reto, los participantes entregan sus soluciones y se da por cerrada la fase de competencia, se valora los programas entregados y se da los resultados finales, declarando a los ganadores en cada categoría.

  6. Evaluación Técnica: Un equipo de docentes expertos en el área evalúa las soluciones de los participantes en cada reto, en función de criterios como la eficiencia del código, la creatividad, la correcta implementación de algoritmos, el cumplimiento de los requisitos del problema y el nivel de complejidad, verificando la originalidad de las soluciones, a través de una rúbrica predefinida, que garantiza un mismo criterio de evaluación.

Reglas del Concurso

La resolución de retos, dentro del campo de desarrollo de software, de acuerdo con el nivel que estén cursando los estudiantes y los conocimientos adquiridos hasta el momento en el área de desarrollo, deben cumplir con las siguientes reglas:

  1. Los programas que resuelvan los retos presentados en cada etapa del concurso deben ser desarrollado en el lenguaje de programación JAVA, y herramientas adicionales de acuerdo con el nivel.

  2. En el primer reto se descalificará a los estudiantes que sus programas tengan errores de compilación o no tengan la funcionalidad completa.

  3. Se debe respetar los estándares de programación y los conceptos aprendidos en las distintas asignaturas, de acuerdo con el semestre del estudiante.

  4. No se permitirá el uso de IA para resolución de los retos, como por ejemplo ChatGPT, celulares o cualquier dispositivo electrónico, el participante que haga uso de estas herramientas será descalificado de la competencia.

  5. Si existe empate en los distintos restos, se incluirán a los participantes que obtenga la misma calificación.

  6. De existir empate en la final, se tomará un nuevo reto para definir a los ganadores. Si el tiempo lo permite será el mismo día, caso contrario se definirá el día y hora del reto de desempate.

Evaluación de los retos

Los retos serán evaluados por docentes de la carrera que apoyan con este proceso.

  • Ing. Jaime Salvador, PhD

  • Ing. Zoila Ruiz, PhD

  • Ing. Sandra Navarrete, Msc

  • Ing. Giovanny Moncayo, PhD

  • Docentes de las áreas de Programación y Programación de Alto Rendimiento

Los criterios específicos para tomar en cuenta serán fijados de acuerdo con el nivel en que se encuentre el estudiante y el reto a desarrollar, los que serán entregados de forma impresa el momento de la participación del estudiante (reto y rúbrica).

Entre los criterios generales serán considerados los siguientes puntos:

  • La aplicación de conceptos básicos de estándares de programación.

  • Problema que resuelve el reto basado en conocimientos adquiridos por el estudiante.

  • Eficiencia y solución del programa planteado en el respectivo reto.

Premios

En cada nivel considerado del concurso se entregará un premio a los tres primeros lugares, los que han sido gestionados por la Dirección de Carrera de Computación, así como diplomas a los tres primeros lugares y diplomas digitales de participación a todos los estudiantes del concurso.

Parte I: Nivel Básico

El nivel básico del concurso de programación está orientado a la creación de aplicaciones sencillas, que requieren un conocimiento básico de las tecnologías y herramientas utilizadas.

Los temas comprendidos en este nivel incluyen:

  • Programación

  • Estructura de datos

1. Triángulo de Pascal

El objetivo de este reto es implementar un programa en Java que genere y muestre el Triángulo de Pascal hasta un número dado de filas. El Triángulo de Pascal es una estructura matemática que se utiliza en combinatoria y teoría de números, y se construye de manera que cada número es la suma de los dos números directamente encima de él en la fila anterior.

1.1. Reto 1 - Nivel básico 1

Escriba un programa en Java que genere y muestre el Triángulo de Pascal hasta un número dado de filas.

El Triángulo de Pascal se construye comenzando con un 1 en la primera fila. Cada número subsiguiente en la fila se obtiene sumando los dos números directamente encima de él en la fila anterior. La primera y última posición de cada fila siempre son 1. (EJM. Fila 4)

Empieza con 1, el siguiente es la suma del 1er y 2do elem = 1+3, el 2do con el 3ero = 3+3 …..

Requisitos:

  • El programa debe pedir al usuario la cantidad de filas del Triángulo de Pascal que desea mostrar.

  • Utiliza un método para calcular cada elemento del triángulo.

  • Muestra el triángulo con una adecuada alineación para que tenga forma triangular.

Ejemplo:

Si el usuario ingresa 5, el programa debe mostrar:

    1
  1 2 1
 1 3 3 1
1 4 6 4 1

Criterios de Calificación:

El código será evaluado de la siguiente manera:

  1. Descalificación inmediata si el código no compila (errores de compilación).

  2. Descalificación si el resultado generado no coincide con lo solicitado.

  3. Calcula correctamente los elementos del triángulo

  4. Muestra el triángulo de forma correcta

1.2. Solución

A continuación se presenta una posible solución al reto, que incluye la implementación de la clase TrianguloPascal y una aplicación para interactuar con el usuario.

Estructura de directorio del proyecto:

src
└── main
    └── java
       └── com
            └── concurso
                └── basico
                    └── reto11
                        ├── AppTriangulo.java
                        └── TrianguloPascal.java

LA clase TrianguloPascal contiene la lógica para generar el Triángulo de Pascal.

Listado 1. Nivel Básico - reto 1 - nivel 1: TrianguloPascal.java
package com.concurso.basico.reto11;

public class TrianguloPascal {
    private int[][] pascal;

    public TrianguloPascal(int n) {
        pascal = new int[n][n];
        llenarPascal();
    }

    // Llenar la matriz con los valores del Triángulo de Pascal
    public void llenarPascal() {

        for (int fila = 0; fila < pascal.length; fila++) {
            for (int col = 0; col <= fila; col++) {
                if (col == 0 || col == fila) {
                    pascal[fila][col] = 1; // Los bordes son siempre 1
                } else {
                    pascal[fila][col] = pascal[fila - 1][col - 1]
                            + pascal[fila - 1][col];
                }
            }
        }
    }

    // Imprimir el Triángulo de Pascal
    public void imprimir() {
        for (int fila = 0; fila < pascal.length; fila++) {
            // Imprimir espacios para centrar
            for (int es = 0; es < pascal.length - fila - 1; es++) {
                System.out.print("  ");
            }
            // Imprimir los números de la fila
            for (int col = 0; col <= fila; col++) {
                System.out.printf("%4d", pascal[fila][col]);
            }
            System.out.println();
        }
    }
}

La clase AppTriangulo es la aplicación principal que interactúa con el usuario y muestra el triángulo.

Listado 2. Nivel Básico - reto 1 - nivel 1: AppTriangulo.java
package com.concurso.basico.reto11;

import java.util.Scanner;

public class AppTriangulo {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.print(
                "Ingrese el tamaño del Triángulo de Pascal: "
        );
        int n = scanner.nextInt();
        TrianguloPascal t = new TrianguloPascal(n);
        t.imprimir();
    }
}

2. Búsqueda en Laberinto

El objetivo de este reto es implementar un programa en Java que permita encontrar un camino desde una posición inicial hasta una posición final en un laberinto representado por una matriz. El laberinto puede contener espacios libres (representados por 0) y paredes (representadas por 1).

2.1. Reto 1 - Nivel básico 2

Implementar un algoritmo recursivo que encuentre todas las rutas posibles desde la esquina superior izquierda (0, 0) hasta la esquina inferior derecha (n-1, n-1) de una matriz cuadrada, donde: 0: Camino transitable; 1: Pared (bloqueo); Movimientos permitidos: Solo derecha (→) o abajo (↓).

Ejemplo de 5x5

Rutas:

(0,0)→(0,1)→(1,1)→(1,2)→(1,3)→(2,3)→(3,3)→(3,4)→(4,4)

Requisitos Específicos

  • Entrada:

    • Matriz int[][] laberinto de tamaño n x n (ej: n = 5).

    • Coordenadas iniciales (0, 0) y finales (n-1, n-1).

  • Salida:

    • Lista de rutas válidas, donde cada ruta es una secuencia de coordenadas en formato (fila,columna).

Restricciones:

  • No se puede pasar los bordes del laberinto.

  • Evitar repetir celdas visitadas (marcar temporalmente celdas usadas).

  • Recursividad obligatoria: No usar enfoque iterativo (ej: while/for para exploración).

  • Estructura de datos: Usar List<List<String>> para almacenar rutas.

Casos de prueba:

              ┌     ┐
Laberinto 2x2 | 0 0 |, sin solución
              | 1 0 |
              └     ┘

Salida esperada: {}
              ┌         ┐
              | 0 0 0 0 |
Laberinto 4x4 | 1 0 1 0 |
              | 0 0 0 0 |
              | 0 1 1 0 |
              └         ┘

Salida esperada:
{
    {(0,0),(0,1),(0,2),(0,3),(1,3),(2,3),(3,3)},
    {(0,0),(0,1),(1,1),(2,1),(2,2),(2,3),(3,3)}
}
              ┌           ┐
              | 0 0 1 0 0 |
Laberinto 5x5 | 1 0 0 0 1 |
              | 0 0 1 0 0 |
              | 0 1 0 0 1 |
              | 1 0 0 0 0 |
              └           ┘

Salida esperada:
{
    {(0,0),(0,1),(1,1),(1,2),(1,3),(2,3),(3,3),(3,4),(4,4)}
}

Criterios de calificación:

El código será evaluado de la siguiente manera:

  • Descalificación inmediata si el código no compila o da errores en tiempo de ejecución.

  • Descalificación si el resultado generado no coincide con lo esperado para los casos de prueba proporcionados.

  • 10 puntos si el algoritmo utiliza recursividad correctamente para generar las rutas.

  • 10 puntos si optimiza evitando repeticiones.

2.2. Solución

A continuación se presenta una posible solución al reto, que incluye la implementación de las clases Laberinto, Coordenada y una clase principal para ejecutar el programa.

Estructura de directorio del proyecto:

src
└── main
    └── java
       └── com
            └── concurso
                └── basico
                    └── reto12
                        ├── Coordenada.java
                        ├── Laberinto.java
                        └── LaberintoMain.java
Diagram
Figura 1. Diagrama de Clases Nivel Básico - reto 1 nivel 2

La clase Coordenada representa una posición en el laberinto.

Listado 3. Nivel Básico - reto 1 - nivel 2: Coordenada.java
package com.concurso.basico.reto12;

public class Coordenada {
    private int fila;
    private int columna;

    public Coordenada(int fila, int columna) {
        this.fila = fila;
        this.columna = columna;
    }

    @Override
    public String toString() {
        return "(" + fila + "," + columna + ")";
    }
}

La clase Laberinto contiene la lógica para encontrar todas las rutas posibles desde la esquina superior izquierda hasta la esquina inferior derecha del laberinto.

Listado 4. Nivel Básico - reto 1 - nivel 2: Laberinto.java
package com.concurso.basico.reto12;

import java.util.ArrayList;
import java.util.List;

public class Laberinto {
    int[][] laberinto;
    boolean[][] visitado;

    public Laberinto(int[][] laberinto) {
        this.laberinto = laberinto;
        visitado = new boolean[laberinto.length][laberinto[0].length];
    }

    public List<List<Coordenada>> encontrarRutas() {
        List<List<Coordenada>> rutas = new ArrayList<>();
        List<Coordenada> rutaActual = new ArrayList<>();

        buscarRutas(0, 0, rutaActual, rutas);

        return rutas;
    }

    private void buscarRutas(int fila, int col,
                             List<Coordenada> rutaActual,
                             List<List<Coordenada>> rutas) {
        int n = laberinto.length;

        // Caso base: llegar a la salida
        if (fila == n - 1 && col == n - 1) {
            rutaActual.add(new Coordenada(fila, col));
            rutas.add(new ArrayList<>(rutaActual));
            rutaActual.removeLast(); //JDK 21
            return;
        }

        // Verificar límites y si es camino transitable
        if (fila < 0 || fila >= n || col < 0 || col >= n ||
                laberinto[fila][col] == 1 || visitado[fila][col]) {
            return;
        }

        // Marcar celda como visitada
        visitado[fila][col] = true;
        rutaActual.add(new Coordenada(fila, col));

        // Moverse a derecha y abajo (recursión)
        buscarRutas(fila, col + 1, rutaActual, rutas); // Derecha
        buscarRutas(fila + 1, col, rutaActual, rutas); // Abajo

        // Backtracking: desmarcar y retroceder
        visitado[fila][col] = false;
        rutaActual.removeLast();
    }
}

La clase LaberintoMain es la clase principal que ejecuta el programa y muestra las rutas encontradas.

Listado 5. Nivel Básico - reto 1 - nivel 2: LaberintoMain.java
package com.concurso.basico.reto12;

import java.util.List;

public class LaberintoMain {

    public static void main(String[] args) {
        int[][] laberinto1 = {
                {0, 0, 1},
                {1, 0, 0},
                {0, 1, 0}
        };

        int[][] laberinto2 = {
                {0,0,0,0},
                {1,0,1,0},
                {0,0,0,0},
                {0,1,1,0}
        };

        Laberinto laberintoMain = new Laberinto(laberinto2);

        List<List<Coordenada>> rutas = laberintoMain.encontrarRutas();

        System.out.println("Rutas encontradas: " + rutas);
    }
}

3. Adivina la palabra

El objetivo de este reto es desarrollar un programa en Java que simule el clásico juego del Ahorcado. El juego consiste en adivinar una palabra, semi oculta, letra por letra antes de que se agoten los intentos permitidos.

3.1. Reto 2 - Nivel básico

Desarrolla un programa en Java que simule el clásico juego del Ahorcado. El juego consiste en adivinar una palabra, semi oculta, letra por letra antes de que se agoten los intentos permitidos.

El programa debe proporcionarle al usuario una palabra (aleatoria de un grupo de palabras almacenadas en un arreglo). Con letras borradas (al menos la mitad de las letras borradas aleatoriamente) y el usuario debe ingresar letra por letra hasta adivinar la palabra.

Ejemplo: p _ l _ b _ _

Requisitos:

  • El programa debe permitir que el usuario siga intentando hasta adivinar la palabra o se le terminen los intentos (los intentos posibles deben ser el doble del número de letras borradas).

  • Asignar la/s letra/s, si es correcta, y desplegar con la letra adivinada en el lugar o lugares correspondientes o restar del número de intentos posibles.

    • Ejemplo: p _ l _ b r_

  • Al finalizar si adivina la palabra debe aparecer un mensaje de ¡GANO! o ¡PERDIO! Si se le agotaron los intentos posibles.

  • Permite al usuario jugar de nuevo sin salir del programa, eligiendo volver a JUGAR o terminar el juego si escoge la opción SALIR.

Buenas Prácticas de Programación:

  • Usa nombres descriptivos

  • Divide el código en Clases con métodos pequeños y específicos.

  • Agrega comentarios para explicar la lógica compleja o los pasos importantes.

  • Asegúrate de manejar entradas inválidas (números negativos o no enteros).

  • Evita cálculos redundantes y optimiza el uso de bucles y operaciones.

Criterios de Calificación:

El código será evaluado de la siguiente manera:

  • Descalificación inmediata si el código no compila o no ejecuta debido a errores sintácticos.

  • Descalificación si el resultado generado no coincide con el objetivo del juego.

  • 10 puntos si el programa cumple con toda la funcionalidad solicitada.

  • 10 puntos si el programa tiene una buena interacción con el usuario y sigue buenas prácticas de programación.

Nota: Solo las soluciones funcionales que pasen las pruebas básicas serán consideradas para la asignación de puntos por funcionalidad e interacción con el usuario.

Prohibición Estricta:

  • 🚫No se permite el uso de Internet durante el concurso.

  • 🚫No está permitido utilizar código generado por IA (ChatGPT, Copilot, etc.).

3.2. Solución

A continuación se presenta una posible solución al reto, que incluye la implementación de las clases necesarias para el juego de adivinar la palabra.

Estructura de directorio del proyecto:

src
└── main
    └── java
       └── com
            └── concurso
                └── basico
                    └── reto21
                        ├── AppAdivina.java
                        └── PalabraAdiv.java
Diagram
Figura 2. Diagrama de Clases Nivel Básico - reto 2

La clase PalabraAdiv es responsable de la lógica del juego, incluyendo la selección de una palabra aleatoria, el manejo de las letras adivinadas y la interacción con el usuario.

Listado 6. Nivel Básico - reto 2: PalabraAdiv.java
package com.concurso.basico.reto21;

import java.util.Random;
import java.util.Scanner;

public class PalabraAdiv {

    private String[] palabra = {
            "martillo",
            "murcielago",
            "mandarina",
            "acelerometro",
            "camiseta",
            "pinguino"
    };

    private StringBuilder adiv;
    private String pal;
    private int op[];

    public void palAdivina() {
        Random r = new Random();
        pal = palabra[r.nextInt(palabra.length)];
        adiv = new StringBuilder(pal);
        op = new int[pal.length() / 2 + 1];
        int num;
        for (int i = 0; i < op.length; i++) {
            num = r.nextInt(pal.length() - 1);
            if (i > 0) {
                if (num != op[i - 1]) {
                    op[i] = num;
                } else {
                    num = r.nextInt(pal.length() - 1);
                    op[i] = num;
                }
            } else {
                op[i] = num;
            }
        }

        for (int i = 0; i < op.length; i++) {
            adiv.replace(op[i], op[i] + 1, "-");
        }
        //return adiv.toString();
        System.out.println(adiv);
    }

    public void adivina() {
        Scanner sc = new Scanner(System.in);
        int cont = adiv.length() / 2 + 3;
        boolean estado = false;
        String let;
        do {
            cont--;
            System.out.println("Ingrese una letra: ");
            let = sc.next();
            Character c;
            for (int i = 0; i < op.length; i++) {
                if (pal.charAt(op[i]) == let.charAt(0)) {
                    c = let.charAt(0);
                    adiv.replace(op[i], op[i] + 1, c.toString());
                    System.out.println(adiv);
                    estado = true;
                    break;
                } else {
                    estado = false;
                }
            }
            if (!estado) {
                System.out.println("Fallaste intenta de nuevo, " +
                        "tienes : " + cont + " intentos");
            }

        } while (cont > 0 && !(pal.equals(adiv.toString())));

        if (pal.equals(adiv.toString())) {
            System.out.println("ganaste el juego");
        } else {
            System.out.println("Te quedaste sin intentos, " +
                    "vuelve a jugar ");
        }
    }
}

La clase AppAdivina es el punto de entrada del programa, donde se crea una instancia de PalabraAdiv y se inicia el juego.

Listado 7. Nivel Básico - reto 2: AppAdivina.java
package com.concurso.basico.reto21;

public class AppAdivina {
  public static void main(String[] args) {
    PalabraAdiv pal = new PalabraAdiv();

    pal.palAdivina();

    pal.adivina();
  }
}

4. Juego de Cartas Nivel 1

El objetivo de este reto es desarrollar un juego de cartas simplificado en Java, donde los jugadores roban cartas de una baraja siguiendo reglas especiales. El estudiante deberá modelar las clases necesarias (Carta, Baraja, Jugador) y garantizar que el juego siga la mecánica descrita a continuación.

4.1. Reto 3 - Nivel básico 1

Implementar un juego de cartas simplificado donde jugadores roban cartas de una Baraja, con reglas especiales. El estudiante deberá modelar las clases necesarias (Carta, Baraja, Jugador) y garantizar que el juego siga la mecánica descrita a continuación:

Reglas del Juego:

  • Carta: las cartas tienen un palo {Corazones, Diamantes, Tréboles, Picas}, un número que puede tener los siguiente valores {2-10, J, Q, K, A } y el puntaje numérico asignado: A (AS) = 1 puntos; K=13, Q=12, J = 11 puntos; 2-10 = Su valor nominal.

  • Baraja:

    • Se crea con las 52 cartas diferentes (4 palos * 13 valores: 2-10, J, Q, K, A).

    • Tiene un método para revolver las cartas de forma randómica intercambiar la posición de las cartas en la baraja.

  • Jugador:

    • Es identificado por un nombre

    • Tiene una mano de 10 cartas que se compone de las cartas que ha robado, inicialmente está vacía su mano.

    • Tiene un método tomarCarta(Carta[] baraja), donde debe sacar las n cartas de la baraja que recibe como parámetro y la inserta en su mano de cartas.

    • Tiene un método para mostrar la mano de cartas en la pantalla y calcula su puntuación.

  • Flujo del juego: Crear baraja → Barajar cartas → Crear 2 jugadores que toman Cartas por turnos hasta que la mano de cada jugador se complete →Mostrar y Puntuar las manos de los jugadores y decidir quién gano.

Debe utilizar arreglos para almacenamiento, no listas ni similares.

Criterios de Calificación:

El código será evaluado de la siguiente manera:

  • Descalificación inmediata si el código no compila o presenta errores de ejecución.

  • 20 puntos si el programa cumple con toda la funcionalidad solicitada y sigue buenas prácticas de programación.

Prohibición Estricta:

  • 🚫No se permite el uso de Internet durante el concurso.

  • 🚫No está permitido utilizar código generado por IA (ChatGPT, Copilot, etc.).

4.2. Solución

A continuación se presenta una posible solución al reto 3, nivel básico 1. El código está dividido en varias clases que representan las cartas, la baraja, los jugadores y la lógica del juego.

Estructura de directorio del proyecto:

src
└── main
    └── java
       └── com
            └── concurso
                └── basico
                    └── reto31
                        ├── App.java
                        ├── Baraja.java
                        ├── Cartas.java
                        ├── Jugador.java
                        ├── Jugadores.java
                        └── Palo.java
Diagram
Figura 3. Diagrama de Clases Nivel Básico - reto 3 nivel 1

La clase Cartas representa una carta con un palo y un valor.

Listado 8. Nivel Básico - reto 3 - nivel 1: Cartas.java
package com.concurso.basico.reto31;

public record Cartas(Palo palo, int valor) {

}

Los enumerados Jugadores y Palo definen los jugadores y los palos de las cartas, respectivamente.

Listado 9. Nivel Básico - reto 3 - nivel 1: Jugadores.java
package com.concurso.basico.reto31;

public enum Jugadores {
    Ana, juan, Carlos
}
Listado 10. Nivel Básico - reto 3 - nivel 1: Palo.java
package com.concurso.basico.reto31;

public enum Palo {
  PICA, TREBOL, CORAZONES, DIAMANTE
}

La clase Baraja contiene un arreglo de cartas, las baraja y las imprime.

Listado 11. Nivel Básico - reto 3 - nivel 1: Baraja.java
package com.concurso.basico.reto31;

import java.util.Random;

public class Baraja {
    public static final int TOTAL_CARTAS = 52;

    private Cartas[] cartas = new Cartas[TOTAL_CARTAS];
    public Cartas[] barajadas = new Cartas[TOTAL_CARTAS];
    private boolean[] marcada = new boolean[TOTAL_CARTAS];
    private Random r = new Random();

    public Baraja() {
        crearCartas();
    }

    public void crearCartas() {
        int count = 1;
        int pal = 0;
        for (int i = 0; i < cartas.length; i++) {
            if (count <= 13)
                cartas[i] = new Cartas(Palo.values()[pal], count++);
            else {
                count = 1;
                pal = pal + 1;
                cartas[i] = new Cartas(Palo.values()[pal], count++);
            }
        }
    }

    public void barajar() {
        int num = 0;
        boolean estado = false;
        for (int i = 0; i < cartas.length; i++) {
            do {
                num = r.nextInt(TOTAL_CARTAS);
                if (barajadas[num] == null) {
                    barajadas[num] = cartas[i];
                    estado = true;
                } else {
                    estado = false;
                }
            } while (!estado);
        }
    }

    public void imrpimir() {
        System.out.println("Las Cartas han sido barajadas");
        for (int i = 0; i < barajadas.length; i++) {
            System.out.print(barajadas[i].palo().name()
                    + barajadas[i].valor() + " ");
        }
        System.out.println();
    }
}

La clase Jugador representa a un jugador que puede tomar cartas de la baraja y mostrar su mano.

Listado 12. Nivel Básico - reto 3 - nivel 1: Jugador.java
package com.concurso.basico.reto31;

public class Jugador {
  private static int count;
  public int num;
  private Baraja baraja;
  private Jugadores jugador;
  private Cartas[] cartas;
  private int tot;

  public Jugador(Jugadores jugador, Baraja baraja) {
    this.jugador = jugador;
    this.baraja = baraja;
    this.cartas = new Cartas[10];
  }

  public void tomarCarta() {
    cartas[num++] = baraja.barajadas[count++];
  }

  public void imprimirMano() {
    for (int i = 0; i < 10; i++) {
      System.out.print(" " + cartas[i].palo()
          + cartas[i].valor() + " ");
    }
    System.out.println();
  }

  public Jugadores getJugador() {
    return jugador;
  }

  public int total() {
    for (int i = 0; i < 10; i++) {
      tot += cartas[i].valor();
    }
    return tot;
  }
}

La clase App es el punto de entrada del programa, donde se crean la baraja y los jugadores, se barajan las cartas y se muestran las manos de los jugadores.

Listado 13. Nivel Básico - reto 3 - nivel 1: App.java
package com.concurso.basico.reto31;

public class App {
    public static void main(String[] args) {
        Baraja b = new Baraja();

        b.barajar();
        b.imrpimir();

        Jugador jugadorUno = new Jugador(Jugadores.Ana, b);
        Jugador jugadorDos = new Jugador(Jugadores.Carlos, b);

        for (int i = 0; i < 10; i++) {
            jugadorUno.tomarCarta();
            jugadorDos.tomarCarta();
        }

        System.out.println(" cartas de " + jugadorUno.getJugador() +
                " con un puntaje final de: " + jugadorUno.total());
        jugadorUno.imprimirMano();

        System.out.println(" cartas de " + jugadorDos.getJugador() +
                " con un puntaje final de: " + jugadorDos.total());
        jugadorDos.imprimirMano();

        System.out.println(jugadorUno.total() > jugadorDos.total() ?
                "Ha ganado: " + jugadorUno.getJugador() :
                "Ha ganado: " + jugadorDos.getJugador());
    }
}

5. Juego de Cartas Nivel 2

El objetivo de este reto es implementar un juego de cartas simplificado donde los jugadores roban cartas de una baraja, siguiendo reglas especiales. El estudiante deberá modelar las clases necesarias (Carta, Baraja, Jugador) y garantizar que el juego siga la mecánica descrita a continuación.

5.1. Reto 3 - Nivel básico 2

Implementar un juego de cartas simplificado donde jugadores roban cartas de una Baraja, con reglas especiales. El estudiante deberá modelar las clases necesarias (Carta, Baraja, Jugador) y garantizar que el juego siga la mecánica descrita a continuación:

Reglas del Juego:

  • Baraja inicial: 52 cartas inmutables (4 palos: {Corazones, Diamantes, Tréboles, Picas} y 13 valores: 2-10, J, Q, K, A). Asignar valores numéricos a las cartas: A (AS) = 20 puntos; K, Q, J= 10 puntos; 2-10 = Su valor nominal. La baraja se comporta como una pila.

  • Jugador: tiene un nombre y una mano de cartas que se compone de las cartas que ha robado. Gana el jugador con más puntos en su mano.

  • Acciones:

    • Revolver la baraja: Las cartas se barajan aleatoriamente antes de empezar.

    • Robar una carta: El jugador saca la carta superior de la baraja que recibe como parámetro y la inserta en su mano de cartas.

    • Regla del AS (1): Si un jugador roba un AS, recibe dos cartas adicionales que roba de la misma baraja automáticamente (en el mismo movimiento).

    • Regla del Rey(K): Si un jugador roba un Rey (K), debe devolver una carta(escogida al azar de su mano) que se coloca en la baraja.

    • Mostrar Mano: el jugador muestra su mano de cartas y calcula su puntuación.

  • Flujo del juego: Crear baraja → Barajar cartas → Crear 2 jugadores que roban por turnos hasta que la baraja se vacíe →Mostrar y Puntuar las manos de los jugadores y decidir quién gano.

Criterios de Calificación:

El código será evaluado de la siguiente manera:

  • Descalificación inmediata si el código no compila o presenta errores de ejecución.

  • Descalificación si el resultado generado no coincide con el flujo del juego.

  • 20 puntos si el programa cumple con toda la funcionalidad solicitada y sigue buenas prácticas de programación.

Prohibición Estricta:

  • 🚫No se permite el uso de Internet durante el concurso.

  • 🚫No está permitido utilizar código generado por IA (ChatGPT, Copilot, etc.).

Regla Oficial:

  • Estudiantes de 1° y 2° semestre de programación deben implementar su solución usando Programación Orientada a Objetos (POO) y arreglos, opcional la Programación Funcional (PF).

  • Estudiantes 3° y 4° semestre de programación deben implementar su solución usando Inmutabilidad y Programación Funcional (PF) como streams (map, filter, reduce), expresiones lambda y las estructuras de datos del Api de Java.

5.2. Solución

A continuación se presenta una posible solución al reto, que incluye las clases Carta, Baraja, Jugador y un Test para ejecutar el juego. Esta implementación sigue las reglas descritas y utiliza buenas prácticas de programación.

Estructura de directorio del proyecto:

src
└── main
    └── java
       └── com
            └── concurso
                └── basico
                    └── reto32
                        ├── Carta.java
                        ├── Baraja.java
                        ├── Jugador.java
                        └── Test.java
Diagram
Figura 4. Diagrama de Clases Nivel Básico - reto 3 nivel 2

La clase Baraja maneja una colección de cartas y permite operaciones como barajar, sacar y colocar cartas.

Listado 14. Nivel Básico - reto 3 - nivel 2: Baraja.java
package com.concurso.basico.reto32;

import java.util.Collections;
import java.util.Stack;

public class Baraja {
    private final Stack<Carta> cartas;

    public Baraja() {
        String[] palos = {
                "Corazones",
                "Diamantes",
                "Tréboles",
                "Picas"
        };

        String[] valores = {"2", "3", "4", "5", "6", "7", "8", "9",
                "10", "J", "Q", "K", "A"};

        int[] puntajes = {2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, 20};

        this.cartas = new Stack<>();
        for (String palo : palos) {
            int i = 0;
            for (String valor : valores) {
                cartas.push(new Carta(palo, valor, puntajes[i++]));
            }
        }
    }

    public void revolver() {
        Collections.shuffle(cartas);
    }

    public Carta sacarCarta() {
        return cartas.pop();
    }

    public void colocarCarta(Carta carta) {
        cartas.push(carta);
    }

    public boolean estaVacio() {
        return cartas.isEmpty();
    }
}

La clase Carta representa una carta del juego, con atributos para el palo, valor y puntaje.

Listado 15. Nivel Básico - reto 3 - nivel 2: Carta.java
package com.concurso.basico.reto32;

public record Carta(String palo, String valor, int puntaje) {
    @Override
    public String toString() {
        return valor + " de " + palo;
    }
}

La clase Jugador representa a un jugador del juego, que puede robar cartas de la baraja y calcular su puntuación.

Listado 16. Nivel Básico - reto 3 - nivel 2: Jugador.java
package com.concurso.basico.reto32;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.stream.IntStream;

public class Jugador {
    private final String nombre;
    private final List<Carta> mano;

    public Jugador(String nombre) {
        this.nombre = nombre;
        this.mano = new ArrayList<>();
    }

    public String getNombre() {
        return nombre;
    }

    public void robarCarta(Baraja baraja) {
        if (baraja.estaVacio()) return;

        Carta carta = baraja.sacarCarta();
        mano.add(carta);

        if ("A".equals(carta.valor())) {
            IntStream.range(0, 2)
                    .forEach(i -> {
                        if (!baraja.estaVacio())
                            mano.add(baraja.sacarCarta());
                    });
        } else if ("K".equals(carta.valor())) {
            Random r = new Random();
            if (!mano.isEmpty()) {
                Carta laCarta = mano.remove(r.nextInt(mano.size()));
                baraja.colocarCarta(laCarta);
            }
        }
    }

    public int puntuar() {
        return this.mano.stream()
                .map(Carta::puntaje)
                .reduce(0, Integer::sum);
    }

    public List<Carta> mostrarMano() {
        return mano;
    }
}

Finalmente, la clase Test ejecuta el flujo del juego.

Listado 17. Nivel Básico - reto 3 - nivel 2: MainReto32.java
package com.concurso.basico.reto32;

public class MainReto32 {
    public static void main(String[] args) {
        // Crear baraja → Barajar cartas → Crear
        //   2 jugadores que roban por turnos
        // hasta que la baraja se vacíe →Mostrar y
        // Puntuar las manos de los jugadores y decidir quién gano.

        Baraja myBaraja = new Baraja();
        myBaraja.revolver();

        Jugador j1 = new Jugador("Angel");
        Jugador j2 = new Jugador("Ximena");

        boolean turno = true;

        while (!myBaraja.estaVacio()) {
            if (turno) j1.robarCarta(myBaraja);
            else j2.robarCarta(myBaraja);

            turno = !turno;
        }

        if (j1.puntuar() > j2.puntuar())
            System.out.println("GANO !! " + j1.getNombre());
        else if (j1.puntuar() < j2.puntuar())
            System.out.println("GANO !! " + j2.getNombre());
        else
            System.out.println("EMPATE !! ");
    }
}

Parte II: Nivel Medio

El nivel medio del concurso de programación está orientado a la creación de aplicaciones más complejas, que requieren un mayor conocimiento de las tecnologías y herramientas utilizadas.

Los temas comprendidos en este nivel incluyen:

  • Programación orientada a objetos

  • Arquitectura de software

  • Patrones de diseño de software

6. Sistema de clasificación automática

El objetivo de este reto es desarrollar un programa en Java que gestione la clasificación automática de empleados en diferentes departamentos, basándose en etiquetas inmutables. El programa debe identificar diferentes tipos de etiquetas utilizando expresiones regulares y asignar a los empleados a los departamentos correspondientes.

6.1. Reto 1

Desarrolle un programa que gestione de forma automática la clasificación de empleados (nombre, etiqueta) inmutables, a los departamentos (Testing, Admin, Programming). Implemente un analizador que identifique diferentes tipos de etiquetas (String) de los empleados, utilizando expresiones regulares. Las etiquetas pueden representar usuarios, administradores o desarrolladores.

Requisitos y funcionalidades:

  1. Detectar:

    • Usuarios: comienzan con @ y terminan con una letra u.

    • Administradores: comienzan con # y terminan con un digito numérico.

    • Desarrolladores: comienzan con %d y finalizan en extensiones como .info, .des, .tec y .sop

  2. Retornar los usuarios por tipo en listas separadas.

  3. Agregar los empleados al departamento correspondiente.

  4. Utilizar expresiones regulares eficientes.

Funcionamiento:

  • Crear una lista de usuarios con distintos tipos de etiquetas.

  • Crear cada departamento que contenga id, nombre y sus empleados

  • Listar empleados por departamento

Criterios de Calificación:

El código será evaluado de la siguiente manera:

  1. Descalificación inmediata si el código no compila o no ejecuta debido a errores de compilación.

  2. Descalificación si el resultado generado no coincide con el objetivo del reto.

  3. 10 puntos si el programa cumple con toda la funcionalidad solicitada.

  4. 10 puntos si el programa tiene una buena interacción con el usuario y sigue buenas prácticas de programación.

Solo las soluciones funcionales que pasen las pruebas básicas serán consideradas para la asignación de puntos por funcionalidad e interacción con el usuario.

Prohibición Estricta:

  • 🚫No se permite el uso de Internet durante el concurso.

  • 🚫No está permitido utilizar código generado por IA (ChatGPT, Copilot, etc.).

6.2. Solución

A continuación se presenta una posible solución al reto 3, nivel medio. El código está dividido en varias clases que representan a los empleados, los departamentos y el clasificador de etiquetas.

Estructura de directorio del proyecto:

src
└── main
    └── java
       └── com
            └── concurso
                └── medio
                    └── reto1
                        ├── AppClasificador.java
                        ├── ClasificadorEtiquetas.java
                        ├── Departamento.java
                        ├── Administrador.java
                        ├── Desarrollador.java
                        ├── Empleado.java
                        └── Usuario.java
Diagram
Figura 5. Diagrama de Clases Nivel Medio - reto 1

La clase Empleado es una clase abstracta que define las propiedades comunes de los empleados, como el nombre y la etiqueta. Las clases Usuario, Desarrollador y Administrador heredan de Empleado y proporcionan su propia implementación del método getTipo().

Listado 18. Nivel Medio - reto 1: Empleado.java
package com.concurso.medio.reto1;

public abstract class Empleado {
    public static final String USUARIO = "Usuario";
    public static final String ADMINISTRADOR = "Administrador";
    public static final String DESARROLLADOR = "Desarrollador";

    private final String nombre;
    private final String etiqueta;

    public Empleado(String nombre, String etiqueta) {
        this.nombre = nombre;
        this.etiqueta = etiqueta;
    }

    public String getNombre() {
        return nombre;
    }

    public String getEtiqueta() {
        return etiqueta;
    }

    public abstract String getTipo();
}

La clase Usuario, Desarrollador y Administrador extienden la clase Empleado y proporcionan su propia implementación del método getTipo().

Listado 19. Nivel Medio - reto 1: Usuario.java
package com.concurso.medio.reto1;

public class Usuario extends Empleado {
    public Usuario(String nombre, String etiqueta) {
        super(nombre, etiqueta);
    }

    @Override
    public String getTipo() {
        return "Usuario";
    }
}
Listado 20. Nivel Medio - reto 1: Desarrollador.java
package com.concurso.medio.reto1;

public class Desarrollador extends Empleado {
    public Desarrollador(String nombre, String etiqueta) {
        super(nombre, etiqueta);
    }

    @Override
    public String getTipo() {
        return "Desarrollador";
    }
}
Listado 21. Nivel Medio - reto 1: Administrador.java
package com.concurso.medio.reto1;

public class Administrador extends Empleado {
    public Administrador(String nombre, String etiqueta) {
        super(nombre, etiqueta);
    }

    @Override
    public String getTipo() {
        return "Administrador";
    }
}

La clase Departamento representa un departamento que contiene una lista de empleados. Tiene métodos para agregar empleados y listar los empleados del departamento.

Listado 22. Nivel Medio - reto 1: Departamento.java
package com.concurso.medio.reto1;

import java.util.ArrayList;
import java.util.List;

public class Departamento {
    private final int id;
    private final String nombre;
    private final List<Empleado> empleados = new ArrayList<>();

    public Departamento(int id, String nombre) {
        this.id = id;
        this.nombre = nombre;
    }

    public void agregarEmpleado(Empleado e) {
        empleados.add(e);
    }

    public List<Empleado> getEmpleados() {
        return empleados;
    }

    public String getNombre() {
        return nombre;
    }

    public void listarEmpleados() {
        System.out.println("Departamento: " + nombre);
        for (Empleado e : empleados) {
            System.out.println("- " + e.getNombre()
                    + " [" + e.getEtiqueta() + "]");
        }
    }
}

La clase ClasificadorEtiquetas utiliza expresiones regulares para clasificar las etiquetas de los empleados. Dependiendo del patrón de la etiqueta, crea una instancia del tipo correspondiente de empleado.

Listado 23. Nivel Medio - reto 1: ClasificadorEtiquetas.java
package com.concurso.medio.reto1;

import java.util.Optional;
import java.util.regex.Pattern;

public class ClasificadorEtiquetas {
    private static final Pattern usuarioPattern =
            Pattern.compile("^@.*u$");

    private static final Pattern adminPattern =
            Pattern.compile("^#.*\\d$");

    private static final Pattern devPattern =
            Pattern.compile("^%d.*\\.(info|des|tec|sop)$");

    public static Optional<Empleado> clasificar(String nombre,
                                                String etiqueta) {
        Empleado emp = null;
        if (usuarioPattern.matcher(etiqueta).matches()) {
            emp = new Usuario(nombre, etiqueta);
        } else if (adminPattern.matcher(etiqueta).matches()) {
            emp =  new Administrador(nombre, etiqueta);
        } else if (devPattern.matcher(etiqueta).matches()) {
            emp =  new Desarrollador(nombre, etiqueta);
        }
        // o lanzar excepción si se prefiere
        return Optional.ofNullable(emp);
    }
}

La clase AppClasificador es el punto de entrada del programa. Crea una lista de empleados con diferentes etiquetas, clasifica cada empleado utilizando la clase ClasificadorEtiquetas y los agrega a los departamentos correspondientes.

Listado 24. Nivel Medio - reto 1: AppClasificador.java
package com.concurso.medio.reto1;

import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;

public class AppClasificador {

    public static void main(String[] args) {
        List<String[]> datos = List.of(
                new String[]{"Ana", "@clientu"},
                new String[]{"Luis", "#admin1"},
                new String[]{"Carlos", "%dcode.des"},
                new String[]{"Diana", "@betauseru"},
                new String[]{"Pedro", "#super5"},
                new String[]{"Laura", "%dapp.tec"}
        );

        Departamento testing = new Departamento(1, "Testing");
        Departamento admin = new Departamento(2, "Admin");
        Departamento programming = new Departamento(3, "Programming");

// alternativa con streams
//   datos.stream()
//           .map(row -> ClasificadorEtiquetas.clasificar(row[0], row[1]))
//           .filter(Optional::isPresent)
//           .flatMap(Optional::stream)
//           .forEach(emp -> {
//               var depto = switch (emp.getTipo()) {
//                   case Empleado.USUARIO -> testing;
//                   case Empleado.ADMINISTRADOR -> admin;
//                   case Empleado.DESARROLLADOR -> programming;
//                   default -> null;
//               };
//               if (depto != null)
//                   depto.agregarEmpleado(emp);
//           });

        for (String[] d : datos) {
            ClasificadorEtiquetas.clasificar(d[0], d[1])
                    .ifPresent(emp -> {
                var depto = switch (emp.getTipo()) {
                    case Empleado.USUARIO -> testing;
                    case Empleado.ADMINISTRADOR -> admin;
                    case Empleado.DESARROLLADOR -> programming;
                    default -> null;
                };
                if (depto != null)
                    depto.agregarEmpleado(emp);
            });
        }

        // Mostrar resultados
        testing.listarEmpleados();
        admin.listarEmpleados();
        programming.listarEmpleados();
    }
}

7. Sistema de sesiones

El objetivo de este reto es implementar un sistema de gestión de sesiones de usuario que garantice que solo exista una única instancia de sesión activa. Además, se debe implementar un mecanismo de control de acceso mediante un proxy que verifique si el usuario está autenticado antes de permitirle acceder a recursos protegidos.

7.1. Reto 2

Diseña un sistema de gestión de sesiones en el que solo pueda existir una única instancia de sesión de usuario. Además, implementa un mecanismo de control de acceso mediante un proxy, que verifique si el usuario está autenticado antes de permitirle acceder a recursos protegidos.

Requisitos:

  • El sistema debe asegurar que solo exista una instancia de sesión activa (aplicando el patrón adecuado).

  • La sesión debe contener un objeto usuario que incluya:

    • Nombre del usuario.

    • Estado de autenticación (autenticado o no).

    • Los usuarios son inmutables una vez creada la sesión. (debe ser un objeto anidado a la sesión)

  • El acceso a los recursos protegidos no debe realizarse directamente. Debe verificar si el usuario está autenticado antes de delegar el acceso al recurso real.

  • No es necesario implementar la funcionalidad completa de los recursos; basta con simular el acceso o mostrar mensajes representativos.

  • Deben aplicarse dos patrones de diseño que se ajusten a los requisitos anteriores

Funcionamiento:

  • Crear una sesión única con un usuario específico.

  • Intentar acceder a un recurso sin llamar directamente al objeto real.

Criterios de Calificación:

El código será evaluado de la siguiente manera:

  1. Descalificación inmediata si el código no compila o no ejecuta debido a errores de compilación.

  2. Descalificación si el resultado generado no coincide con el objetivo del reto.

  3. 10 puntos si el programa cumple con toda la funcionalidad solicitada.

Solo las soluciones funcionales que pasen las pruebas básicas serán consideradas para la asignación de puntos por funcionalidad e interacción con el usuario.

Prohibición Estricta:

  • 🚫No se permite el uso de Internet durante el concurso.

  • 🚫No está permitido utilizar código generado por IA (ChatGPT, Copilot, etc.).

7.2. Solución

A continuación se presenta una posible solución al reto 2, nivel medio. El código está dividido en varias clases que representan la sesión, el usuario y los recursos protegidos.

Estructura de directorio del proyecto:

src
└── main
    └── java
       └── com
            └── concurso
                └── medio
                    └── reto2
                        ├── Main.java
                        ├── ProxyRecurso.java
                        ├── RecursoReal.java
                        ├── Recursos.java
                        └── Sesion.java
Diagram
Figura 6. Diagrama de Clases Nivel Medio - reto 2

La clase Recursos define la interfaz que los recursos protegidos deben implementar. La clase RecursoReal es la implementación concreta de un recurso protegido, mientras que ProxyRecurso actúa como un proxy que verifica si el usuario está autenticado antes de permitir el acceso al recurso real.

Listado 25. Nivel Medio - reto 2: Recursos.java
package com.concurso.medio.reto2;

public interface Recursos {
    void acceder(Sesion s);
}
Listado 26. Nivel Medio - reto 2: RecursoReal.java
package com.concurso.medio.reto2;

public class RecursoReal implements Recursos {
    public void acceder(Sesion s) {
        System.out.println("Accediendo al recurso protegido.");
    }
}
Listado 27. Nivel Medio - reto 2: ProxyRecurso.java
package com.concurso.medio.reto2;

public class ProxyRecurso implements Recursos {
    // private boolean autenticado;
    private RecursoReal recursoReal = new RecursoReal();

    public ProxyRecurso() {

    }

    public void acceder(Sesion s) {
        if (s.getUsuario().autentica()) recursoReal.acceder(s);
        else System.out.println("Acceso denegado.");
    }
}

La clase Sesion es responsable de gestionar la sesión del usuario. Implementa el patrón Singleton para garantizar que solo exista una instancia de sesión activa. La clase Usuario es un objeto inmutable que contiene el nombre del usuario y su estado de autenticación.

Listado 28. Nivel Medio - reto 2: Sesion.java
package com.concurso.medio.reto2;

public class Sesion {
    private static Sesion instancia;
    private Usuario usuario;

    private Sesion(Usuario usuario) {
        this.usuario = usuario;
    }

    public static Sesion crearSesion(Usuario usuario) {
        if (instancia == null) {
            instancia = new Sesion(usuario);
            System.out.println(" Se creo instancia");
        } else System.out.println(" solo existe una instancia " +
                "de sesión para los usuarios");
        return instancia;
    }

    public Usuario getUsuario() {
        return usuario;
    }

    record Usuario(String name, boolean autentica) {

    }
}

La clase Main es el punto de entrada del programa, donde se crea una sesión y se intenta acceder a un recurso protegido a través del proxy.

Listado 29. Nivel Medio - reto 2: Main.java
package com.concurso.medio.reto2;

import com.concurso.medio.reto2.Sesion.Usuario;

public class Main {
    public static void main(String[] args) {
        Sesion sesion = Sesion.crearSesion(
                new Usuario("Mary", true)
        );

        Sesion sesion2 = Sesion.crearSesion(
                new Usuario("Juan", false)
        );

        ProxyRecurso r = new ProxyRecurso();
        r.acceder(sesion);
    }
}

8. Reportes dinámicos

El objetivo de este reto es implementar un sistema de gestión de sesiones de usuario que garantice que solo exista una única instancia de sesión activa. Además, se debe implementar un mecanismo de control de acceso mediante un proxy que verifique si el usuario está autenticado antes de permitirle acceder a recursos protegidos.

8.1. Reto 3

Diseñe y desarrolle una aplicación en Java que permita generar reportes dinámicos y personalizables a partir de los datos contenidos en una tabla de base de datos (se crea la tabla los campos y se agrega la información). La aplicación debe aplicar patrones de diseño como Builder para:

  • Separar la lógica de construcción de contenido del formato general del reporte.

  • Permitir la personalización del reporte (los campos mostrados).

  • Generar distintos formatos de reporte a partir de la misma fuente de datos.

Requisitos:

  • Crear la base de datos con una sola tabla que contenga 5 campos.

  • Solo se debe implementar los métodos necesarios del CRUD.

  • No se requiere el ingreso de datos en la tabla de la base, desde la aplicación.

  • Permitir seleccionar los campos a incluir en el reporte (por ejemplo: nombre, edad, correo, etc.), se puede implementar algún patrón si es necesario.

  • Implementar el patrón Builder para construir el contenido del reporte

Funcionamiento:

  • Crear dos reportes diferentes que agreguen diferentes atributos de la tabla

  • Mostrar los reportes en consola

Criterios de Calificación:

El código será evaluado de la siguiente manera:

  1. Descalificación inmediata si el código no compila o no ejecuta debido a errores de compilación

  2. Descalificación si el resultado generado no coincide con el objetivo del reto.

  3. 10 puntos si el programa cumple con toda la funcionalidad solicitada.

  4. 10 puntos si el programa tiene una buena interacción con el usuario y sigue buenas prácticas de programación.

Solo las soluciones funcionales que pasen las pruebas básicas serán consideradas para la asignación de puntos por funcionalidad e interacción con el usuario.

Prohibición Estricta:

  • 🚫No se permite el uso de Internet durante el concurso.

  • 🚫No está permitido utilizar código generado por IA (ChatGPT, Copilot, etc.).

8.2. Solución

Estructura de directorio del proyecto:

src
└── main
    └── java
       └── com
            └── concurso
                └── medio
                    └── reto3
                        ├── builder
                        |   ├── ReporteBuilder.java
                        |   ├── ReporteConcretoBuilder.java
                        |   └── ReporteDirector.java
                        ├── db
                        |   ├── ConexionBD.java
                        |   ├── CreacionBase.java
                        |   └── PersonaDAO.java
                        ├── model
                        |   └── Persona.java
                        └── ReportesApp.java

Para la implementación de este reto, es necesario incorporar la dependencia:

implementation("org.xerial:sqlite-jdbc:3.46.1.3")
implementation("commons-beanutils:commons-beanutils:1.11.0")

A continuación se presenta una posible solución al reto 3, nivel medio. El código está dividido en varias clases que representan la conexión a la base de datos, el modelo de datos Persona, el DAO para acceder a los datos, la clase para crear la base de datos y los reportes utilizando el patrón Builder.

Diagram
Figura 7. Diagrama de Clases Nivel Medio - reto 3

La clase ConexionBD se encarga de establecer la conexión con la base de datos SQLite.

Listado 30. Nivel Medio - reto 3: ConexionBD.java
package com.concurso.medio.reto3.db;

import java.sql.Connection;
import java.sql.DriverManager;

public class ConexionBD {
    public static final String URL = "jdbc:sqlite:reporte.db";

    public static Connection conectar() {
        try {
            return DriverManager.getConnection(URL);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

La clase Persona representa la entidad que se almacenará en la base de datos. Utiliza Lombok para generar automáticamente los métodos getters, setters, toString, etc., lo que simplifica el código y mejora la legibilidad.

Listado 31. Nivel Medio - reto 3: Persona.java
package com.concurso.medio.reto3.model;

import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class Persona {
    private int id;
    private String nombre;
    private int edad;
    private String correo;
    private String direccion;
    private String telefono;
}

La clase PersonaDAO es responsable de interactuar con la base de datos para obtener los datos de las personas. Utiliza JDBC para ejecutar consultas SQL y mapear los resultados a objetos Persona.

Listado 32. Nivel Medio - reto 3: PersonaDAO.java
package com.concurso.medio.reto3.db;

import com.concurso.medio.reto3.model.Persona;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

public class PersonaDAO {
    public static List<Persona> obtenerPersonas() {
        List<Persona> personas = new ArrayList<>();
        String sql = "SELECT * FROM personas";

        try (Connection conn = ConexionBD.conectar();
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery(sql)) {

            while (rs.next()) {
                personas.add(Persona.builder()
                        .id(rs.getInt("id"))
                        .nombre(rs.getString("nombre"))
                        .edad(rs.getInt("edad"))
                        .correo(rs.getString("correo"))
                        .direccion(rs.getString("direccion"))
                        .telefono(rs.getString("telefono"))
                        .build());
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return personas;
    }
}

La clase CreacionBase es responsable de crear la base de datos, la tabla PERSONAS y los datos de ejemplo. Utiliza JDBC para ejecutar las sentencias SQL necesarias para crear la tabla y poblarla con datos iniciales si está vacía.

Listado 33. Nivel Medio - reto 3: CreacionBase.java
package com.concurso.medio.reto3.db;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class CreacionBase {
    private Connection conn;

    public void connect() throws SQLException {
        conn = DriverManager.getConnection(ConexionBD.URL);
    }

    public void close() throws SQLException {
        if (conn != null) conn.close();
    }

    public void createTable() throws SQLException {
        String sql = """
                CREATE TABLE IF NOT EXISTS Personas (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    nombre TEXT NOT NULL,
                    edad INTEGER,
                    correo TEXT,
                    direccion TEXT,
                    telefono TEXT
                );
                """;

        try (Statement stmt = conn.createStatement()) {
            stmt.execute(sql);
        }
    }

    // Insertamos datos para probar (solo si no hay)
    public void insertSampleData() throws SQLException {
        String checkSql = "SELECT COUNT(*) FROM Personas";
        try (Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery(checkSql)) {
            if (rs.next()) {
                int count = rs.getInt(1);
                if (count > 0) return; // ya hay datos
            }
        }

        String insertSql = """
            INSERT INTO Personas 
            (nombre, edad, correo, direccion, telefono) 
            VALUES
            ('Ana', 28, 'ana@mail.com', 'Cumbaya','2456789'),
            ('Luis', 34, 'luis@mail.com', 'Conocto', '0987654321'),
            ('Marta', 40, 'marta@mail.com', 'Quito', '045666777');
            """;

        try (Statement stmt = conn.createStatement()) {
            stmt.executeUpdate(insertSql);
        }
    }
}

La clase ReporteBuilder define la interfaz para construir reportes. Permite establecer los datos y los campos que se incluirán en el reporte, y proporciona un método para generar el reporte en formato de cadena de texto (String).

Listado 34. Nivel Medio - reto 3: ReporteBuilder.java
package com.concurso.medio.reto3.builder;

import java.util.List;

public interface ReporteBuilder<T> {
    ReporteBuilder<T> setDatos(List<T> personas);
    ReporteBuilder<T> setCampos(List<String> campos);
    String buildReporte();
}

La clase ReporteConcretoBuilder implementa la interfaz ReporteBuilder y se encarga de construir el reporte dinámico. Utiliza reflexión para obtener los valores de los campos especificados en los objetos de tipo T. El reporte se construye en formato de texto, con un encabezado que muestra los nombres de los campos y un cuerpo que muestra los valores correspondientes.

Listado 35. Nivel Medio - reto 3: ReporteConcretoBuilder.java
package com.concurso.medio.reto3.builder;

import org.apache.commons.beanutils.PropertyUtils;

import java.util.List;

public class ReporteConcretoBuilder<T> implements ReporteBuilder<T> {
    private List<T> datos;
    private List<String> campos;

    private Object getValue(Object obj, String fieldName) {
        try {
            if (PropertyUtils.isReadable(obj, fieldName)) {
                return PropertyUtils.getProperty(obj, fieldName);
            } else {
                return null;
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public ReporteBuilder<T> setDatos(List<T> datos) {
        this.datos = datos;
        return this;
    }

    @Override
    public ReporteBuilder<T> setCampos(List<String> campos) {
        this.campos = campos;
        return this;
    }

    private void buildHeader(StringBuilder report) {
        for (String f : campos) {
            report.append(String.format("%-15s", f.toUpperCase()));
        }
        report.append("\n");
        for (int i = 0; i < campos.size() * 15; i++) {
            report.append("-");
        }
        report.append("\n");
    }

    @Override
    public String buildReporte() {
        StringBuilder sb = new StringBuilder();
        sb.append("=== Reporte Dinamico ===\n");

        if (datos.isEmpty() || campos.isEmpty()) {
            return sb.toString();
        }

        buildHeader(sb);

        for (T it : datos) {
            for (String campo : campos) {
                Object val = getValue(it, campo);

                sb.append(
                        String.format("%-15s", val != null
                                ? val
                                : "?"
                        )
                );
            }
            sb.append("\n");
        }

        return sb.toString();
    }
}

La clase ReporteDirector es responsable de construir el reporte utilizando un ReporteBuilder. Se encarga de coordinar el proceso de construcción del reporte, separando la lógica de construcción del formato general del reporte. Permite personalizar los campos que se incluirán en el reporte y genera el reporte final en formato de texto.

Listado 36. Nivel Medio - reto 3: ReporteDirector.java
package com.concurso.medio.reto3.builder;

import java.util.List;

public class ReporteDirector<T> {
    private final ReporteBuilder<T> builder;

    public ReporteDirector(ReporteBuilder<T> builder) {
        this.builder = builder;
    }

    public String construirReporte(List<T> datos,
                                   List<String> campos) {
        return builder.setDatos(datos)
                .setCampos(campos)
                .buildReporte();
    }
}

La clase ReportesApp es el punto de entrada de la aplicación. Se encarga de crear la base de datos, obtener los datos de las personas y generar dos reportes diferentes utilizando el patrón Builder. Los reportes se muestran en la consola.

Listado 37. Nivel Medio - reto 3: ReportesApp.java
package com.concurso.medio.reto3;

import com.concurso.medio.reto3.builder.ReporteConcretoBuilder;
import com.concurso.medio.reto3.builder.ReporteDirector;
import com.concurso.medio.reto3.db.PersonaDAO;
import com.concurso.medio.reto3.model.Persona;

import java.util.Arrays;
import java.util.List;

public class ReportesApp {

    public static void main(String[] args) throws Exception {
        // se ejecuta una sola vez para crear la base,
        //   la tabla e insertar los datos

        //CreacionBase db = new CreacionBase();
        //db.connect();
        //db.createTable();
        //db.insertSampleData();

        List<Persona> personas = PersonaDAO.obtenerPersonas();

        // Reporte 1: Solo nombre y correo
        var builder1 = new ReporteConcretoBuilder<Persona>();
        var director1 = new ReporteDirector<Persona>(builder1);
        String reporte1 = director1.construirReporte(personas,
                Arrays.asList("nombre", "correo")
        );
        System.out.println(reporte1);

        // Reporte 2: nombre, edad, dirección, teléfono
        var builder2 = new ReporteConcretoBuilder<Persona>();
        var director2 = new ReporteDirector<Persona>(builder2);
        String reporte2 = director2.construirReporte(personas,
                Arrays.asList(
                        "nombre",
                        "edad",
                        "direccion",
                        "telefono"
                )
        );
        System.out.println(reporte2);
    }
}

Parte III: Nivel Avanzado

El nivel avanzado del concurso de programación está orientado a la creación de aplicaciones más complejas, que requieren un mayor conocimiento de las tecnologías y herramientas utilizadas.

En este nivel, los participantes deben demostrar su capacidad para resolver problemas más desafiantes y desarrollar soluciones eficientes y escalables.

Los temas comprendidos en este nivel incluyen:

  • Programación funcional

  • Componentes de negocio y persistencia

  • Programación concurrente

  • Programación distribuida

9. Ordenamiento Quick Sort

El objetivo de este reto es implementar el algoritmo de ordenamiento QuickSort utilizando una lista enlazada genérica. El algoritmo QuickSort es un método eficiente para ordenar listas y se basa en la técnica de divide y vencerás.

9.1. Reto 1

El algoritmo QuickSort divide al conjunto de datos en dos subconjuntos (aproximadamente del mismo tamaño), a continuación ordena cada conjunto por separado y luego los fusiona para obtener el resultado final.

Algoritmo:

  • Se selecciona un pivot (el primer elemento de la lista)

  • Se generan dos sub-listas: la primera contiene los elementos menores al pivot, la segunda contiene los elementos mayores al pivot.

  • Se ordenan las dos sub-listas (izquierda y derecha) de manera recursiva mediante el mismo algoritmo (QuickSort). La recursión termina si la lista está vacía.

  • Se ubica al elemento pivot de tal forma que los elementos a la izquierda sean menores y los elementos de la derecha sean mayores

Por ejemplo, considerar la lista [4,10,1,11,9,3,8]

1ra iteración

Se selecciona el pivot: 4
Se generan las dos sub-listas:
menores a 4: [1,3]
mayores a 4: [10,11,9,8]
Se ordenan las dos sub-listas
menores a 4: quicksort([1,4]) = [1,4]
mayores a 4: quicksort([10,11,9,8])=[8,9,10,11]
Se ubica el elemento pivot: [1,3] + 4 + [8,9,10,11]

2da iteración (a manera de ejemplo, lista=[10,11,9,8])

Se selecciona el pivot: 10
Se generan las dos sub-listas:
menores a 4: [9,8]
mayores a 4: [11]
Se ordenan las dos sub-listas
menores a 4: quicksort([9,8]) = [8,9]
mayores a 4: quicksort([11])=[11]
Se ubica el elemento pivot: [8,9] + 10 + [11]

Código base:

Se debe utilizar como código base el archivo

ENTREGABLE:

Proyecto GRADLE con el código fuente.

9.2. Código fuente base

La clase Lista representa una lista enlazada de elementos genéricos. Esta clase es una interfaz sellada (sealed interface) que permite definir dos implementaciones: Cons para una lista no vacía y Empty para una lista vacía.

Estructura de directorio del proyecto:

src
└── main
    └── java
       └── com
            └── concurso
                └── avanzada
                    └── reto1
                        ├── Cons.java
                        ├── Empty.java
                        ├── Lista.java
                        └── QuickSort.java
Diagram
Figura 8. Diagrama de Clases Nivel Avanzado - reto 1

La interface Lista define los métodos básicos para manipular listas enlazadas, como head(), tail(), isEmpty(), prepend(), y concat(). También incluye métodos estáticos para crear listas a partir de un elemento y una cola (tail), o a partir de un arreglo de elementos.

package com.concurso.avanzado.reto1;

public sealed interface Lista<T> permits Cons, Empty {
    Lista Empty = new Empty();

    T head();

    Lista<T> tail();

    boolean isEmpty();

    static <T> Lista<T> of(T elem, Lista<T> tail) {
        return new Cons<>(elem, tail);
    }

    static <T> Lista<T> of(T... elems) {
        var tmp = Lista.Empty;
        for (int i = elems.length - 1; i >= 0; i--) {
            tmp = Lista.of(elems[i], tmp);
        }

        return tmp;
    }

    default Lista<T> prepend(T elem) {
        return Lista.of(elem, this);
    }

    default Lista<T> concat(Lista<T> ls) {
        if (isEmpty()) {
            return ls;
        } else {
            return Lista.of(this.head(), tail().concat(ls));
        }
    }
}

La clase Cons representa una lista no vacía, que contiene un elemento head y una referencia a la cola de la lista tail. Implementa los métodos de la interfaz Lista, incluyendo el método isEmpty() que devuelve false para indicar que la lista no está vacía.

package com.concurso.avanzado.reto1;

record Cons<T>(T head, Lista<T> tail) implements Lista<T> {
    @Override
    public boolean isEmpty() {
        return false;
    }

    @Override
    public String toString() {
        return String.format("[%s,%s]", head, tail);
    }
}

La clase Empty representa una lista vacía, que lanza una excepción si se intenta acceder a su cabeza o cola (lista vacía). Implementa los métodos de la interfaz Lista, incluyendo el método isEmpty() que devuelve true para indicar que la lista está vacía.

package com.concurso.avanzado.reto1;

final class Empty<T> implements Lista<T> {
    Empty() {

    }

    @Override
    public T head() {
        throw new RuntimeException("Lista vacía");
    }

    @Override
    public Lista<T> tail() {
        throw new RuntimeException("Lista vacía");
    }

    @Override
    public boolean isEmpty() {
        return true;
    }

    @Override
    public String toString() {
        return "Empty";
    }
}

La clase QuickSort muestra el esquema de una posible implementación del algoritmo de ordenamiento QuickSort. Contiene un método partition que divide la lista en dos sub-listas basadas en un elemento pivot, y un método sort que ordena la lista utilizando el algoritmo QuickSort. El método sort también tiene una sobrecarga que permite ordenar listas de elementos que implementan la interfaz Comparable.

package com.concurso.avanzada;

import java.util.Comparator;

public class QuickSort {
    record Pair<T>(Lista<T> ls1, Lista<T> ls2) {
    }

    static <T> Pair<T> partition(T pivot, Lista<T> ls,
        Comparator<T> cmp) {
        //TODO: completar
    }

    public static <T> Lista<T> sort(Lista<T> ls, Comparator<T> cmp) {
        //TODO: completar
    }

    public static <T extends Comparable> Lista<T> sort(Lista<T> ls) {
        return QuickSort.sort(ls, Comparable::compareTo);
    }

    public static void main(String[] args) {
        //var ls = Lista.of(12,10,1,11,9,7,8);
        var ls = Lista.of(4,10,1,11,9,3,8);

        var sortedList = QuickSort.sort(ls);

        System.out.println(sortedList);
    }
}

9.3. Solución

La solución al reto consiste en completar la implementación del algoritmo QuickSort utilizando la clase Lista como base para manejar las listas enlazadas. A continuación se muestra el código completo de la clase QuickSort, que incluye el método partition para dividir la lista y el método sort para ordenar la lista utilizando el algoritmo QuickSort.

Listado 38. Nivel Avanzado - reto 1: QuickSort.java
package com.concurso.avanzado.reto1;

import java.util.Comparator;

public class QuickSort {
    record Pair<T>(Lista<T> ls1, Lista<T> ls2) {
    }

    static <T> Pair<T> partition(T pivot, Lista<T> ls,
                                          Comparator<T> cmp) {
        // se toma la cabecera de la lista
        //   si la cabecera es menor que el PIVOT,
        //     se agrega a la lista de la izquierda
        //   si la cabecera es mayor que el PIVOT,
        //     se agrega a la lista de la derecha
        // se repite el procedimiento para la cola
        // el procedimiento termina si la lista está vacía
        if (ls.isEmpty()) {
            return new Pair<>(Lista.Empty, Lista.Empty);
        } else {
            var h = ls.head();

            var tmp = partition(pivot, ls.tail(), cmp);

            if (cmp.compare(h, pivot) < 0) { //h<elem
                return new Pair<>(tmp.ls1.prepend(h), tmp.ls2);
            } else { //h>=elem
                return new Pair<>(tmp.ls1, tmp.ls2.prepend(h));
            }
        }
    }

    public static <T> Lista<T> sort(Lista<T> ls, Comparator<T> cmp) {
        if (ls.isEmpty()) {
            return Lista.Empty;
        } else {
            var mid = ls.head();

            var tmp = partition(mid, ls.tail(), cmp);

            var smallerSorted = QuickSort.sort(tmp.ls1, cmp);
            var largerSorted = QuickSort.sort(tmp.ls2, cmp);

            return smallerSorted.concat(Lista.of(mid, largerSorted));
        }
    }

    public static <T extends Comparable<T>> Lista<T> sort(Lista<T> ls) {
        return QuickSort.sort(ls, Comparable::compareTo);
    }

    public static void main(String[] args) {
        //var ls = Lista.of(12,10,1,11,9,7,8);
        var ls = Lista.of(4, 10, 1, 11, 9, 3, 8);

        var sortedList = QuickSort.sort(ls);

        System.out.println(sortedList);
    }
}

10. Base de datos y servicios REST

El objetivo de este reto consiste en construir una aplicación que permita importar datos desde un archivo CSV a una base de datos, y exponer servicios REST para consultar la información importada.

10.1. Reto 2

Considere la archivo disponible en la siguiente dirección, el cual contiene información del censo de población del año 2010 para la provincia de Pichincha (format CSV):

Considere las siguientes columnas:

Columna Descripción

I01/I02

Provincia, Cantón

P01

Sexo

P03

Edad

P04A/P04M

Año/mes de nacimiento

Construir una aplicación que permita realizar lo siguiente:

  • Definir una base de datos, con las respectivas tablas, para almacenar la información disponible en el recurso indicado previamente.

  • Modelar la información de la tabla anterior mediante una clase Persona. Mapear la clase Persona a la tabla creada en el punto 1 utilizando JPA.

    • Las tablas de la base de datos deben crearse de manera automática.

  • Importar los datos del archivo CSV proporcionado mediante descarga, realizando el siguiente proceso (utilizar solo construcciones funcionales):

    • Leer el archivo

    • Mediante un Stream, leer los n-primeros registros, mapear las columnas del archivo CSV a las columnas de la tabla indicada anteriormente.

    • Insertar los elementos en la base de datos utilizando JPA

  • Implementar un recurso REST que permita importar datos en la base de datos pasando como parámetro el número de registros a immportar.

  • Implementar un recurso REST que permita consultar el total de hombres y mujeres dado el código de cantón.

  • Implementar un recurso REST que permita consultar el total de hombres y mujeres dado el año de nacimiento. El proceso debe consultar el listado de personas para un determinado año, y luego, mediante operaciones con streams, totalizar el número de hombres y mujeres.

ENTREGABLE:

Proyecto GRADLE con el código fuente.

10.2. Solución

A continuación se presenta una posible solución al reto 2, nivel avanzado. El código está dividido en varias clases que representan la entidad Persona, el repositorio para acceder a los datos, los servicios para importar datos y los recursos REST.

Estructura de directorio del proyecto:

src
└── main
    └── java
       └── com
            └── concurso
                └── avanzada
                    └── reto2
                        ├── db
                        │   └── Persona.java
                        ├── dtos
                        │   └── CountDto.java
                        ├── repository
                        │   └── PersonaRepository.java
                        ├── rest
                        │   └── PersonasRest.java
                        └── servicios
                            ├── ImportarDatos.java
                            └── ImportarDatosImpl.java
Diagram
Figura 9. Diagrama de Clases Nivel Avanzado - reto 2

El archivo build.gradle.kts define las dependencias y configuraciones necesarias para el proyecto. Se utiliza Quarkus como framework para construir la aplicación, y se incluyen las dependencias para JPA, REST y CDI.

Listado 39. Nivel Avanzado - reto 2: build.gradle.kts
plugins {
    id("java")
    id("io.freefair.lombok") version "8.13.1"
    id("io.quarkus") version "3.22.2"
}

group = "com.concurso.avanzada"
version = "1.0-SNAPSHOT"

repositories {
    mavenCentral()
}

val quarkusVersion = "3.22.2"

java {
    sourceCompatibility = JavaVersion.VERSION_21
    targetCompatibility = JavaVersion.VERSION_21
}

dependencies {
    implementation(enforcedPlatform("io.quarkus.platform:quarkus-bom:${quarkusVersion}"))

    //CDI
    implementation("io.quarkus:quarkus-arc")

    //REST
    implementation("io.quarkus:quarkus-rest")
    implementation("io.quarkus:quarkus-rest-jsonb")

    //JPA
    implementation("io.quarkus:quarkus-hibernate-orm-panache")
    implementation("io.quarkus:quarkus-jdbc-postgresql")
}

tasks.withType<JavaCompile> {
    options.encoding = "UTF-8"
    options.compilerArgs.add("-parameters")
}

El archivo application.properties define la configuración de la base de datos, incluyendo el tipo de base de datos (PostgreSQL), las credenciales y el URL de conexión. También se pueden configurar opciones adicionales como la generación automática de la base de datos y el puerto HTTP.

Listado 40. Nivel Avanzado - reto 2: application.properties
quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=postgres
quarkus.datasource.password=postgres
quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/concurso
#quarkus.hibernate-orm.database.generation=drop-and-create
#quarkus.hibernate-orm.log.sql=true
#quarkus.hibernate-orm.log.format-sql=true
quarkus.http.port=8080
app.file-name=c:/datos/Pichincha_CSV_Poblacion.csv

La clase Persona representa la entidad que se va a mapear a la tabla de la base de datos. Utiliza anotaciones JPA para definir los atributos.

Listado 41. Nivel Avanzado - reto 2: Persona.java
package com.concurso.avanzado.reto2.db;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;

@Getter @Setter
@Entity
public class Persona {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column
    private String provincia;

    @Column
    private String canton;

    @Column
    private Integer sexo;

    @Column
    private Integer edad;

    @Column(name = "anio_nacimiento")
    private Integer anioNacim;

    @Column(name = "mes_nacimiento")
    private Integer mesNacim;
}

La clase PersonaRepository extiende PanacheRepositoryBase de Quarkus, lo que permite realizar operaciones CRUD sobre la entidad Persona. Incluye métodos para consultar el número de hombres y mujeres por cantón y por año de nacimiento.

Listado 42. Nivel Avanzado - reto 2: PersonaRepository.java
package com.concurso.avanzado.reto2.repository;

import com.concurso.avanzado.reto2.db.Persona;
import com.concurso.avanzado.reto2.dtos.CountDto;
import io.quarkus.hibernate.orm.panache.PanacheRepositoryBase;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.transaction.Transactional;

import java.util.List;
import java.util.stream.Collector;
import java.util.stream.Collectors;

@ApplicationScoped
@Transactional
public class PersonaRepository implements
        PanacheRepositoryBase<Persona, Integer> {

    @PersistenceContext
    EntityManager entityManager;

    public List<CountDto> findByCanton(String canton) {

        String sql = "select o.sexo, count(o) " +
                " from Persona o " +
                " where o.canton=?1 group by o.sexo";

        return entityManager.createQuery(sql, Object[].class)
                .setParameter(1, canton)
                .getResultList()
                .stream()
                .map(o -> new CountDto(
                        ((Integer) o[0]) == 1 ? "Hombres" : "Mujeres",
                        (Long) (o)[1]))
                .collect(Collectors.toList());
    }

    public List<CountDto> findByAnio(Integer anio) {
        var map = this.find("anioNacimiento", anio)
                .stream()
                .collect(Collectors.groupingBy(
                        Persona::getSexo, Collectors.counting()
                        ));

        if(map.isEmpty()) {
            return List.of();
        }

        return List.of(
                new CountDto("Hombres", map.getOrDefault(1, 0L)),
                new CountDto("Mujeres", map.getOrDefault(2, 0L))
        );
    }
}

La clase CountDto es un objeto de transferencia de datos (DTO) que se utiliza para devolver el conteo de hombres y mujeres en las respuestas REST. Contiene dos campos: key y count.

Listado 43. Nivel Avanzado - reto 2: CountDto.java
package com.concurso.avanzado.reto2.dtos;

public record CountDto(String key, Long count) {
}

La clase PersonasRest es un recurso REST que expone los endpoints para importar datos y consultar la información de las personas. Utiliza CDI para inyectar los servicios necesarios.

Listado 44. Nivel Avanzado - reto 2: PersonaRest.java
package com.concurso.avanzado.reto2.rest;

import com.concurso.avanzado.reto2.repository.PersonaRepository;
import com.concurso.avanzado.reto2.servicios.ImportarDatos;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;

@Path("/personas")
public class PersonasRest {

    @Inject
    ImportarDatos importarDatos;

    @Inject
    PersonaRepository personaRepository;

    @GET
    @Path("/importar/{count}")
    public Response importar(@PathParam("count") Integer count) {
        importarDatos.importar(count);

        return Response.ok("Personas importadas correctamente")
                .build();
    }

    @GET
    @Path("/{canton}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response personasPorCanton(
            @PathParam("canton") String canton) {

        var data = personaRepository.findByCanton(canton);

        if (data.isEmpty()) {
            return Response.status(Response.Status.NOT_FOUND)
                    .entity("No se encontraron personas: " + canton)
                    .build();
        }

        return Response.ok(data).build();
    }

    @GET
    @Path("/anio/{anio}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response personasPorAnio(@PathParam("anio") Integer anio) {

        var data = personaRepository.findByAnio(anio);

        if (data.isEmpty()) {
            return Response.status(Response.Status.NOT_FOUND)
                    .entity("No se encontraron personas: " + anio)
                    .build();
        }

        return Response.ok(data).build();
    }
}

La interfaz ImportarDatos define el contrato para el servicio de importación de datos. Contiene el método importar que recibe el número de registros a importar.

Listado 45. Nivel Avanzado - reto 2: ImportarDatos.java
package com.concurso.avanzado.reto2.servicios;

public interface ImportarDatos {
    void importar(Integer count);
}

La clase ImportarDatosImpl implementa la interfaz ImportarDatos y contiene la lógica para leer el archivo CSV, mapear los datos a la entidad Persona y persistirlos en la base de datos utilizando el repositorio PersonaRepository. Utiliza Java NIO para leer el archivo de manera eficiente.

Listado 46. Nivel Avanzado - reto 2: ImportarDatosImpl.java
package com.concurso.avanzado.reto2.servicios;

import com.concurso.avanzado.reto2.db.Persona;
import com.concurso.avanzado.reto2.repository.PersonaRepository;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.eclipse.microprofile.config.inject.ConfigProperty;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.atomic.AtomicInteger;

@ApplicationScoped
public class ImportarDatosImpl implements ImportarDatos {

    @Inject
    PersonaRepository repo;

    @Inject
    @ConfigProperty(name = "app.file-name",
            defaultValue = "c:/cc/Pichincha_CSV_Poblacion.csv")
    String csvFileName;

    public void importar(Integer count) {

        try {
            AtomicInteger cc = new AtomicInteger(0);;

            Files.lines(Path.of(csvFileName))
                    .skip(1) // 1=header
                    .takeWhile(it->cc.getAndIncrement()<count)
                    .map(it -> it.split(","))
                    .map(values -> {
                        Persona per = new Persona();

                        //sexo: P01->10
                        //edad: P03->12
                        //anioNacimiento: P04A->14
                        //mesNacimiento: P04M->13
                        var sexo = Integer.parseInt(values[10]);
                        var edad = Integer.parseInt(values[12]);
                        var anio = Integer.parseInt(values[14]);
                        var mes = Integer.parseInt(values[13]);

                        per.setProvincia(values[0]);
                        per.setCanton(values[1]);
                        per.setSexo(sexo);
                        per.setEdad(edad);
                        per.setAnioNacim(anio);
                        per.setMesNacim(mes);

                        return per;
                    })
                    .forEach(repo::persist);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

11. Tablero ajedrez

El objetivo de este reto es crear una imagen de un tablero de ajedrez utilizando programación concurrente. El tablero debe ser representado como un arreglo unidimensional de bytes, donde cada byte representa el color de una celda del tablero (blanco, negro).

11.1. Reto 3

Considere un tablero de ajedrez de dimensión 8x8:

Tablero ajedrez

La tarea consiste en generar una imagen de dimensión WxH con 4 canales (RGBA) la cual represente la imagen del tablero de dimensión MxM (M>1).

La imagen se la representará como un arreglo unidimensional de WxHx4 bytes.

La implementación se la debe realizar utilizando programación concurrente con n-hilos (threads) de ejecución, donde cada hilo solamente dibujará una de las celdas del tablero, por lo que se necesitarán MxM hilos. Se puede utilizar el siguiente código para guardar la imagen en el disco.

public static void saveImage( byte[] pixels, int width, int height,
  String outputPath) throws IOException {

    BufferedImage image = new BufferedImage(
    width, height, BufferedImage.TYPE_4BYTE_ABGR);

    WritableRaster raster = image.getRaster();
    raster.setDataElements(0, 0, width, height, pixels);

    ImageIO.write(image, "png", new File(outputPath));
}

ENTREGABLE:

Proyecto GRADLE con el código fuente.

11.2. Solución

A continuación se presenta una posible solución al reto 3, nivel medio. El código está dividido en varias clases que representan el tablero, la tarea de pintar el tablero y la información de la imagen.

Estructura de directorio del proyecto:

src
└── main
    └── java
       └── com
            └── concurso
                └── avanzada
                    └── reto3
                        ├── ImageInfo.java
                        ├── Main.java
                        ├── Tablero.java
                        └── TaskTablero.java
Diagram
Figura 10. Diagrama de Clases Nivel Avanzado - reto 3

La clase ImageInfo representa la información de la imagen, incluyendo su ancho, alto, número de canales y los datos de píxeles. Adionalmente, define constantes utilizadas en el tablero, como el número de canales y los colores utilizados para pintar cada celda del tablero.

Listado 47. Nivel Avanzado - reto 3: ImageInfo.java
package com.concurso.avanzado.reto3;

public record ImageInfo(int width, int height, int channels,
                        byte[] pixelData) {
    public final static int CHANNELS = 4;
    static final int[] colors = {0, 255}; // negro, blanco
}

La clase TaskTablero implementa la lógica para pintar cada casilla del tablero. Utiliza un patrón de colores alternos para las filas pares e impares.

Listado 48. Nivel Avanzado - reto 3: TaskTablero.java
package com.concurso.avanzado.reto3;

public class TaskTablero implements Runnable {
    private final Tablero tablero;

    private final int row;
    private final int col;

    public TaskTablero(Tablero tablero, int row, int col) {
        this.tablero = tablero;
        this.row = row;
        this.col = col;
    }

    @Override
    public void run() {
        int index = row * tablero.getTamTablero() + col;

        byte color = 0;

        if (row % 2 == 0) {
            //fila par
            color = (byte) ImageInfo.colors[col % 2];
        }
        else {
            color = (byte) ImageInfo.colors[(col + 1) % 2];
        }

        System.out.printf("task[%d, %d]: index=%d, color=%d\n",
                row, col, index, color);

        int xs = row * tablero.getBlockSize();
        int ys = col * tablero.getBlockSize();

        byte[] pixelData = tablero.getImage().pixelData();
        int width = tablero.getImage().width();

        for (int y = xs; y < xs + tablero.getBlockSize(); y++) {
            for (int x = ys; x < ys + tablero.getBlockSize(); x++) {
                int pixelIndex = (y * width + x) * ImageInfo.CHANNELS;
                pixelData[pixelIndex + 0] = color; // Rojo
                pixelData[pixelIndex + 1] = color; // Verde
                pixelData[pixelIndex + 2] = color; // Azul
                pixelData[pixelIndex + 3] = (byte) 255;
            }
        }
    }
}

La clase Tablero es responsable de crear el tablero y gestionar las tareas de dibujo. Utiliza múltiples hilos para dibujar cada casilla del tablero en paralelo.

Listado 49. Nivel Avanzado - reto 3: Tablero.java
package com.concurso.avanzado.reto3;

import lombok.Getter;

import java.util.ArrayList;
import java.util.List;

public class Tablero {
    @Getter
    private final int tamTablero;
    @Getter
    private final int blockSize;

    @Getter
    private final ImageInfo image;

    public Tablero(int tamTablero, ImageInfo image) {
        this.tamTablero = tamTablero;
        blockSize = image.width() / tamTablero;
        this.image = image;
    }

    void paint() {
        List<Thread> threads = new ArrayList<>();

        for (int row = 0; row < tamTablero; row++) {
            for (int col = 0; col < tamTablero; col++) {
                TaskTablero task = new TaskTablero(this, row, col);

                Thread th = new Thread(task);

                threads.add(th);

                th.start();
            }
        }

        threads.forEach(th -> {
            try {
                th.join();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });

        //contorno de la imagen
        int width = image.width();
        int height = image.height();

        int size = width * height;

        for (int i = 0; i < width; i++) {
            int index = i * ImageInfo.CHANNELS;

            image.pixelData()[index] = (byte) 0;
            image.pixelData()[index + 1] = (byte) 0;
            image.pixelData()[index + 2] = (byte) 0;
            image.pixelData()[index + 3] = (byte) 255;

            index = (size - i) * ImageInfo.CHANNELS - 4;
            image.pixelData()[index] = (byte) 0;
            image.pixelData()[index + 1] = (byte) 0;
            image.pixelData()[index + 2] = (byte) 0;
            image.pixelData()[index + 3] = (byte) 255;
        }

        for (int i = 0; i < height; i++) {
            int index = (i * width) * ImageInfo.CHANNELS;

            image.pixelData()[index] = (byte) 0;
            image.pixelData()[index + 1] = (byte) 0;
            image.pixelData()[index + 2] = (byte) 0;
            image.pixelData()[index + 3] = (byte) 255;

            index = ((i + 1) * width) * ImageInfo.CHANNELS - 4;
            image.pixelData()[index] = (byte) 0;
            image.pixelData()[index + 1] = (byte) 0;
            image.pixelData()[index + 2] = (byte) 0;
            image.pixelData()[index + 3] = (byte) 255;
        }
    }
}

La clase Main es el punto de entrada del programa. Crea una instancia del tablero, dibuja el tablero y guarda la imagen resultante en un archivo PNG.

Listado 50. Nivel Avanzado - reto 3: Main.java
package com.concurso.avanzado.reto3;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;

public class Main {
    public static void saveRgbImage(byte[] pixels, int width,
                                    int height, String outputPath)
            throws IOException {

        BufferedImage image = new BufferedImage(width, height,
                BufferedImage.TYPE_4BYTE_ABGR);

        WritableRaster raster = image.getRaster();
        raster.setDataElements(0, 0, width, height, pixels);

        ImageIO.write(image, "png", new File(outputPath));
    }

    public static void main(String[] args) throws Exception {
        //----
        int width = 1024;
        int height = 1024;
        int channels = 4; // RGB
        byte[] pixelData = new byte[width * height * channels];

        ImageInfo image = new ImageInfo(width, height,
                ImageInfo.CHANNELS, pixelData);

        Tablero tablero = new Tablero(8, image);

        tablero.paint();

        saveRgbImage(image.pixelData(),
                image.width(),
                image.height(),
                "c:/cc/image04.png"
        );
    }
}

Parte IV: Resultados

12. Resultados del Concurso de Programación 2025

El concurso se realizó en la modalidad de resolución de retos, en cada nivel todos los participantes inscritos se presentaron al primer reto en los horarios definidos, en el tiempo destinado resolvieron el reto y el jurado calificador revisó y,con el uso de una rúbrica, dio la nota respectiva a cada participante.

NIVEL INSCRITOS

BASICO

68

MEDIO

56

AVANZADO

26

Los mejores puntuados en cada categoría pasaron al segundo reto, en caso de empate, clasificaron todos los estudiantes que alcanzaron la misma nota, según consta en el siguiente cuadro:

NIVEL CLASIFICADOS SEGUNDO RETO

BASICO

27

MEDIO

20

AVANZADO

14

En la segunda ronda, a cada categoría se le asignó un nuevo reto, el cual fue sometido a revisión por el jurado calificador. En este reto pasaron a la siguiente ronda los estudiantes que alcanzaron los mejores puntajes, según consta en la siguiente tabla:

NIVEL CLASIFICADOS TERCER RETO

BASICO

7

MEDIO

5

AVANZADO

6

Luego de la evaluación rigurosa de los participantes por parte del jurado calificador, en cada uno de los retos planteados a cada nivel considerado en el concurso (básico, medio y avanzado), los ganadores en cada categoría son los siguientes:

12.1. Ganadores Nivel Básico

Tabla 2. Ganadores Nivel Básico
LUGAR NOMBRE CARRERA / SEMESTRE

1ro.

RUIZ SALAZAR DAVID MARCELINO

COMPUTACIÓN/ 2DO SEMESTRE

2do.

SAENZ PARAMO JOHAN ERNESTO

COMPUTACIÓN/ 3ER SEMESTRE

3ro.

OJEDA MORENO AUSTIN ISMAEL

COMPUTACIÓN/ 3ER SEMESTRE

12.2. Ganadores Nivel Medio

Tabla 3. Ganadores Nivel Medio
LUGAR NOMBRE CARRERA / SEMESTRE

1ro.

ALAMMARIN MOUAAZ

COMPUTACIÓN/ 6TO SEMESTRE

2do.

AGUAS JIMENEZ NELSON DAVID

COMPUTACIÓN/ 5TO SEMESTRE

3ro.

CONDOLO NARVAEZ BYRON PAUL

COMPUTACIÓN/ 7MO SEMESTRE

12.3. Ganadores Nivel Avanzado

Tabla 4. Ganadores Nivel Avanzado
LUGAR NOMBRE CARRERA / SEMESTRE

1ro.

MULLO PAUCAR BRYAN FERNANDO

COMPUTACIÓN/ 9NO SEMESTRE

2do.

POZO MALDONADO KEVIN FERNANDO

COMPUTACIÓN/ 8VO SEMESTRE

3ro.

ESTRELLA CAICEDO JUAN CARLOS

COMPUTACIÓN/ 10MO SEMESTRE

Felicitamos a los ganadores y agradecemos la participación de todos los estudiantes que hicieron eco de esta convocatoria y asumieron este reto con responsabilidad, de igual forma reconocer el compromiso asumido por la Dirección de Carrera para apoyar y continuar con este evento de gran importancia para la Carrera, pero sobre todo para los estudiantes. Un reconocimiento a los organizadores y colaboradores que hicieron posible este evento.

Anexo A: Figuras, tablas y código

Lista de figuras

Figura 1. Diagrama de Clases Nivel Básico - reto 1 nivel 2
Figura 2. Diagrama de Clases Nivel Básico - reto 2
Figura 3. Diagrama de Clases Nivel Básico - reto 3 nivel 1
Figura 4. Diagrama de Clases Nivel Básico - reto 3 nivel 2
Figura 5. Diagrama de Clases Nivel Medio - reto 1
Figura 6. Diagrama de Clases Nivel Medio - reto 2
Figura 7. Diagrama de Clases Nivel Medio - reto 3
Figura 8. Diagrama de Clases Nivel Avanzado - reto 1
Figura 9. Diagrama de Clases Nivel Avanzado - reto 2
Figura 10. Diagrama de Clases Nivel Avanzado - reto 3

Lista de tablas

Tabla 1. Cronograma del Concurso
Tabla 2. Ganadores Nivel Básico
Tabla 3. Ganadores Nivel Medio
Tabla 4. Ganadores Nivel Avanzado

Lista de código

Listado 1. Nivel Básico - reto 1 - nivel 1: TrianguloPascal.java
Listado 2. Nivel Básico - reto 1 - nivel 1: AppTriangulo.java
Listado 3. Nivel Básico - reto 1 - nivel 2: Coordenada.java
Listado 4. Nivel Básico - reto 1 - nivel 2: Laberinto.java
Listado 5. Nivel Básico - reto 1 - nivel 2: LaberintoMain.java
Listado 6. Nivel Básico - reto 2: PalabraAdiv.java
Listado 7. Nivel Básico - reto 2: AppAdivina.java
Listado 8. Nivel Básico - reto 3 - nivel 1: Cartas.java
Listado 9. Nivel Básico - reto 3 - nivel 1: Jugadores.java
Listado 10. Nivel Básico - reto 3 - nivel 1: Palo.java
Listado 11. Nivel Básico - reto 3 - nivel 1: Baraja.java
Listado 12. Nivel Básico - reto 3 - nivel 1: Jugador.java
Listado 13. Nivel Básico - reto 3 - nivel 1: App.java
Listado 14. Nivel Básico - reto 3 - nivel 2: Baraja.java
Listado 15. Nivel Básico - reto 3 - nivel 2: Carta.java
Listado 16. Nivel Básico - reto 3 - nivel 2: Jugador.java
Listado 17. Nivel Básico - reto 3 - nivel 2: MainReto32.java
Listado 18. Nivel Medio - reto 1: Empleado.java
Listado 19. Nivel Medio - reto 1: Usuario.java
Listado 20. Nivel Medio - reto 1: Desarrollador.java
Listado 21. Nivel Medio - reto 1: Administrador.java
Listado 22. Nivel Medio - reto 1: Departamento.java
Listado 23. Nivel Medio - reto 1: ClasificadorEtiquetas.java
Listado 24. Nivel Medio - reto 1: AppClasificador.java
Listado 25. Nivel Medio - reto 2: Recursos.java
Listado 26. Nivel Medio - reto 2: RecursoReal.java
Listado 27. Nivel Medio - reto 2: ProxyRecurso.java
Listado 28. Nivel Medio - reto 2: Sesion.java
Listado 29. Nivel Medio - reto 2: Main.java
Listado 30. Nivel Medio - reto 3: ConexionBD.java
Listado 31. Nivel Medio - reto 3: Persona.java
Listado 32. Nivel Medio - reto 3: PersonaDAO.java
Listado 33. Nivel Medio - reto 3: CreacionBase.java
Listado 34. Nivel Medio - reto 3: ReporteBuilder.java
Listado 35. Nivel Medio - reto 3: ReporteConcretoBuilder.java
Listado 36. Nivel Medio - reto 3: ReporteDirector.java
Listado 37. Nivel Medio - reto 3: ReportesApp.java
Listado 38. Nivel Avanzado - reto 1: QuickSort.java
Listado 39. Nivel Avanzado - reto 2: build.gradle.kts
Listado 40. Nivel Avanzado - reto 2: application.properties
Listado 41. Nivel Avanzado - reto 2: Persona.java
Listado 42. Nivel Avanzado - reto 2: PersonaRepository.java
Listado 43. Nivel Avanzado - reto 2: CountDto.java
Listado 44. Nivel Avanzado - reto 2: PersonaRest.java
Listado 45. Nivel Avanzado - reto 2: ImportarDatos.java
Listado 46. Nivel Avanzado - reto 2: ImportarDatosImpl.java
Listado 47. Nivel Avanzado - reto 3: ImageInfo.java
Listado 48. Nivel Avanzado - reto 3: TaskTablero.java
Listado 49. Nivel Avanzado - reto 3: Tablero.java
Listado 50. Nivel Avanzado - reto 3: Main.java