Vous êtes dans un donjon d'un étage. Il y a un trésor qui est protégé par des portes verrouillées. Les portes peuvent être ouvertes en trouvant les clés correspondantes. Votre objectif est de trouver le chemin le plus court vers le trésor.
Contribution
L'entrée sera une grille à deux dimensions représentant la disposition initiale du donjon.
###########
#$ # g#
# # ####
###G## #
# ####C#
#c @ #
###########
C'est vous: @
Ce sont des murs: #
C'est le trésor: Les $
portes verrouillées sont en majuscules: A
... Z
Chaque porte a une clé minuscule correspondante: a
...z
- Il y en aura toujours un
@
et un$
. - Le donjon sera toujours rectangulaire.
Il n'est pas garanti que le bord extérieur du donjon soit un mur. Ceci est un donjon valide:
$ A## @ a
- Il n'est pas garanti que le trésor soit accessible. Certains donjons peuvent ne pas être résolus.
- Il peut y avoir des portes sans clé, et il peut y avoir des clés qui n'ouvrent aucune porte.
- Il n'y aura jamais de portes ou de clés en double.
Sortie
Votre programme doit imprimer une séquence de R
, L
, U
, D
(ou 4 autres symboles distincts) pour représenter le plus court chemin possible au trésor. Ici, RLUD
représente respectivement droite, gauche, haut et bas. S'il existe plusieurs chemins d'accès plus courts, votre programme n'a besoin que d'en imprimer un.
- Vous ne pouvez pas vous déplacer sur un mur.
- Vous ne pouvez pas vous déplacer en dehors des limites du donjon.
- Vous ne pouvez pas accéder à une porte sans ramasser sa clé.
- Déplacez-vous sur une clé pour la récupérer.
- Il n'est pas nécessaire d'ouvrir chaque porte.
S'il n'est pas possible d'atteindre le trésor par une séquence valide de mouvements, alors votre programme doit se terminer sans rien imprimer. (Une nouvelle ligne de fin est autorisée.)
Notation
Il s'agit de code-golf, donc la réponse avec le plus petit nombre d'octets l'emporte.
Cas de test
Chaque cas de test aura la hauteur et la largeur du donjon sur la première ligne, et un chemin possible, avec le nombre optimal de coups, sur la dernière ligne.
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)
Il n'est pas possible d'atteindre le trésor dans les donjons suivants. Pour ces cas de test, il ne devrait y avoir aucune sortie.
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#
#########################
L'extrait de code suivant peut être utilisé pour valider les réponses.
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/>
la source
Réponses:
Perl,
157152151 octetsComprend +4 pour
-p0
(ne peut pas être considéré comme une simple extension de-e
car il utilise'
à plusieurs endroits)Courez avec le labyrinthe sur STDIN:
keymaze.pl
:Remplacez
\n
et^H
par leurs versions littérales pour le score revendiqué. Nécessite environ 1 heure et un peu moins de 2 gigaoctets sur ma machine pour résoudre le grand labyrinthe.la source
Java 8 -
12821277126812591257 octetsCela passe tous les tests. Cependant, pour certains d'entre eux, cela donne des résultats légèrement différents (quand il y a plus d'une manière optimale, ce qui n'est pas un problème).
Pour le 4ème test, cela donne:
Au lieu de cela:
Pour le 5ème test, cela donne:
Au lieu de cela:
Version golfée:
Version non golfée
Fonctionnalités:
Prendre connaissance
Pour l'exécuter, essayez ceci:
Ou si vous exécutez la version non golfée, remplacez celle
G
-ci parTreasureHunt
.Le fichier doit contenir le donjon. L'entrée ne doit pas se terminer par un saut de ligne. De plus, il n'accepte que les fins de ligne au
\n
format. Cela ne fonctionnera pas avec\r\n
ou avec\r
.En outre, il ne valide ni ne désinfecte l'entrée. Si l'entrée est mal formée, le comportement n'est pas défini (susceptible de lever une exception). Si le fichier est introuvable, une exception sera levée.
Remarques
Ma première implémentation quelque part près de 1100 octets n'a pas pu résoudre le 5ème cas de test dans un délai raisonnable. La raison en est que mon implémentation force toutes les permutations possibles des objets de collection (c'est-à-dire les clés et le trésor) qui sont accessibles (c'est-à-dire non enfermés dans une pièce inaccessible).
Dans le pire des cas, avec les 26 clés et le trésor, ce serait 27! = 10,888,869,450,418,352,160,768,000,000 permutations différentes.
Le PO n'a pas précisé que la réponse devrait être quelque chose qui s'est déroulé dans un délai raisonnable. Cependant, je considère qu'il s'agit d'une échappatoire que je ne voudrais pas exploiter. J'ai donc décidé de le faire fonctionner dans un délai acceptable pour tous les cas de test. Pour y parvenir, mon programme révisé propose un élagage dans les chemins de recherche qui se sont avérés être pire que certains connaissent déjà la solution. De plus, il met également en cache des sous-solutions (c'est-à-dire la programmation dynamique) pour éviter de recalculer de nombreux donjons identiques qui pourraient survenir. Avec cela, il est capable de résoudre le 5ème cas de test en un peu plus d'une minute sur mon ordinateur.
La solution est récursive. L'idée est d'abord d'amener l'aventurier à un objet (une clé ou le trésor). Dans le cas d'une clé, une fois que l'aventurier l'a atteinte, un nouveau donjon similaire est généré avec la clé et la porte supprimées et l'aventurier s'est déplacé à l'endroit où se trouvait la clé. Avec cela, le donjon plus simple généré est résolu récursivement jusqu'au point où le trésor est atteint ou l'algorithme conclut qu'il n'y a aucun élément accessible. L'ordre des éléments à visiter est forcé brut avec l'élagage et la mise en cache comme expliqué ci-dessus.
La recherche de chemin entre l'aventurier et les objets se fait avec un algorithme qui ressemble à la fois à floodfill et à Dijkstra.
Enfin, je soupçonne que ce problème est NP-complet (enfin, la version généralisée sans limitation du nombre de portes / clés). Si cela est vrai, ne vous attendez pas à des solutions qui résolvent de manière optimale de très grands donjons avec des miryades de portes et de clés dans un délai raisonnable. Si des chemins sous-optimaux étaient autorisés, alors il serait facilement traçable avec quelques heuristiques (allez simplement au trésor si possible, sinon allez à la clé la plus proche).
la source