Preparamos un diccionario con las conexiones entre nodos (si a -> b entonces b -> a tambien) y luego llamamos a la función traverse que devuelve un generador de rutas que usamos para contabilizar la respuesta y mostrar las rutas al asuario.
Traverse empieza por generar una lista de rutas desde el nodo de partida ("start") y después itera cada una de ellas intentando aumentarlas con un nodo más, bien "end" bien uno que cumpla con las restricciones. Finalmente se emite la ruta si está completa o se almacena de nuevo.
Probamos con los diversos ejemplos de tests.
Y a continuación atacamos el puzle.
Bueno no muy contento ya que la versión recursiva me gustaba mas pero me obligaba a hacer copias profundas (deepcopy) de las rutas todo el rato. Un operador de copia profunda, yo qué se algo como =<= seria una adición al lenguaje intersante...)
En la segunda parte vamos a poder visitar alguna cueva pequeña por segunda vez. Esta vez traverse2(...) nos devuelve un stream con tuplas con la ruta y un Bool que indica si alguna cueva pequeña se visitó dos veces.
Una ligera modificación para gestionar el flag de "doble visita" en cada ruta y una claúsula adicional en el bloque condicional que permite añadir una cueva pequeña ya visita como último recurso cuando se han visitado todas las posibles.
Atacamos los puzles sin esperar muchas sorpresas gracias a los pocos cambios añadidos...
Y finalemente nos las vemos de nuevo con el puzzle. El hecho de imprimir cada ruta hace que la ejecución se dilate un poco mas de lo debido...
Bueno y acabo por Hoy (pese a que ya voy retrasado) por que habiendo llegado al ecuador del concurso me lo voy a tomar ya con mas tranquilidad...
El parser: secuencia de parsers "polymerP" y "newlineP >> rulesP" que capturan tanto la plantilla como las reglas. Creamos todos los subparser necesarios. Leed la función desde el final hacia arriba y veréis la "estructura"
la parte 1 "del tirón". Leemos las reglas y preparamos un diccionario.. BB -> C. En cada paso de polimerización convertimos el pólimero en pares(zip) y aplicamos la conversión a cada par según el dict. El resultado crece rápidamente por lo que abreviamos la salida si len > 60
El parser como siempre: construimos partes como número, coordenada etc.. Aquí la novedad es instructionP que parsea un "fold" y devuelve un lambda que realiza el doblado propiamente dicho "lambda a: fold(a, x, y)" donde x y son el eje e y la fila ó columna respectivamente.
para construir la hoja desde las coordenadas suminstradas tenemos la función data_to_sheet bastante directa (reseñar que hay que averiguar primero la dimensión de las lista de listas)
El parser!! No me canso de quitarme problemas leyendo la entrada con un poco de cuidado (incluso he tratado de correr el fichero de un puzle con el código de otro y esto ayuda a que nada que no tenga que pasar "pase"...
Leemos todos los "chunks" y de aquellos corruptos calculos su "score" an base al caracter que no cuadraba en el lexing.. Usamos un dict para las puntuaciones +
problemas de lectura comprensiva? yo, a veces, lo que me ha llevado a darme de bruces con el puzle (habiendo pasado el test) hasta que quité las diagonales que nadie me habia pedido 🤨
El parser. aprovechamos para probar estrategias de sanitización como por ejemplo leer la primera linea y adaptar el parser al vuelo para que las demas sean exactamente de la misma longitud +
Otro trabajo "guarro" y que conste que quise hacerlo de una forma elegante pero acabé haciéndolo en plan "el juego de la imitación" buscando el "Heil JS!" y esperando pacientemente a que la "bomba" cuadrase todo..
Ha sido muy guarro y no me ha gustado (he usado la fuerza bruta) asi que bueno ya daré con la solución mas elegante que seguramente será una función conveza o algo similar 😓