Ideas Errantes

Solvitur Ambulando


       .---_ 
      / / /\|
     / / | \ *
    /  /  \ \
   / /  / \  \ 
 ./~~~~~~~~~~~\.
( .",^. -". '.~ )
 '~~~~~~~~~~~~~' 

    

Lecciones de Advent of Code 2023

Read in English

TL;DR: Advent of Code 2023 en pocas palabras

Advent of Code es un desafío de programación interesante, pero se vuelve difícil rápidamente. Si eres nuevo o no te gustan los acertijos complicados, puede que sea demasiado. Sin embargo, es una gran oportunidad para mejorar tus habilidades de programación si estás preparado para un desafío. ¡Solo prepárate para un poco de frustración, matemáticas y tal vez algunas risas o enojos con elfos bastnate tontos!

No es mi primer año haciendo advenimiento del código, ¡pero sí el primero que completé!

Puedes encontrar mis soluciones de AoC 2023 aquí!

Descubrí Advent of Code por primera vez en 2021, pero rápidamente me di cuenta de que no se trataba de pequeños acertijos de programación (una vez que pasas alrededor del día 5, ¡se vuelve bastante complicado!). ¡En 2021, me di por vencido después de obtener solo 7 estrellas! Luego, en 2022, gracias a la increíble comunidad subreddit encontré motivación y energía para llegar hasta el día 15; después de esto, no estaba listo para entender los conceptos necesarios para hacer un código (o incluso entender una solución de otra persona) para obtener las respuestas del día 16 (y ni siquiera hablemos de los próximos días). ¡Por eso hoy estoy bastante contento y orgulloso de mí mismo después de conseguir las 50 estrellas * de este año 2023!

¡Advent of Code no es un desafío fácil de completar si no tienes una sólida experiencia en informática y matemáticas!

Dicho esto, quiero compartir algunas de las lecciones que aprendí al hacer Advent of Code 2023. Con todas las horas que pasé depurando programando, surgieron algunas lecciones en forma de intentos desesperados de obtener soluciones nuevos algoritmos, enfoques para simplificar el código y uso de funciones y expresiones regulares de JavaScript.

¡Espero que estas pequeñas lecciones puedan ser útiles de alguna manera para ti!

Lección 1: ¡Analizando datos para ejecutarlos en la consola de Google Chrome DevTools!

Como desafío personal (y más tarde como una forma de facilitar que otros probaran mis soluciones) decidí ejecutar mi AoC en la pestaña de la consola de Google Chrome DevTools (la opción de Inspeccionar de tu navegador que te hace sentir como un hacker cuando sabes usarla). Entonces, lo primero que debía hacer era encontrar una manera de analizar fácilmente los datos de los ejemplos y los inputs para manipularlos y resolver los desafíos.

Después de 2 o 3 días, descubrí lo que sería la línea de código más recurrente en mis soluciones AoC: const data = $0.innerText.split('\n').slice(0,-1); Hay algunas variaciones de esta línea dependiendo del desafío del día, pero en general, siempre se ve así.

¿Qué significa $0 en este caso? te preguntarás; y la respuesta es simple: una vez que abre la opción Inspeccionar, la etiqueta html seleccionada se puede recuperar en la consola con la expresión $0. Esto facilita la obtención de las propiedades de ese elemento seleccionado. Sabiendo que en la página de input solo hay un elemento (la etiqueta prev con la etiqueta de code dentro con el texto), esta expresión siempre funcionará para obtener el texto interno de la página de entrada.

En caso de que tengas curiosidad, mi método para obtener los datos antes de saber esto era literalmente copiar el texto en una constante (¡como un cavernícola!), luego, cuando me convertí en un homo sapiens, comencé a usar const data = document.getElementsByTagName("pre")[0].innerText.split('\n').slice(0,-1); Con el $0 evolucioné a un Homo Sapiens Sapiens =)

.split('\n').slice(0,-1); resulta útil gracias a que los ejemplos e inputs de cada día mantienen la misma estructura: líneas de texto separadas por un salto de línea cada una y un espacio en blanco (' ') al final.

Después de eso, dependiendo de cómo se deben manipular los datos, surgió otra forma estándar de "dividir" esas líneas de texto para extraer la información. Aquí hay un ejemplo del día 13:

Ejemplo de datos a analizar:

                        
#.##..##.
..#.##.#.
##......#
##......#
..#.##.#.
..##..##.
#.#.##.#.
                        
                    

Ejemplo de código para analizar esos datos:

                        
data.forEach((line, i) => {
    if (line != '') {
        m.push(line);
        i === data.length-1 ? mirrors.push(m) : null;
    } else {
        mirrors.push(m);
        m = [];
    }
});                
                        
                    

