Sie befinden sich in einem einstöckigen Kerker. Es gibt einen Schatz, der durch verschlossene Türen geschützt ist. Türen können geöffnet werden, indem die entsprechenden Schlüssel gefunden werden. Ihr Ziel ist es, den kürzesten Weg zum Schatz zu finden.
Eingang
Die Eingabe erfolgt in Form eines zweidimensionalen Rasters, das das ursprüngliche Layout des Dungeons darstellt.
###########
#$ # g#
# # ####
###G## #
# ####C#
#c @ #
###########
Das bist du: @
Das sind Wände: #
Das ist der Schatz: $
Verschlossene Türen sind Großbuchstaben: A
... Z
Jede Tür hat einen entsprechenden Kleinbuchstabenschlüssel: a
...z
- Es wird immer eins
@
und eins geben$
. - Der Dungeon wird immer rechteckig sein.
Es kann nicht garantiert werden, dass die Außenkante des Dungeons eine Wand ist. Dies ist ein gültiger Dungeon:
$ A## @ a
- Es ist nicht garantiert, dass der Schatz erreichbar ist. Einige Dungeons sind möglicherweise nicht lösbar.
- Es kann Türen ohne Schlüssel geben, und es kann Schlüssel geben, die keine Türen öffnen.
- Es wird niemals doppelte Türen oder Schlüssel geben.
Ausgabe
Ihr Programm soll eine Folge von Druck R
, L
, U
, D
(oder 4 andere verschiedene Symbole) , um die repräsentieren kürzesten möglichen Weg zum Schatz. Hier RLUD
steht für rechts, links, oben und unten. Wenn es mehrere kürzeste Pfade gibt, muss Ihr Programm nur einen davon drucken.
- Du kannst nicht an eine Wand gehen.
- Sie können sich nicht außerhalb der Dungeongrenzen bewegen.
- Sie können eine Tür nicht betreten, ohne den Schlüssel aufzuheben.
- Gehe auf einen Schlüssel, um ihn aufzuheben.
- Es ist nicht notwendig, jede einzelne Tür zu öffnen.
Wenn es nicht möglich ist, den Schatz durch eine gültige Folge von Zügen zu erreichen, muss Ihr Programm beendet werden, ohne etwas zu drucken. (Ein abschließender Zeilenumbruch ist zulässig.)
Wertung
Das ist Code-Golf, also gewinnt die Antwort mit der niedrigsten Byteanzahl.
Testfälle
Jeder Testfall enthält die Höhe und Breite des Dungeons in der ersten Zeile und einen möglichen Pfad mit der optimalen Anzahl von Zügen in der letzten Zeile.
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)
Es ist nicht möglich, den Schatz in den folgenden Dungeons zu erreichen. Für diese Testfälle sollte keine Ausgabe erfolgen.
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#
#########################
Das folgende Snippet kann zur Validierung von Antworten verwendet werden.
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/>
quelle
Antworten:
Perl,
157152151 BytesBeinhaltet +4 für
-p0
(kann nicht nur als Erweiterung von gezählt werden,-e
da es'
an mehreren Stellen verwendet wird)Lauf mit dem Labyrinth auf STDIN:
keymaze.pl
:Ersetzen
\n
und^H
durch ihre wörtlichen Versionen für die beanspruchte Kerbe. Benötigt ca. 1 Stunde und etwas weniger als 2 Gigabyte auf meinem Rechner, um das große Labyrinth zu lösen.quelle
Java 8 -
12821277126812591257 BytesDies besteht alle Tests. Für einige von ihnen ergeben sich jedoch leicht unterschiedliche Ergebnisse (wenn es mehr als einen optimalen Weg gibt, was kein Problem darstellt).
Für den 4. Test gibt es folgendes:
An Stelle von:
Für den 5. Test gibt es folgendes:
An Stelle von:
Golf Version:
Ungolfed-Version
Eigenschaften:
Eingaben nehmen
Versuchen Sie Folgendes, um es auszuführen:
Oder, wenn Sie die ungolfed Version laufen lassen, ersetzen Sie die
G
durchTreasureHunt
.Die Datei sollte den Dungeon enthalten. Die Eingabe sollte nicht mit einem Zeilenvorschub enden. Außerdem werden nur Zeilenenden im
\n
Format akzeptiert . Es funktioniert nicht mit\r\n
oder mit\r
.Außerdem werden die Eingaben nicht überprüft oder bereinigt. Wenn die Eingabe fehlerhaft ist, ist das Verhalten undefiniert (wahrscheinlich wird eine Ausnahme ausgelöst). Wenn die Datei nicht gefunden werden kann, wird eine Ausnahme ausgelöst.
Bemerkungen
Meine erste Implementierung irgendwo in der Nähe von 1100 Bytes konnte den 5. Testfall nicht in angemessener Zeit lösen. Der Grund dafür ist, dass meine Implementierung alle möglichen Permutationen von sammelbaren Gegenständen (dh den Schlüsseln und dem Schatz), die zugänglich sind (dh nicht in einem unzugänglichen Raum eingeschlossen sind), brachial erzwingt.
Im schlimmsten Fall wären das mit allen 26 Schlüsseln und dem Schatz 27! = 10.888.869.450.418.352.160.768.000.000 verschiedene Permutationen.
Das OP hat nicht festgelegt, dass die Antwort in angemessener Zeit erfolgen soll. Ich halte dies jedoch für eine Lücke, die ich nicht ausnutzen möchte. Also habe ich beschlossen, es für alle Testfälle in akzeptabler Zeit laufen zu lassen. Um dies zu erreichen, werden in meinem überarbeiteten Programm Suchpfade beschnitten, die nachweislich schlechter sind als einige bereits bekannte Lösungen. Außerdem werden Unterauflösungen (dh dynamische Programmierung) zwischengespeichert, um zu vermeiden, dass möglicherweise viele identische Dungeons neu berechnet werden. Damit ist es möglich, den 5. Testfall in etwas mehr als einer Minute auf meinem Computer zu lösen.
Die Lösung ist rekursiv. Die Idee ist zunächst, den Abenteurer zu einem Gegenstand (einem Schlüssel oder dem Schatz) zu bringen. Im Fall eines Schlüssels wird, nachdem der Abenteurer ihn erreicht hat, ein neuer, ähnlicher Dungeon erstellt, in dem sowohl der Schlüssel als auch die Tür gelöscht werden und der Abenteurer dorthin verschoben wird, wo sich der Schlüssel befand. Damit wird der erzeugte einfachere Dungeon rekursiv gelöst, bis der Punkt erreicht ist oder der Algorithmus feststellt, dass es keinen erreichbaren Gegenstand gibt. Die Reihenfolge der zu besuchenden Elemente wird mit Bereinigen und Zwischenspeichern brachial erzwungen, wie oben erläutert.
Die Wegfindung zwischen dem Abenteurer und den Gegenständen erfolgt mit einem Algorithmus, der sowohl Floodfill als auch Dijkstra ähnelt.
Schließlich vermute ich, dass dieses Problem NP-vollständig ist (nun, die verallgemeinerte Version davon ohne Beschränkung der Anzahl der Türen / Schlüssel). Wenn dies zutrifft, erwarten Sie keine Lösungen, die sehr große Verliese mit unzähligen Türen und Schlüsseln in angemessener Zeit optimal lösen. Wenn suboptimale Pfade zugelassen würden, wäre dies mit einigen Heuristiken leicht zu verfolgen (gehen Sie nach Möglichkeit zum Schatz, andernfalls zum nächsten Schlüssel).
quelle