Ich will dich verdursten sehen

12

Sie sind ein Reisender, der die Wüste zwischen zwei Städten durchquert. Sie können nicht genug Wasser tragen, um ohne anzuhalten durchzukommen. Dies ist eine Variante eines klassischen Puzzles.

Die Regeln

Eine Wüste sieht so aus: ein BxH-Gitter mit größtenteils leerem Raum. Das markierte Feld Sbefindet sich dort, wo Sie beginnen, Ewo Sie enden möchten, und ein mit der Nummer N markiertes Quadrat enthält N Wassereinheiten. Quadrate, die mit einem .Hold-Zero Wasser markiert sind.

.....................................
........S............................
.....................................
.........7...........................
.....................................
.......................3.............
.....5...............................
................................2....
.....................................
.....................................
.....................................
...............................E.....
.....................................
....................7................
.....................................
.....................................

Sie beginnen bei S mit 5 Einheiten Wasser.

Sie können maximal 5 Einheiten Wasser mitführen.

Jedes Mal, wenn du an der Reihe bist

  1. ein Quadrat nach oben, unten, links oder rechts bewegen,
  2. verbrauchen Sie 1 Einheit Wasser, das Sie tragen,
  3. Nehmen Sie einige Wassereinheiten auf oder lassen Sie sie fallen .

Ein wiederum notiert also: (direction)(+|-)(units of water), +zeigen Sie Wasser Aufnehmen, -dass Sie es fallen.

Beispiel Kurven:

D+0        Move Down
R+0        Move Right
D+2        Move Down, pick up two units of water.
U-1        Move Up, drop one unit of water.

Wenn Sie diese Züge ab S im obigen Beispiel ausführen, sieht die Wüste danach so aus.

.....................................
........S............................
.........1...........................
.........5...........................
.....................................
.......................3.............
.....5...............................
................................2....
.....................................
.....................................
.....................................
...............................E.....
.....................................
....................7................
.....................................
.....................................

Sie können nicht mehr Wasser aufnehmen, als sich bereits auf Ihrem Platz befindet. Wenn Sie das Wasser aufheben, ziehen Sie diese Anzahl von Einheiten von der Zählung der Kacheln ab.

Sie können nur Wasser aufnehmen, um maximal 5 Einheiten aufzunehmen.

Kein Plättchen kann mehr als 9 Einheiten enthalten, außer S, das unendlich viele Einheiten enthält.

Sie können nur so viel Wasser fallen lassen, wie Sie gerade halten.

Das Wasser auf dem Boden bleibt unverändert, bis Sie es wieder aufnehmen.

Wenn Sie zu S zurückkehren, können Sie eine beliebige Menge Wasser aufnehmen, ohne es zu verbrauchen.

Wenn Sie E erreichen , gewinnen Sie . Sie gewinnen immer noch, wenn Sie Ihre letzte Wassereinheit auf E verbrauchen.

Wenn du nach deinem Zug null Wasser hast und nicht auf E bist, stirbst du .

Ein- und Ausgang

Ihr Programm erhält eine Startkarte beliebiger Größe STDINals ASCII-Grafik im obigen Format. Sie können davon ausgehen, dass es sich um ein Rechteck handelt, dh dass alle Zeilen die gleiche Länge haben, dass es genau ein Sund ein EQuadrat gibt, dass alle Zeilen mit abgeschlossen \nsind und dass die gesamte STDIN diesem regulären Ausdruck entspricht:/^[SE1-9\.\n]+$/

Ihr Programm schreibt die folgende Ausgabe nach STDOUT:

  1. die Liste der Züge,
  2. der Endzustand der Karte.

Sie können die Liste der Züge in einem beliebigen Format ausgeben.

Der Endzustand der Karte wird im selben Format wie die Eingabe gedruckt, außer dass zusätzlich die Route angezeigt wird, die Sie durch die Wüste genommen haben, indem alle besuchten Kacheln mit markiert werden #, wenn diese Kacheln kein Wasser enthalten und nicht S oder E sind (d. H es ist .).

BEISPIEL Eingabe:

.....S.
.......
.......
E......
....8..

BEISPIEL für eine erfolgreiche Ausgabe:

D+0
D+0
D+0
D+0
L+5
L+0
L+0
L+0
L+0
U+0
.....S.
.....#.
.....#.
E....#.
####3#.

Nichttrivialität

Wenn Sie Ihren Code veröffentlichen, veröffentlichen Sie eine Beispiel-Map-Eingabe, in der Ihr Code eine Lösung findet, für die die folgenden Nicht-Trivialitätsbedingungen erfüllt sind:

  • S und E sind mindestens 10 Züge voneinander entfernt.
  • Jedes Quadrat, das anfänglich N Wassereinheiten enthält, muss von einem N-breiten Rand umgeben sein, in dem sich alle Quadrate befinden .(kein Wasser, kein S oder E).

BEISPIEL

........2.
..........
..........
S.1..2....
..........
..........
........1.
..3.......
.........E

Wenn Sie die Wassermenge auf einer Fliese erhöhen, ist das oben Gesagte trivial.

Bedarf