¡Tener una forma constante de analizar datos facilita comenzar a programar cada reto cada día!

Lección 2: ¡Benditos sean los RegEx!

¡Solía ​​odiar las expresiones regulares! (RegEx para los amigos) Me parecían muy contra-intuitivos y nada amigables. Después de todo, ¡¿cómo carajos es que '/\D/g' significa todas las apariciones de caracteres que no sean dígitos?! Pero cuando notas que al simplemente escribir str = item.replace(/\D/g, ''); puedes convertir esto abc123def456 en esto 123456 en vez de conseguir lo mismo de esta forma:

            
for (let i = 0; i < line.length; i++) {
    if (line[i] === '0' || line[i] === '1' || line[i] === '2' || line[i] === '3' 
    || line[i] === '4' || line[i] === '5' || line[i] === '6' || line[i] === '7' 
    || line[i] === '8' || line[i] === '9') {
        str += line[i];
    }
}
            
        

¡Ahí es cuando entiendes la belleza de las RegEx!

Todavía estoy aprendiendo cómo crear mis nuevas expresiones de mejores amigas, mientras aprendo, ChatGPT es un gran compañero para ayudarme a generar estas expresiones infernales.

Lección 3: Ego viam inveniam aut faciam

"Encontraré una manera, o la crearé.",
esa es la traducción.

Los algoritmos de búsqueda son algo que no puede faltar en tu repositorio de programación si planeas participar en AoC. El año pasado aprendí sobre Breadth-First Search (BFS) y cómo implementarlo para encontrar el camino más corto en un mapa/gráfico. Durante este año, no sólo aprendí a escribir variantes de este algoritmo, sino que también exploré algunos algoritmos nuevos e interesantes. Pero antes de profundizar en ellos, aquí tienes algunos conceptos que te gustaría saber para sobrevivir al siguiente párrafo:

Aquí hay una pequeña descripción general de algunos de estos hermosos algoritmos:

  1. BFS. Éste es particularmente útil para encontrar el camino más corto en un gráfico no ponderado. El punto clave de BFS es que explora todos los vértices en el nivel actual de una cola (lista de espera) antes de pasar a los vértices del siguiente nivel. Esto garantiza que se descubra primero el camino más corto a cada vértice alcanzable. Aquí está una de mis implementación de este algoritmo, específicamente de mi solución del día 10:
    while (queue.length > 0) {
        let pipe = queue.shift();
        let neighbors = getNeighbors(pipe);
        for (let i = 0; i < neighbors.length; i++) {
            let neighbor = neighbors[i];
            let contains = visited.some( (v) => v.x === neighbor.x && v.y === neighbor.y );
            if (!contains) {
                visited.push(neighbors[i]);
                queue.push(neighbors[i]);
            }
        }
    }
    
  2. DFS. Es otro algoritmo de recorrido de gráficos que explora un gráfico visitando cada rama lo más lejos posible antes de retroceder. Al igual que BFS, DFS se utiliza para recorrer gráficos y se puede aplicar a varios problemas relacionados con gráficos.
  3. Dijikstra. Es un algoritmo popular y ampliamente utilizado en informática y teoría de grafos para encontrar el camino más corto entre nodos en un gráfico. A diferencia de BFS, es más útil con gráficos ponderados. El algoritmo de Dijkstra se basa en el principio de "codicia" (greediness) al seleccionar siempre el nodo con la distancia tentativa más pequeña para la exploración. Garantiza que una vez que un nodo se marca como visitado, su distancia tentativa sea la más corta posible.
  4. A* (se pronuncia "A estrella"). Es un algoritmo popular de búsqueda y recorrido de gráficos que combina los principios del algoritmo de Dijkstra y la búsqueda codiciosa de best-first search. Los puntos clave de A* son el uso tanto del costo real desde el nodo inicial (valor g) como de la estimación heurística hasta el nodo objetivo (valor h) para tomar decisiones informadas sobre qué nodos explorar.

No estoy haciendo justicia a estos algoritmos con mis pobres explicaciones, por lo que te recomiendo que los busques en tu fuente de información de programación favorita para aprender más sobre estas poderosas herramientas.

Lección 4: Encontrar ciclos usando MCM

Quizás el descubrimiento más interesante que hice en este año de AoC es la posibilidad de utilizar MCM para identificar ciclos o patrones repetitivos. El mínimo común múltiplo (MCM) es un concepto de matemáticas que seguro aprendiste durante tus años de escuela/colegio, pero que probablemente nunca volviste a utilizar (y apenas lo recuerdas); fue mi caso hasta que me encontré atrapado en el día 8 parte 2 y, buscando una salvación solución, Descubrí que este concepto podría aplicarse al desafío del día para evitar el tiempo eterno que requeriría una implementación de fuerza bruta para dar una respuesta.

