Hay muchos sitios de desafíos de programación, pero uno que se ha vuelto popular en los últimos años es Advent of Code, que consiste en 25 desafíos que se ofrecen diariamente en diciembre, antes de Navidad.
El primer AOC que completé fue en 2021, en GO. La hice porque necesitaba practicar Go, puesto que en ese tiempo estaba empezando a trabajar en Uber y este es el principal lenguaje que usamos para backend.
Hay personas que lo resuelven por verdadero deporte, porque hay un ranking, otros como en mi caso, para aprender o mejorar en algún lenguaje, pero también puede servir para prepararte para una entrevista técnica, por ejemplo.
Los problemas no son fáciles, y si no tienes experiencia pueden tomarte bastante tiempo para resolver. Yo trato de resolver al menos la primera parte del problema en el día, la segunda, que suele ser más compleja, la dejo para después. No me vuelvo loco tratando de resolver todo en el mismo día. Durante la mañana, antes de trabajar, o tomando el desayuno leo el problema, si me hace sentido intento una solución, sino le doy vueltas durante algún break o antes del almuerzo. Normalmente los problemas los resuelvo en la noche, después de haberme desconectado del trabajo. Si el día ha sido duro, simplemente paso.
Este año, hasta ahora, he resuelto completamente seis días, y los días 7 y 8 parcialmente. Si te interesan acá están las soluciones de los primeros cinco días, están escritas en Rust, así que puede ser útil si estás aprendiendo ese lenguaje. Por cada solución escribo un breve resumen de que es lo que hice, y van con un enlace a la fuente.
Día 1.
Parte 1, consiste en tomar el primer y último dígito de cada línea. Si un dígito solo ocurre una vez se duplica. Luego se suman. Esto lo hago usando map, y una función que busca los dígitos en cada línea.
Parte 2: para la parte dos hay que considerar palabras que pueden expresar números, como “one”, “nine”, etc. Pero hay veces en que estas palabras comparten algún carácter, como “threeight”, o “twone”. Usé una expresión regular, pero en Rust la biblioteca regex no soporta expresiones de este tipo, así que tuve que agregar todos los casos particulares de combinaciones para poder agregar esos números.
Día 2.
Parte 1, la primera línea del input tiene las restricciones que se deben cumplir. Luego simplemente mapeamos cada línea a un juego y filtramos los que cumplen las restricciones. La combinación de map y filter ayuda un montón.
Parte 2: en este caso hay que tomar el máximo valor de cada color y multiplicarlos, para obtener la “potencia” del juego, luego se suman. Esto se logra modificando un poco la parte 1.
Día 3.
Parte 1, la complejidad está en la parte “geométrica”. Hay que tener cuidad con los bordes. Es por eso que el código es bien complejo, con muchos ifs, hay otras técnicas para hacer esto más elegante, pero opté por una solución “quick and dirty”, que es lo que haría si estuviera con presión de tiempo en una entrevista real, por ejemplo.
Parte 2, en realidad es una variación de la primera parte, en que debes buscar en líneas donde encuentras un patrón específico ('*').
Día 4.
Parte 1, acá debes mapear cada línea en dos partes, los números ganadores y los apostados, luego buscas las coincidencias y cuentas los puntos. Mirando mi solución, ahora pienso que hay una forma mucho más simple de hacer esto, pero recuerda, “quick and dirty”, no gastaremos mucho tiempo optimizando más de lo necesario.
Parte 2, acá una solución naive probablemente sea muy ineficiente en términos de tiempo de ejecución y espacio, porque tenderás a incrementar cada tarjeta según las reglas definidas en el problema. No requieres hacer eso, basta con tener un contador de las veces que se copia cada tarjeta y después sumas. Recuerda en partir con 1 en cada contador.
Día 5.
Parte 1, acá lo que hago es crear los mapas que transforman de un tipo de material en otro y luego se aplican a cada semilla.
Parte 2, mi primera solució fue por fuerza bruta y optimizé la compilación del programa, y lo resolvió en un par de minutos. Luego me di cuenta de que en realidad se puede mapear al revés desde destino a origen y partir desde la localización hacia la semilla, y esa solución es bastante buena, así que la implementé el día después.