Vermutlich wird Ihr Programm eine Reihe von fehlgeschlagenen Versuchen haben, bevor es eine Lösung findet.

  1. Ihr Programm muss eventuell lösbare Eingaben lösen.
  2. Ich möchte Ihnen beim Sterben zusehen - Ihr Programm gibt die Züge und die endgültige Karte der Route zum Tode für jeden fehlgeschlagenen Versuch, eine Lösung zu finden, aus.
  3. Wenn Sie auf eine gewinnbringende Lösung stoßen, drucken Sie die vollständige Ausgabe aus und beenden Sie den Vorgang.
  4. Führen Sie den Test durch, bis eine Lösung gefunden wurde. Versuchen Sie jedoch nicht, dieselbe Lösung zweimal zu verwenden. Alle Todesfälle sollten auf unterschiedlichen Wegen verlaufen.
  5. Verwenden Sie dies als Testeingang:

(Es ist mindestens eine Bewegung erforderlich, um einen Wasser-Cache in der Mitte abzulegen.)

 S........
 .........
 .........
 ........E

Kürzester Code, der mit einer nicht trivialen Demonstrationseingabe gepostet wird, die er löst, gewinnt.

spraff
quelle
Dies muss geklärt werden, um anzugeben, ob das Programm in der Lage sein muss, lösbare Karten zu lösen, oder ob es nur für eine Karte funktionieren muss. Ich würde das erstere definitiv ermutigen; Bei einer Karte ist es einfacher, die Lösung fest zu codieren, als sie zu berechnen.
Zur Verdeutlichung bearbeitet. Ja, Sie gewinnen, wenn Sie mehr als null Wasser haben, und ja, Ihr Programm muss alle lösbaren Eingaben lösen.
Spraff
Was hindert Sie daran, einen Algorithmus wie A * zu verwenden und einen Pfad von 5 Einheiten auf jedem Plättchen abzulegen, zu dem Sie nacheinander gehen und zum Anfang zurückkehren, wenn Sie auf ein Plättchen ohne 5 Wasser treten?
Blue
Nichts. Gehen Sie geradeaus.
Spraff
Die Strategie, alles Wasser aus S zu befördern, sollte funktionieren, auch wenn sie furchtbar langweilig sein wird. Betrachten Sie S.,.,.,. E .... E wo und e sind wirklich Punkte. Die Kommas sind, wo Sie Ihre Verstecke auf dem Weg aufbewahren, und 'e' ist, wo Sie 5 Wasser haben müssen, um einen Lauf für E zu machen. 4 Schritte, um 1 Wasser zum ersten Komma zu bewegen (E + 0 E-1 W + 0 W + 4). 16 Schritte, um 1 Wasser zum zweiten Komma zu verschieben. 52 bis zum dritten, 160 bis zum vierten, 484 bis 1 Wasser auf e fallen und zurück zu S. 1926 Schritte und Sie sind bei e tragen 5 Wasser, 5 weitere bis E laufen, 1931 Schritte. Alle zwei Schritte des Pfades verdreifachen effektiv Ihre Lösungslänge.
Sparr

Antworten:

12

Perl, 299 + 1 = 300, 254 + 1 = 255 Bytes

Dies wird mit ziemlicher Sicherheit von einer der Golfsprachen übertroffen, wenn Leute meinen Algorithmus sehen :-)

Laufen Sie mit -n(1 Byte Strafe).

Die vorherige Version entsprach nicht ganz der Spezifikation, da zusätzliches Wasser auf der Karte zurückblieb und in der endgültigen Version der Karte nicht angezeigt wurde. Während ich den Algorithmus änderte, um mit dieser Situation umzugehen, schaffte ich es ein bisschen kleiner zu spielen.