Un poco de matemática escolar: ¿qué es MCM?

MCM significa "Mínimo Común Múltiplo" y es un concepto matemático que se utiliza para encontrar el entero positivo más pequeño que es múltiplo de dos o más números. Veámoslo con un ejemplo sencillo gracias a ChatGPT por ahorrarme tiempo con esto
Para encontrar el mínimo común múltiplo (MCM) de 4 y 6, puedes seguir los pasos descritos a continuación:

  1. Factorización prima:
    
    4 = 22
    6 = 21 × 3 1
    
    
  2. Recopilar factores primos: en este caso, los factores primos únicos son 2, 3.
  3. Multiplicar: MCM(4,6) = 22 × 31 = 4 × 3 = 12
Entonces, el mínimo común múltiplo de 4 y 6 es 12. Fácil, ¿verdad?

Aunque en código, parece un poco más complicado. Aquí está mi implementación en JavaScript:

En vez de MCM, como escribo el código originalmente en inglés, leerás LCM (Least Common Multiple)
function findLCM(numbers) {
    function findGCD(a, b) {
        return b === 0 ? a : findGCD(b, a % b);
    }
    function findLCMOfTwo(a, b) {
        return (a * b) / findGCD(a, b);
    }
    let lcm = numbers[0];
    for (let i = 1; i < numbers.length; i++) {
        lcm = findLCMOfTwo(lcm, numbers[i]);
    }

    return lcm;
}

findLCM([4,6]);

Con esta implementación, puede pasar cualquier cantidad de números a un [array] y devolverá el MCM de esos números.

Lección 5: Las fórmulas del área del polígono.

Siguiendo con las matemáticas que aprendiste pero que nunca usaste, otro concepto interesante que aprendí en este evento de AoC fue cómo usar la Fórmula del cordón y el Teorema de Pick para encontrar el área y los puntos interiores de un polígono.

Conociendo los puntos verdes, calcular los puntos rojos en una figura como esta puede resultar muy útil para diferentes aplicaciones. Por ejemplo, sistemas de información geográfica, diseño asistido por ordenador (CAD), juegos, robótica y planificación de rutas. Esto es algo que se puede conseguir calculando el área y el interior del polígono.

¿Recomendaría los eventos de Adviento del Código?

Es algo que he estado pensando en los últimos días. AoC es definitivamente una excelente experiencia de programación para aprender, pero también puede ser muy frustrante. Solo hay que mirar las estadísticas para notarlo. +220 mil usuarios obtuvieron las dos estrellas del día 1, pero solo casi 7 mil usuarios obtuvieron las dos estrellas del día 25 (en caso de que no lo sepas, para obtener la última estrella, se requiere tener todas las demás estrellas), así que aquí surge una pregunta interesante ¿esto habla más del poco interés de los programadores en desafíos o de la dificultad AoC?

En mi opinión personal, Advent of Code no es algo para principiantes o personas que no toleran el fracaso en una actividad por diversión. Aunque la sección Acerca de AoC señala que se trata de un evento con pequeños acertijos de programación en el que puedes participar sin experiencia en Informática , la realidad es que después de los primeros días, no hay pequeños acertijos y necesitarás un conocimiento sólido de informática y matemáticas para avanzar (pero ey, dice "participar", ¡no ganar!). No me sentiría cómodo recomendando AoC a alrededor del 90% de los programadores que conozco. Puedo decir con seguridad que desistirían tan pronto como comiencen los días con dos dígitos.

Dicho esto, Advent of Code sigue siendo una gran oportunidad para mejorar las habilidades de programación y aprender mucho. Si puedes manejar la frustración de depurar código durante varias horas, implementa conceptos matemáticos complicados en tu código y no enojarte con los elfos por ser tan ingenuos... todo esto solo para obtener algunos asteriscos digitales como este *, ¡entonces deberías intentarlo! bajo tu propia responsabilidad


En conclusión, Advent of Code 2023 resultó ser un gran viaje, no solo para superar los desafíos de programación sino también para adquirir conocimientos y técnicas invaluables para mejorar mis habilidades. ¿Has probado AoC? ¿Has aprendido algo de ello? ¿Algo que te gustaría compartir al respecto? Si lees hasta aquí, ¡me gustaría saber de ti! No dudes en enviarme un correo electrónico: hi@ivanr3d.com si hay algo que quieras compartir. Me encantaría enriquecer este artículo con más ideas y experiencias de otras personas.

¡Gracias por leer! Si quieres, comparte estos pensamientos con alguien más: