Estás en una mazmorra de un piso. Hay un tesoro protegido por puertas cerradas. Las puertas se pueden abrir buscando las llaves correspondientes. Su objetivo es encontrar el camino más corto hacia el tesoro.
Entrada
La entrada será una cuadrícula bidimensional que representa el diseño inicial de la mazmorra.
###########
#$ # g#
# # ####
###G## #
# ####C#
#c @ #
###########
Este es usted: @
Estas son paredes: #
Este es el tesoro: Las $
puertas cerradas son letras mayúsculas: A
... Z
Cada puerta tiene su correspondiente llave en minúscula: a
...z
- Siempre habrá uno
@
y uno$
. - La mazmorra siempre será rectangular.
No se garantiza que el borde exterior de la mazmorra sea una pared. Esta es una mazmorra válida:
$ A## @ a
- No se garantiza que el tesoro sea accesible. Algunas mazmorras pueden no tener solución.
- Puede haber puertas sin llave y puede haber llaves que no abren ninguna puerta.
- Nunca habrá puertas o llaves duplicadas.
Salida
Su programa debe imprimir una secuencia de R
, L
, U
, D
(u otros símbolos distintos 4) para representar el más corto camino posible hacia el tesoro. Aquí, RLUD
significa derecha, izquierda, arriba y abajo, respectivamente. Si hay varias rutas más cortas, su programa solo necesita imprimir una de ellas.
- No puedes moverte hacia una pared.
- No puedes moverte fuera de los límites de las mazmorras.
- No se puede pasar a una puerta sin recoger la llave.
- Muévete a una tecla para recogerla.
- No es necesario abrir todas las puertas.
Si no es posible alcanzar el tesoro a través de una secuencia válida de movimientos, entonces su programa debe finalizar sin imprimir nada. (Se permite una nueva línea final).
Tanteo
Este es el código de golf, por lo que gana la respuesta con el conteo de bytes más bajo.
Casos de prueba
Cada caso de prueba tendrá la altura y el ancho de la mazmorra en la primera línea, y una ruta posible, con el número óptimo de movimientos, en la última línea.
1 2
@$
R (1)
3 3
$
#Z#
@ z
RRLUUR (6)
3 5
c#d#$
#C#D
@
UUDDRRUUDDRRUU (14)
7 16
c # b # ###@
### #
A ##### ####
d # e
B ## #####
### C ##
# a DE $
RDDDDDDL (8)
16 37
#####################################
# #ijk #a M ##m## # # R #
# # # # # ####
###J#### ############# ### # P b#
#e N h # ####
########## ########### ###### #
# # # $ # # # ####
# D H # # # Q f#
# EcF # #####A##### ###### ####
# G # #####B##### # #
# K #####C##### ############
# # #
########### # #### ##### ####
# # p # # n # #
# d # @ # o# r #
#################Z###################
UUULLLLLLDDLLLDLLLLLLRRRRRRRRRUUURRRRRRRRRRRRRRRDDLLRRUULLUUUUUUURRRRRUURRRDRRRLLLLULLLLLDDLLLLUULLLUDLLLLLULLLRRRRRDRRRRRRDDLLLLLLLLLLLLDDDLLLLLLLDURRRRRRRRDDDDRRRRRRUUUUU (172)
No es posible alcanzar el tesoro en las siguientes mazmorras. Para estos casos de prueba, no debería haber salida.
1 3
@#$
7 11
#a#j#$#i#f#
# #E#F#c#H#
# #K#D#A#G#
# #
#C#J# #I#B#
#h#d# #L#g#
#l#e#@#b#k#
10 25
#########################
# fgh # # c B b # #
$ # # # # # #
###### # ##H###E## #
# #
# ######### ##e##
Z @ D y # # #
# ######### F C#
# G # Ad#
#########################
El siguiente fragmento se puede utilizar para validar respuestas.
function run() {var dungeonText = document.getElementById("dungeon").value;var dungeonLines = dungeonText.split("\n");var height = dungeonLines.length;var width = dungeonLines[0].length;var dungeon = new Array(height);for (i = 0; i < dungeon.length; i++) {var dungeonLine = dungeonLines[i];if (dungeonLine.length != width) {return error("The dungeon is not rectangular");} dungeon[i] = dungeonLines[i].split("");} var movesText = document.getElementById("moves").value;var moves = movesText.trim().split("");var moveCount = moves.length;var rowAt, colAt;for (r = 0; r < dungeon.length; r++) {for (c = 0; c < dungeon[r].length; c++) {if (dungeon[r][c] == '@') {rowAt = r;colAt = c;}}} var treasure = false;while (moves.length > 0) {var move = moves[0];var row = rowAt,col = colAt;switch (move) {case 'R':col++;break;case 'L':col--;break;case 'U':row--;break;case 'D':row++;break;default:return print(dungeon, moves, "Invalid move");} if (row < 0 || col < 0 || row >= height || col >= width) {return print(dungeon, moves, "Out of bounds");} var target = dungeon[row][col];if (target.match(/[A-Z#]/)) {return print(dungeon, moves, "Path blocked");} if (target.match(/[a-z]/)) {var door = target.toUpperCase();for (r = 0; r < dungeon.length; r++) {for (c = 0; c < dungeon[r].length; c++) {if (dungeon[r][c] == door) {dungeon[r][c] = ' ';}}}} if (target == '$') {treasure = true;} dungeon[row][col] = '@';dungeon[rowAt][colAt] = '.';rowAt = row;colAt = col;moves.shift();} if (treasure) {print(dungeon, moves, "Got the treasure in " + moveCount + " moves!");} else {print(dungeon, moves, "Failed to reach treasure");}} function error(message) {var result = document.getElementById("result");result.innerHTML = message;} function print(dungeon, moves, message) {var output = message + "\n";for (r = 0; r < dungeon.length; r++) {for (c = 0; c < dungeon[r].length; c++) {output += dungeon[r][c];} output += "\n";} for (i = 0; i < moves.length; i++) {output += moves[i];} var result = document.getElementById("result");result.innerHTML = output;}
Dungeon:<br/><textarea id="dungeon" name="dungeon" rows="20" cols="40"></textarea><br/>Moves:<br/><textarea id="moves" name="moves" cols="40"></textarea><br/><button id="run" name="run" onclick="run();">Start</button><br/><br/>Result:<br/><textarea id="result" name="result" rows="20" cols="40" disabled></textarea><br/>
fuente
Respuestas:
Perl,
157152151 bytesIncluye +4 para
-p0
(no se puede contar solo como una extensión de-e
porque se usa'
en varios lugares)Corre con el laberinto en STDIN:
keymaze.pl
:Reemplazar
\n
y^H
por sus versiones literales para la puntuación reclamada. Necesita alrededor de 1 hora y un poco menos de 2 Gigabytes en mi máquina para resolver el gran laberinto.fuente
Java
8-12821277126812591257 bytesEsto pasa todas las pruebas. Sin embargo, para algunos de ellos da resultados ligeramente diferentes (cuando hay más de una forma óptima, lo cual no es un problema).
Para la cuarta prueba, da esto:
En lugar de esto:
Para la quinta prueba, da esto:
En lugar de esto:
Versión de golf:
Versión sin golf
caracteristicas:
Tomando entrada
Para ejecutarlo, intente esto:
O si está ejecutando la versión sin golf, reemplace la
G
conTreasureHunt
.El archivo debe contener la mazmorra. La entrada no debe terminar con un avance de línea. Además, solo acepta finales de línea en el
\n
formato. No funcionará con\r\n
o con\r
.Además, no valida ni desinfecta la entrada. Si la entrada tiene un formato incorrecto, el comportamiento no está definido (es probable que arroje una excepción). Si no se puede encontrar el archivo, se generará una excepción.
Observaciones
Mi primera implementación en algún lugar cerca de 1100 bytes no pudo resolver el quinto caso de prueba en un tiempo razonable. La razón de esto es porque mi implementación obliga a todas las permutaciones posibles de objetos coleccionables (es decir, las llaves y el tesoro) que son accesibles (es decir, no están encerrados en una habitación inaccesible).
En el peor de los casos, con las 26 llaves y el tesoro, ¡serían 27! = 10,888,869,450,418,352,160,768,000,000 permutaciones diferentes.
El OP no especificó que la respuesta debería ser algo que se ejecutara en un tiempo razonable. Sin embargo, considero que esta es una laguna que no me gustaría explotar. Entonces, decidí hacerlo funcionar en un tiempo aceptable para todos los casos de prueba. Para lograr eso, mi programa revisado presenta poda en las rutas de búsqueda que han demostrado ser peores de lo que algunos ya saben. Además, también almacena soluciones en caché (es decir, programación dinámica) para evitar volver a calcular muchas mazmorras idénticas que puedan surgir. Con eso, es capaz de resolver el quinto caso de prueba en poco más de un minuto en mi computadora.
La solución es recursiva. La idea es primero llevar al aventurero a algún objeto (una llave o el tesoro). En el caso de una llave, después de que el aventurero la alcanza, se genera una nueva mazmorra similar con la llave y la puerta borradas y el aventurero se mueve a donde estaba la llave. Con eso, la mazmorra más simple generada se resuelve de forma recursiva hasta el momento en que se alcanza el tesoro o el algoritmo concluye que no hay ningún elemento accesible. El orden de los artículos a visitar es forzado por la fuerza bruta con poda y almacenamiento en caché como se explicó anteriormente.
La búsqueda del camino entre el aventurero y los elementos se realiza con un algoritmo que se asemeja tanto a Dilkstra como a Dilkstra.
Finalmente, sospecho que este problema es NP-completo (bueno, la versión generalizada del mismo sin limitación en el número de puertas / llaves). Si esto es cierto, no espere soluciones que resuelvan óptimamente mazmorras muy grandes con miríadas de puertas y llaves en un tiempo razonable. Si se permitieran caminos subóptimos, entonces sería fácilmente manejable con algunas heurísticas (solo vaya al tesoro si es posible, de lo contrario, vaya a la tecla más cercana).
fuente