push@a,[split//];($s,$t)=(length$`,$.)if/S/;($e,$f)=(length$`,$.)if/E/}{$_.=$s<$e?($s++,R):$s>$e?($s--,L):$t<$f?($t++,D):($t--,U);$\=reverse$";$".=y/LRUD/RLDU/r.Y.reverse.($"=~y/Y/X/r);$a[$t-1][$s]=~y/./#/;$\.=$s-$e||$t-$f?redo:$_;print map{join'',@$_}@a

Beispiel (Ich habe der Ausgabe Zeilenumbrüche hinzugefügt, um das Scrollen und Anzeigen der Struktur zu vermeiden):

E .....
# .....
# .....
# .....
##### S
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLUXDRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLUUXDDRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLUXDRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLUUUYDDDRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLUXDRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLUUYDDRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLUYDRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLYRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLYRRRR
 LXR LLXRR LXR LLLYRRR LXR LLYRR LYR LLLLLUUUU

In der Notation durch das Programm verwendet wird , wird die Bewegung vertreten durch L, R, Uund Dfür links, oben, rechts, unten sind. Standardmäßig nehmen Sie nach jeder Bewegung 1 Einheit Wasser auf, dies kann jedoch durch Hinzufügen eines Zeichens geändert werden:

  • X: 2 Einheiten Wasser fallen lassen, anstatt 1 aufzuheben
  • Y: 1 Einheit Wasser fallen lassen, anstatt 1 aufzuheben
  • (dh Leerzeichen): vollständig auf Wasser nachfüllen (erst nach einem Wechsel zu S; das Programm wird auch mit einem führenden Leerzeichen ausgegeben, was sinnvoll ist, weil Sie voll mit Wasser beginnen)

Wie Sie sehen, ist es möglich, diese (eher unfruchtbare) Karte ohne zusätzliche Pools zu überqueren. Tatsächlich ist es möglich, mit diesen Regeln auf jeder Karte eine beliebige Entfernung zu erreichen , ohne dass Wasser vorab eingelagert werden muss. Als solches ignoriert dieser Algorithmus nur vorgelagertes Wasser, was bedeutet, dass ich keine Bytes verschwenden muss, die versuchen, damit umzugehen. Das bedeutet auch, dass Sie den Bot nicht sterben sehen werden, sorry. Es bewegt sich nie über den Bereich hinaus, in dem es sein Überleben garantiert.

Der Grund, warum wir beides Xund benötigen Y(und ein bisschen zusätzlichen Code, um sicherzustellen, dass wir den Xgrößten Teil der Strategie durchlaufen, aber gelegentlich Yam Ende), ist, dass für die Spezifikation die endgültige Version der Karte ausgegeben werden muss. Die einfachste Möglichkeit, dies umzusetzen, besteht darin, die Karte vollständig unberührt zu lassen (abgesehen von unserem Weg durch anfangs leere Quadrate), zumal ein Quadrat, das mit 9Wasser begann, das Ergebnis sein würde10 , auf dem Weg (was die ASCII-Kunst bricht) und wir haben nur verwendetXUnd deshalb müssen wir eine Lösung finden, die vermeidet, dass zusätzliches Wasser auf die Karte fällt. Der Algorithmus hier würde "natürlich" 1 zusätzliche Wassereinheit auf jedes Feld auf der Route fallen lassen; Infolgedessen reduzieren wir die Menge an Wasser, die während des vorletzten Besuchs jedes Quadrats gefallen ist, um 1, indem wir Y anstelle von X verwenden, sodass wir das Quadrat bei unserem letzten Besuch wieder auf seine ursprüngliche Wassermenge anstatt auf die ursprüngliche Menge abtropfen lassen Es war etwas feuchter als zu Beginn.

Ich würde empfehlen, dies nicht auf einer großen Karte auszuführen, da es eine O (2 ^ n) -Leistung hat (obwohl der Bot niemals verdurstet, ist es plausibel zu glauben, dass er mit einer Strategie wie dieser an Hunger sterben würde).

Lesbare Version:

# implicit with -n: read a line of input into $_
push @a, [split //]; #/ split $_ into characters, store at the end of @a
($s,$t) = (length$`,$.) if /S/; # if we see S, store its coordinates
($e,$f) = (length$`,$.) if /E/  # if we see E, store its coordinates
}{ # Due to -n, loop back to start if there are more lines.

# From here onwards, $" stores the partial solution this iteration;
#                    $\ stores the partial solution last iteration;
#                    $_ stores the path from ($s,$t) to S.
# At the start of the program, $" is a space, $\ and $_ are empty.

$_ .=  # Work out the next step on the path:
  $s < $e ? ($s++,R) # if too far left, move right, record that in $_;
: $s > $e ? ($s--,L) # if too far right, move left, record that in $_;
: $t < $f ? ($t++,D) # if too far up,    move down, record that in $_;
: ($t--,U);          # in other cases we must be too far down.
$\ = reverse $";     # Store last iteration; $" is constructed backwards.
$" .=                # Extend $" by appending
  y/LRUD/RLDU/r .    # the path from ($s, $t) back to S;
  Y .                # a literal 'Y';
  reverse .          # $/ backwards (i.e. the path from S to ($s, $t);
  ($"=~y/Y/X/r);     # a copy of $" with all 'Y' changed to 'X'.
$a[$t-1][$s] =~      # At the current path coordinate,
  y/./#/;            # replace any '.' with '#'.
$\ .=                # Start appending to $\;
  $s-$e||$t-$f?redo  # if we're not at E, abort that and jump back to {{,
: $_;                # otherwise append $_ (the path from S to E).
print map            # For each element of some array
  {join'',@$_}       # output its concatenated elements
  @a                 # specifying that array as @a.
# Implicitly: print $\ (which specifies the sort of newline print uses).

quelle
Wäre eine Flut, die die Welt in einer Spirale füllt, weniger Code als Ihr Block von Bedingungen für die Richtung, um den Ausgang zu suchen?
Sparr
1
Ich denke nicht, dass es so wäre (obwohl es möglich ist, dass ich eine Möglichkeit nicht sehe; es ist sicherlich eine Idee, die es sich zu überlegen lohnt). Sie müssen sich noch mit vier Richtungen auseinandersetzen, und Sie müssen sich jetzt auch mit dem Rand der Karte auseinandersetzen, was in dieser Version des Algorithmus kein Problem darstellt.
Guter Punkt, wieder Kanten. Ich denke, es könnte auf einer unendlichen Karte gemacht werden.
Sparr