Office Escape: Planen Sie Ihren Ausweg!

32

Es ist der letzte Sprint ... und die Hälfte Ihres Teams ist krank. Sie arbeiten spät dran, machen gerade Ihr letztes Commit für den Tag und freuen sich auf ... warum haben Sie die Lichter ausgeschaltet? Ich erinnere mich nicht an den Sicherheitsmann, der vorbeikam ... oh nein! Ich habe meine Schlüssel zu Hause gelassen!

Als der Schrecken der Situation einsetzt, entscheiden Sie, dass Sie fliehen werden .

Aufgabenübersicht

Um deine Flucht zu bewirken, brauchst du einen Plan! Sie wissen jedoch, dass jeder Plan scheitern kann und dass unterschiedliche Pläne unterschiedliche Anstrengungen erfordern.

Da Sie hungrig, müde und ein Ingenieur sind, schreiben Sie ein kurzes Programm, um herauszufinden, wie Sie dem Komplex am besten entkommen können. Dabei müssen Sie die Erfolgsaussichten und den erforderlichen Aufwand in Einklang bringen.

Sie machen eine Karte des Gebäudes:

#######################
#                =    #
!                =    !    <-- window
#          !     =    #        (freedom!)
#################=    #
#    #           =    #
#    #           =    #
#    #           =    #
# o  !   # #  !  =    #
##|  !  ## #  !  =    #
#######################

  ^  ^           ^
  me my door     ludicrously high shelves
     (locked)    (climbable)

Um dem Büro zu entkommen, müssen Sie sich von der Karte entfernen. Hier sehen Sie 2 Fenster ( !), eines würde Sie in die Freiheit führen, aber nur eines davon ist zugänglich. Wir definieren "außerhalb der Karte", wenn Sie Ihre Füße außerhalb der Kartengrenzen haben

Zelltypen

  - empty, you can be here (i.e. the escapee can consume this cell)
# - solid (your desk, your in-tray), you can't be here, but you can stand on it
! - destructible, (co-worker's desk, door, window), you can't be here until you smash it first (turning it into an empty cell)
= - climbable, (fire ladder, filing cabinet, etc.), you can be here

Die Zellen, die ursprünglich vom Flüchtling verbraucht wurden, gelten als leer.

Aktionsspezifikationen

Sie haben eine Reihe von möglichen Aktionen zur Verfügung. Diese werden durch einfache Zustandsübergänge mit einer ganzzahligen Erfolgswahrscheinlichkeit definiert. Zum Beispiel bewegen Sie zum Gehen die Eskapee-Zelle um eine Zelle, die wir mit diesem Übergang darstellen:

Schritt

1 St., 100%, Spiegel

 o.            o
 |.   -->      |
 #            #

Die Punkte zeigen Zellen, die leer sein müssen (oder kletterbar, aber nicht fest oder zerstörbar sein dürfen), weil wir uns hinein oder hindurch bewegen. Die 100% bedeuten, dass Sie eine 100% ige Chance haben, sich nicht zu verletzen und Ihre gewagte Flucht zu beenden. Alle Wahrscheinlichkeiten sind ganzzahlige Prozentsätze zwischen 1% und einschließlich 100%. Das erste Diagramm zeigt den Ausgangszustand (auf etwas Festem stehend, neben einem leeren Raum stehend). Das zweite Diagramm zeigt den Terminalstatus (in den leeren Raum verschoben). Es ist nicht erforderlich, dass nicht spezifizierte Zellen (Leerzeichen ) auf der linken Seite (Ausgangszustand) etwas Besonderes sind. Nicht spezifizierte Zellen (Leerzeichen,) auf der rechten Seite (Endzustand) sollte derselbe sein wie zuvor (z. B. auf was auch immer sich hinter dem Flüchtling befand oder auf was auch immer ich gerade gehe (sei es ein leerer Raum oder etwas anderes) ) Diagramme ändern nur die Zellen von zerstörbar nach leer, es können keine weiteren Änderungen auftreten. "1 STP" bedeutet, dass es 1 STP kostet: Wir definieren den "STP" als die Energiemenge, die für einen Schritt erforderlich ist.

"Spiegel" bedeutet, dass diese Aktion zwei Formen hat. Die Aktion "rechts" wird angezeigt, die Aktion "links" ist ein exakter Spiegel, zum Beispiel:

.o
.|
 # 

ist die Spiegelform (links) von

o.
|.
# 

Die rechte Aktion heißt "Right" (zB "Step Right") Die linke Aktion heißt "Left" (zB "Step Left")

In diesen Diagrammen wird der Flüchtling durch gezeigt

o
|

im Stehen (2 Einheiten groß) und

%

beim Hocken (1 Einheit groß). Zellen, die fest oder zerstörbar sein müssen, werden durch einen Hash angezeigt #. Zellen, die nicht fest oder zerstörbar sein dürfen, sind durch einen Punkt gekennzeichnet .. Zellen, die zerstörbar sein müssen, werden durch einen Knall angezeigt !. Ein neu erzeugter Leerraum wird durch einen Unterstrich angezeigt _. xist ein Referenzpunkt, der sich nicht bewegt (es gibt ihn nicht, keine Einschränkung dafür, wie diese Zelle sein muss (wie ein Leerzeichen )).

Hinweis: Wir ignorieren das Problem der schnellen Verzögerung, wenn Sie auf den Boden fallen, und ja, in diesem Spiel können Sie absolut epische Sprünge auf Leitern machen.

Schritt

1 St., 100%, Spiegel

 o.         o
 |.  -->    |
x#        x#

Steigen Sie aus

1 St., 100%, Spiegel

 =         =
 o.  -->    o
 |.         |
x=        x= 

Mischen

3 stp, 100%, spiegel

 %.         %
x#   -->  x# 

Aufsteigen

10 Stp., 95%, Spiegel

 o.         %
 |#  -->    #
x#        x#

Fallen

0 stp, 100%

 o         
 |  -->   o
x.       x|

Drop (Stehen)

0 stp, 100%

 %        o
x.  -->  x|

Hochklettern

2 stp, 100%

 =        o
 o  -->   |
x|       x

Hocken

2 stp, 100%

 o
 |  -->   %
x#       x#

Stand

4 stp, 100%

 .        o
 %  -->   |
x#       x#

Kurzer Sprung

4 Stp., 95%, Spiegel

 o..          o
 |..  -->     |
x#         x#

Weitsprung

7 Stp., 75%, Spiegel

 o...           o
 |...  -->      |
x#          x#

Hochsprung

12 stp, 90%, Spiegel

 ..         o
 o.  -->    |
 |          
x#        x# 

Setzen Sie Ihren Rücken hinein!

20 Stp., 80%, Spiegel

 o!.         _o
 |!.  -->    _|
x#         x#

Schlagen

8 stp, 90%, Spiegel

 o!        o_
 |   -->   |
x#        x#

Kick

8 Stp., 85%, Spiegel

 o         o
 |!  -->   |_
x#        x#

Briefmarke

8 stp, 90%

 o        o
 |  -->   |
x!       x_

Pläne

Ein Plan ist eine Folge der oben definierten Aktionen. Beispielsweise:

Step Left
High Jump Left
Crouch
Shuffle Left
Shuffle Left
Stand
Long Jump Left
Put your back into it! Left
Step Left

Beachten Sie die Einbeziehung der Tropfen. Die Regeln sollten so festgelegt werden, dass Sie nichts anderes tun als fallen zu lassen, aber Sie müssen immer noch planen!

Für jeden Plan ist ein Aufwand erforderlich. Dies ist die Summe des Aufwands für jeden Schritt. Es gibt auch eine Erfolgswahrscheinlichkeit, die sich aus den Erfolgswahrscheinlichkeiten jeder Aktion ergibt. Einfaches Beispiel:

Step Right:          1stp,  100%
Long Jump Right:     7stp,  75%
Step Right:          1stp,  100%
Stamp:               8stp,  90%
Drop:                0stp,  100%
Drop:                0stp,  100%
Drop:                0stp,  100%
Drop:                0stp,  100%
Step Left:           1stp,  100%
Step Left:           1stp,  100%
High Jump Left:      12stp, 90%

Effort = 1+7+1+8+1+1+12 = 31
Success Probability = 75%*90*90% = 60.75%

Ein "bearbeitetes Beispiel" für die Karte oben auf der Seite kann als Zusammenfassung angesehen werden .

Eingang

Die Eingabe besteht aus zwei Teilen, einer Ganzzahl und einem Array oder einer Zeichenfolge.

Die Ganzzahl ist Ihre minimale akzeptable (prozentuale) Erfolgswahrscheinlichkeit. Es ist als Prozentsatz zu interpretieren, also bedeutet 80, dass Ihr Plan mit einer Wahrscheinlichkeit von mindestens 80% erfolgreich sein muss.

Eine gültige Karte ist ein Rechteck, das den stehenden Eskapee (Mindestgröße 1x2) und keine nicht angegebenen Symbole enthält. Alle Zeilen sind gleich lang. Sie können Eingaben als eindimensionale, durch Trennzeichen getrennte Zeichenfolge (Trennzeichen muss ein einzelnes konsistentes Zeichen oder eines aus CRLF- und LFCR-Paaren sein) als ein ähnliches eindimensionales oder zweidimensionales Array akzeptieren. Wenn Ihr ausgewähltes Eingabeformat die Breite oder Höhe der Karte nicht in irgendeiner Weise angibt, können Sie zusätzliche Argumente dafür akzeptieren (dies müssen Sie in Ihrer Antwort klar angeben). Sie können Befehlszeilenargumente und Standardeingaben mischen, wenn dies für Sie geeignet ist (z. B. Karte von stdin, minimale Erfolgswahrscheinlichkeit von argv). Das Folgende sind gültige und ungültige Beispielkarten.

Gültig:

o
|

Gültig:

  #     #
  !   o #
  !   | #
#########

Ungültig (kein Flüchtling):

  #     #
  !     #
  !     #
#########

Ungültig (Escape beginnt immer zu stehen):

  #     #
  !     #
  !   % #
#########

Ungültig (ungültiges Symbol):

  #     #
  !  ~  #
  !     #
#########

Ungültig (kein Rechteck / Zeilen mit unterschiedlicher Länge):

  #     #
  !   o #
  !   | # 
#########

Sie können davon ausgehen, dass Ihre Eingabe gültig ist (es ist mir egal, was Ihr Programm tut, wenn es ungültige Eingaben erhält).

Ausgabe

Die Ausgabe erfolgt in Textform (ASCII). Kann als Zeichenfolge zurückgegeben oder auf die Standardausgabe gedruckt werden. Der Plan muss durch einen LF, CRLF oder LFCR abgegrenzt werden. Ebenso muss nach dem erforderlichen Aufwand ein weiterer LF, CRLF oder LFCR vorhanden sein. Ein nachfolgender Zeilenumbruch ist optional.

Sie müssen einen optimalen Plan zusammen mit dem erforderlichen Aufwand ausgeben oder "Es gibt keine Hoffnung!" wenn kein solcher Plan existiert. Sie müssen die Erfolgswahrscheinlichkeit nicht ausgeben. Dieser Text kann einen nachgestellten Zeilenumbruch enthalten oder nicht.

Ein optimaler Plan ist definiert als ein Plan (siehe oben), der den geringsten Aufwand mit mindestens der gegebenen Erfolgswahrscheinlichkeit erfordert. Beachten Sie, dass Ihre Wahrscheinlichkeitsberechnungen genau sein müssen. Sie können davon ausgehen, dass Fließkommazahlen nicht gut genug sind (daher erwarte ich nicht, dass Sie sie ausgeben). Ich werde versuchen, Testfälle zu entwerfen, um dies fair zu testen (wenn Sie sie bestehen und keine dummen Annahmen treffen, halten Sie Ihre Einreichung möglicherweise für gültig).

Format:

Required Effort: <effort>
<plan>

Zum Beispiel für die Eingabe

50
  #     #
  !   o #
  !   | #
#########

Eine angemessene Ausgabe wäre:

Required Effort: 23
Step Left
Step Left
Step Left
Kick Left
Punch Left
Step Left
Step Left
Step Left
Step Left

Die Erfolgswahrscheinlichkeit liegt hier bei 76,5%.

Für die gleiche Karte, jedoch mit einer minimalen Erfolgswahrscheinlichkeit von 80%, müssten Sie "Ihren Rücken hineinlegen", was mehr Aufwand erfordert, aber die Erfolgswahrscheinlichkeitskriterien erfüllt. Wenn die minimale Erfolgswahrscheinlichkeit größer als 80% wäre, müssten Sie etwas härter nachdenken (entweder durch einen Teil der Tür schlagen oder treten und hinausschlurfen). Wenn die minimale Erfolgswahrscheinlichkeit 100% wäre, müssten Sie ausdrucken "Es gibt keine Hoffnung!"

Beispiele

Es ist möglich, dass es mehr als einen gültigen Plan für eine Eingabe gibt. Ihre Ausgabe muss nicht genau diesen entsprechen, aber den richtigen erforderlichen Aufwand haben und einen gültigen Plan haben. Sie können den Prüfer verwenden, um Ihre Lösungen zu überprüfen (siehe unten).

Eingang:

100
o
|

Ausgabe:

Required Effort: 0
Drop

Eingang:

5
# =      #
# =      !
# = !  ! !
# =#######
# =      #
# =   o  #
# = ! |  #
##########

Ausgabe:

Required Effort: 57
Step Left
Kick Left
Step Left
Step Left
Step Left
Climb Up
Climb Up
Climb Up
Climb Up
Climb off Right
High Jump Right
Long Jump Right
Step Right
Drop
Kick Right
Crouch
Shuffle Right
Shuffle Right

Eingang:

60
#########
# ! #   #
! ! ! o #
! # ! | #
#########

Ausgabe:

Required Effort: 58
Step Left
Kick Left
Crouch
Shuffle Left
Shuffle Left
Stand
Punch Left
Clamber Up Left
Shuffle Left
Drop (Stand)
Kick Left
Crouch
Shuffle Left
Shuffle Left

Für dieselbe Karte, jedoch zu 80%, sollte die Ausgabe wie folgt lauten:

There is no hope!

Für dieselbe Karte, jedoch zu 50%, wird der erforderliche Aufwand mit einem anderen Plan zu 56.

Eingang:

50
#######################
#          #     =    #
!          #     =    !
#          #     =    #
######  #####!## =### #
#=   ##       #  =    #
#=#############  =    #
#=               =    #
#= o             =    #
#!!|             =    #
#######################

Ausgabe:

Required Effort: 121
Step Right
Step Right
Step Right
Step Right
Step Right
Step Right
Step Right
Step Right
Step Right
Step Right
Step Right
Step Right
Step Right
Step Right
Climb Up
Climb Up
Climb Up
Climb Up
Climb Up
Climb Up
Climb off Right
Long Jump Left
Step Left
Step Left
Stamp
Drop
Drop
Crouch
Shuffle Left
Shuffle Left
Shuffle Left
Shuffle Left
Shuffle Left
Shuffle Left
Stand
Clamber Up Left
Stand
Clamber Up Left
Stand
Step Left
Step Left
Step Left
Step Left
Punch Left
Clamber Up Left
Shuffle Left

Eingang:

66
######
#  ###
#o ! !
#| ! !
### ##
######

Ausgabe:

Required Effort: 37
Step Right
Put your back into it! Right
Kick Right
Crouch
Shuffle Right
Shuffle Right

Eingang:

Dieser soll eine Reihe falscher Annahmen überprüfen, denen man zum Opfer fallen und die folglich etwas seltsam aussehen können

30
###################
# ## # # #   #  = #
! ## #   #   #  = #
#      #   #    = #
##  ############= #
# ## #         #= #
# =  #         #= #
! =  #         #= #
# =  #         #= #
#o=  !          ==#
#|=  !           =#
#!= # ==########==#
#   #    !   !!  =#
#   #    !!  !  = #
#   # !!!!#########
#   # #           #
#   # #           #
###################

Ausgabe mit Erfolgschance Einschränkung 30:

Required Effort: 199
Long Jump Right
Put your back into it! Right
<snip>

Ausgabe mit Erfolgschance-Einschränkung 32:

Required Effort: 200
Long Jump Right
Punch Right
<snip>

Wenn Sie die Karte oben als Eingabe verwenden, sollten Sie mit einer Erfolgswahrscheinlichkeit von 1% einen erforderlichen Aufwand von 116 erzielen (Erfolgschance ~ 32%, die Ausführung in meinem Testprogramm dauerte ca. 20 Sekunden).

Siegkriterien

Dies ist Code-Golf, möge der kürzeste Code gewinnen.

Um berechtigt zu sein, muss Ihre Funktion oder Ihr Programm funktionieren und in der Lage sein, jeden der oben genannten Testfälle in weniger als 30 Minuten auf einem vernünftigen Computer zu lösen. Mein Löser erledigt sie jeweils in weniger als 30 Sekunden. Wenn das Testskript (unten) in weniger als 30 Minuten ausgeführt wird, können Sie mit Sicherheit loslegen.

Beispiel Solver, Verifier, Test Script und TestCases (mit Lösungen)

C # -Code für einen Solver und Lösungsüberprüfer ist hier als Zusammenfassung verfügbar . Der Inhalt enthält auch file.txteine maschinenlesbare (ausreichend) Form der oben beschriebenen Aktionen, die für die Ausführung des Programms erforderlich ist. Jegliche Diskrepanz zwischen dieser Datei und der Spezifikation ist nicht beabsichtigt.

Die Übersicht enthält auch eine Reihe von Testfällen (einschließlich aller obigen Beispiele) und ein PowerShell-Skript, mit dem automatisch eine Übermittlung für diese durchgeführt wird. Wenn das Skript anzeigt, dass ein bestimmter Test fehlgeschlagen ist, können Sie OfficeEscapeSolver.exe testcase<n>.txt outputFromYourProgram.txtweitere Details anzeigen. Beispiellösungen für diese Testfälle finden Sie in einem anderen Gist .

Der gesamte Code ist ein komplettes Durcheinander (wenn auch ungolfed), aber Sie sollten sich nicht weit von dem entfernen müssen, static void Main(...)um die Ausgabemenge zu ändern (Sie können diese Informationen gerne verwenden, ich habe sie zu Ihrem Vorteil bereitgestellt!).

Das Bestehen eines Testfalls bedeutet nicht unbedingt, dass Ihre Ausgabe gut strukturiert ist, da das Skript und der Prüfer sehr großzügig sind. Ihre Ausgabe muss mit der obigen Spezifikation übereinstimmen, damit Ihre Einreichung gültig ist.

Wenn Sie der Meinung sind, dass Sie einen Fehler mit dem Löser oder dem Testskript, einen Fehler in file.txtoder einen zweifelhaften Testfall gefunden haben, kommentieren Sie diesen Beitrag bitte, oder senden Sie mir auf andere Weise einen Ping-Befehl im SE-Chat. Ich werde wahrscheinlich keinen anderen Kommunikationsversuch bemerken.

Ich werde das Testskript nicht in Bash oder Batch bereitstellen, weil ich sie nicht kenne, aber ich bin froh, eine Übersetzung beizufügen und werde eine C # -Version schreiben, wenn die Leute eine wollen.

Post Amble

Haben sie Fragen? Zögern Sie nicht, fragen Sie sie noch heute!

Diese Aufgabe erfordert Anstrengung , um ernsthaften Golfern etwas zu bieten, in das sie sich hineinversetzen können.

Mein Dank geht an ais523 für sein Feedback zu Input / Output.

Ich kann mehr Testfälle in der GIST-Datei bereitstellen, wenn die Leute mehr wollen (dieser Beitrag soll nicht länger werden) oder einige von ihnen bereitstellen möchten.

VisualMelon
quelle
2
Große Herausforderung! Ich werde es auf jeden Fall versuchen, wenn ich Zeit habe. :)
R. Kap
Sie wissen, die Sturzgefahren (oder besser gesagt die rasche Verzögerung am Boden) könnten modelliert werden, indem der Sturzübergang mit einer Wahrscheinlichkeit von etwa 95% angegeben wird. ;) Schöne Herausforderung!
Martin Ender
Kannst du durch ein Himmelslicht oder Tunnel entkommen? dh oben und oder unten im Feld? oder nur links oder rechts?
Moogie
@ Moogie kannst du ja! Solange Ihre Füße frei sind, sind Sie frei (siehe zum Beispiel den 1x2-Testfall, in dem die Lösung nur einmal getropft wird). Ich werde einen kleinen Testkoffer hinzufügen, um zu testen, wie es von der Decke geht.
VisualMelon
3
Kopfgeld zur Frage hinzugefügt. Dies ist eine großartige Frage, die Antworten verdient.
programmer5000

Antworten:

3

Perl 5, 1425, 1464, 1481, 1469, 1485, 1438 Bytes

Das war eine lustige Herausforderung! Und es sieht schockierend aus, als hätte ich den kürzesten Code mit etwas weniger als 1,5 kB! :)

Ich bin mir ziemlich sicher, dass es endlich funktioniert. Das verwendete Trennzeichen ist :und es gibt einen zusätzlichen Abstand von zwei Zeilen oben und einer Spalte auf jeder Seite . Also für Ihre Eingabe von:

60
#########
# ! #   #
! ! ! o #
! # ! | #
#########

Mein Programm würde dauern: (Hinweis: Am Ende muss ein Doppelpunkt stehen, am Anfang jedoch nicht!)

60
#########:# ! #   #:! ! ! o #:! # ! | #:#########:

Ich verwende reguläre Ausdrücke, um von einer Karte in eine andere zu übersetzen und mit roher Gewalt zu lösen. Ich füge der Liste jedoch keine Karten hinzu, wenn diese Karte bereits mit weniger Aufwand und größerer oder gleicher Wahrscheinlichkeit erreicht wurde. Karten werden aus der Liste entfernt, sobald alle möglichen Bewegungen von diesem Punkt erschöpft sind. Das Programm wird erfolgreich beendet, wenn es mit einem regulären Ausdruck übereinstimmt, der anzeigt, dass ich die Seite oder den Boden erreicht habe, und mit "Es gibt keine Hoffnung!" Endet. wenn die Liste der Karten erschöpft ist.

Leider wurde sehr viel Effizienz abgehandelt, um ein paar Bytes zu entfernen, so dass die Golf-Version ziemlich langsam ist;) Perl scheint besonders die Bewertungen als ziemlich schmerzhaft zu empfinden.

Ohne weiteres

chop($P=<>,$_=<>);s/:/ : /g;$w++until/:.{$w}:/;$z=$"x$w;$_="(.{".$w--."})"for($c,$h,$i,$j);$_="$z:$z: $_$z";$n="[ =]";$d="([!#])";@s=split/,/,'Drop,Drop (Stand),Stepx,Climb offx,Shufflex,Clamber Upx,Put your back into it!x,Punchx,Kickx,Short Jumpx,Long Jumpx,High Jumpx,Crouch,Stand,Climb Up,Stamp';@c=split/,/,"o$c\\|$c$n/ \$1o\$2|,%$c$n/o\$1|,o$n$h\\|$n$h${d}/ o\$1 |\$2\$3,=${c}o$n$h\\|$n$h=/=\$1=o\$2=|\$3=,%$n$h$d/ %\$1\$2,o$n$h\\|${d}$h${d}/ %".'$1 $2$3$4,'."o!$n$i\\|!$n$i${d}/  o\$1  |\$2\$3,o!$h\\|$c$d/o \$1|\$2\$3,\\|!$h$d/| \$1\$2,o$n$n$i\\|$n$n$i${d}/  o\$1  |\$2\$3,o$n$n$n$j\\|$n$n$n$j${d}/   o\$1   |\$2\$3,$n$n${h}o$n$h\\|$c$d/ o".'$1 |$2 $3$4,'."o$c\\|$c${d}/ \$1%\$2\$3,$n$c%$c${d}/o\$1|\$2\$3,=${c}o$c\\|/o\$1|\$2=,\\|$c!/|\$1 ";eval"*$_=sub{\$Q=\"$s[$_]\";s/$c[$_]/}"for(0..15);sub M{$_=join":",map{join'',reverse split//}split/:/};push@M,[$_,0,100,$P];$B{$_}=100;@E=(0,0,1,1,3,10,20,8,8,4,7,12,2,4,2,8);@P=map{100-$_}(0,0,0,0,0,5,20,10,15,5,25,10,0,0,0,10);$z='$N=[$_,$G+0,$t,$t[3]*100,"$t[4]$Q\n"];$N->[4]=~s/x/';do{sub A{@N=@$N;if($N[2]/$N[3]>$B{$N[0]}){push@M,$N;$B{$N[0]}=$N[2]/$N[3]}};die"There is no hope!\n"if(!(@M=grep$G-$_->[1]<21,@M));$e=-1;while(++$e<@M){@t=@{$M[$e]};$m=$_=$t[0];die"Required Effort: $t[1]\n$t[4]"if(/([|%]:|:[|%])/||/[|%][^:]*$/||/^$c:[^:]*[%|]/);for$x(0..15){$_=$m;$t=$t[2]*$P[$x];if($G==$E[$x]+$t[1]and$t>=$t[3]*100){&$x;eval"$z Right/";A;$_=$m;M;&$x;M;eval"$z Left/";A;}}}}

Aus Gründen der Vernunft ist hier das Gleiche mit Zeilenumbrüchen und ein paar Kommentaren:

chop($P=<>,$_=<>); #Take input
s/:/ : /g; #Pad columns on either side so escapee can leave that way
$w++until/:.{$w}:/; #Find width
$z=$"x$w;#Setup a blank line for use in padding later
$_="(.{".$w--."})"for($c,$h,$i,$j); #Set up some generic capturing regexes for reuse
$_="$z:$z: $_$z"; #Pad the top and bottom so the escapee can leave those ways
$n="[ =]"; #Regex for nonsolid block
$d="([!#])"; #Regex for solid block
@s=split/,/,'Drop,Drop (Stand),Stepx,Climb offx,Shufflex,Clamber Upx,Put your back into it!x,Punchx,Kickx,Short Jumpx,Long Jumpx,High Jumpx,Crouch,Stand,Climb Up,Stamp'; #Movement names
@c=split/,/,"o$c\\|$c$n/ \$1o\$2|,%$c$n/o\$1|,o$n$h\\|$n$h${d}/ o\$1 |\$2\$3,=${c}o$n$h\\|$n$h=/=\$1=o\$2=|\$3=,%$n$h$d/ %\$1\$2,o$n$h\\|${d}$h${d}/ %".'$1 $2$3$4,'."o!$n$i\\|!$n$i${d}/  o\$1  |\$2\$3,o!$h\\|$c$d/o \$1|\$2\$3,\\|!$h$d/| \$1\$2,o$n$n$i\\|$n$n$i${d}/  o\$1  |\$2\$3,o$n$n$n$j\\|$n$n$n$j${d}/   o\$1   |\$2\$3,$n$n${h}o$n$h\\|$c$d/ o".'$1 |$2 $3$4,'."o$c\\|$c${d}/ \$1%\$2\$3,$n$c%$c${d}/o\$1|\$2\$3,=${c}o$c\\|/o\$1|\$2=,\\|$c!/|\$1 ";#Movement regexes
eval"*$_=sub{\$Q=\"$s[$_]\";s/$c[$_]/}"for(0..15); #Setup methods to apply regexes. Name of these methods are 0,1,2,3, etc, so we can easily call them in a loop
sub M{$_=join":",map{join'',reverse split//}split/:/}; #Method to mirror the map. All the regexes are right-moving, so the mirror effects are achieved by M;&$x;M
push@M,[$_,0,100,$P]; #Array for initial map position. Encodes: [Map,Effort value,Probability value 1,Probability value 2,Movements(initially undef)]. Two integers are used for the probability to avoid floating point (although after enough steps they overflow and are automatically converted to f.p.)
$B{$_}=100; #Hash map to hold best probability of reaching a map. A new map is never added if it requires at least as much effort and doesn't give a better probability.
@E=(0,0,1,1,3,10,20,8,8,4,7,12,2,4,2,8); #Effort values
@P=map{100-$_}(0,0,0,0,0,5,20,10,15,5,25,10,0,0,0,10); #Probability values
$z='$N=[$_,$G+0,$t,$t[3]*100,"$t[4]$Q\n"];$N->[4]=~s/x/'; #Setup map values
do{ #Loop over all efforts. Do-while loop starts at undef, which is converted to zero automatically when used in a numeric context
    sub A{@N=@$N;if($N[2]/$N[3]>$B{$N[0]}){push@M,$N;$B{$N[0]}=$N[2]/$N[3]}}; #Method to add a map to list.
    die"There is no hope!\n"if(!(@M=grep$G-$_->[1]<21,@M)); #Pares away maps that no longer can produce new maps, and prints "There is no hope!" to stderr if there are no maps left.
    $e=-1;
    while(++$e<@M){ #Loop over all maps. Note that this loops over even maps that are created during the loop
        @t=@{$M[$e]}; #Dereference info about each map
        $m=$_=$t[0]; $Setup map variables
        die"Required Effort: $t[1]\n$t[4]"if(/([|%]:|:[|%])/||/[|%][^:]*$/||/^$c:[^:]*[%|]/); #Checks if escaped, and gives message if so.
        for$x(0..15){
            $_=$m; #Put map into $_
            $t=$t[2]*$P[$x]; #Probability calculation
            if($G==$E[$x]+$t[1]and$t>=$t[3]*100){ #If effort values are right and probability is over threshold
                &$x; #Run regex
                eval"$z Right/"; #Set up map info
                A; #Add map to list @M (only if probability works out right)
                $_=$m;
                M;&$x;M; #Same thing, but mirrored now (generates movement left)
                eval"$z Left/";
                A;
            }
        }
    }
}while(++$G)

Ich kann bereits einige Stellen sehen, an denen ich noch ein paar Bytes wegschneiden kann, aber ich möchte noch nicht alle Tests wiederholen. Später! :)

Bearbeiten: Es wurden einige Auffüllungen hinzugefügt, um die Ausgabe beim Durchlaufen des Bodens genauer anzupassen. Einige der Auswertungen wurden entfernt, sodass der Code jetzt möglicherweise auch schneller ausgeführt wird!

Bearbeiten: Wurde nicht richtig mit Leitern und Stürzen umgegangen. Kommt mit Leitern immer noch nicht zurecht ... Ich versuche das jetzt zu beheben.

Chris
quelle
Froh, dass jemand anderes Spaß damit hat! Ich befürchte, dass ich dies nicht so akzeptieren kann, wie es derzeit ist, da Sie nicht davon ausgehen können, dass die Eingabe mit diesen zusätzlichen Zeilen oder Abständen oben ist (aber bei ~ 1,5 kB sollte das sofortige Einfügen nicht schaden zu viel!). Ich habe Perl nicht auf diesem Computer, aber ich werde versuchen, einen Weg zu finden, dies heute zu testen, damit ich überprüfen kann, ob es funktioniert und in einem vernünftigen Zeitrahmen abläuft, und einen Bericht erstatten kann!
VisualMelon
1
@VisualMelon Kein Problem, ich habe die Eingabemethode geändert und das Auffüllen manuell vorgenommen. Es neigt dazu, bei größeren Rätseln in die Luft zu jagen, läuft jedoch für die meisten Ihrer Testfälle in einem angemessenen Zeitrahmen.
Chris
Dies wurde noch nicht getestet, aber ich stelle fest, dass dies einen regulären Ausdruck verwendet, um zu erkennen, wann Sie von der Seite oder von unten abheben. Sie können jedoch auch von oben abheben (siehe Testfall 10, der zu diesem Zweck hinzugefügt wurde), falls Sie es verpasst haben this
VisualMelon
1
@VisualMelon Ah, ich bin davon ausgegangen, dass der Flüchtling, um vom Dach zu entkommen, auf den Raum steigen und dann vom Dach zur Seite gehen muss. Ich sehe jetzt den entsprechenden Satz. Ich werde es reparieren :)
Chris
2
Könnten Sie einen TIO-Link hinzufügen?
programmer5000
3

C #, 1814 1481 1395 Bytes

Was für ein Mist !! Ich bin jetzt wirklich ziemlich zufrieden damit!

using C=System.Console;using System.Linq;class S{string M,N="";int x,y,E,c;decimal P=1;static void Main(){int W=0,H=0,x,i,j,k,X,Y,f,m,P=int.Parse(C.ReadLine());string l,M="",B,R="There is no hope!";for(;(l=C.ReadLine())!=null;H++,M+=l)W=l.Length;x=M.IndexOf("|");var D=new[]{new S{M=M,x=x%W,y=x/W}}.ToList();for(var N=D.ToDictionary(s=>R,s=>D);D.Count>0;D.Sort((z,w)=>z.E-w.E)){S s=D[f=0];D.Remove(s);var n=N[l=s.x+s.M+s.y+s.c]=N.ContainsKey(l)?N[l]:new S[0].ToList();if(n.All(o=>o.P<s.P|o.E>s.E)){n.Add(s);X=s.x;Y=s.y;if((X|Y|-X/W-Y/H)<0){R="Required Effort: "+s.E+s.N;break;}for(var A="0110d,Step,*** * #*,0110d,Climb off,=** * =*,3310d,Shuffle,***** #*,2:1/_,Clamber Up,*** *##*,0420_,Short Jump,****  *  #**,0730K,Long Jump,*****   *   #***,0<1/Z,High Jump,  * **#*,0D20P,Put your back into it!,****! *! #**,0800Z,Punch,***!**#*,0800U,Kick,*****!#*,0001d,Drop,*** ,1001d,Drop (Stand),*** ,2200d,Crouch,***#,1400d,Stand,* *#,020/d,Climb Up,=***,0800Z,Stamp,***!".Split(',');f<26;){l=A[k=f*3%48];B=A[++k]+(f>15?" Right":f>9?"":" Left");M=A[++k];m=f++/16*2-1;var Q=s.M.ToArray();var K=s.P*l[4]>=P&s.c==l[k=0]%2;for(j=Y-3;j++<=Y;)for(i=X;i!=X+m*M.Length/4;i+=m)if((K&="==  *!!##*!*=*|*| o*o ".Contains(""+((i|j)>=0&j<H&i<W?Q[x=j*W+i]:' ')+M[k]))&M[k++]==33)Q[x]=' ';if(K)D.Add(new S{M=new string(Q),N=s.N+"\n"+B,x=X+l[2]%48*m,y=Y+l[3]-48,c=l[0]/50,E=s.E+l[1]-48,P=s.P*l[4]/100});}}}C.Write(R);}}

Probieren Sie es online

Komplettes Programm, Eingabe in STDIN, Ausgabe in STDOUT. Im Wesentlichen ein Umschreiben meines ursprünglichen Lösers unter Verwendung eines einfachen und ineffizient implementierten BFS, um den optimalen Pfad zu finden. Es ist einigermaßen schnell, kann nicht viel langsamer sein als meine andere Implementierung (ich habe es allerdings nicht wirklich zeitlich festgelegt) und läuft mit Sicherheit innerhalb des Zeitlimits. Ein Großteil der Kosten entfällt auf die Aktionstabelle, die als durch Kommas getrennte Werte codiert ist, in denen der Name, die Zuordnungszuordnung (Match / Smash) und andere Eigenschaften jeder verfügbaren Aktion aufgezeichnet sind.

Es beginnt mit dem Einlesen der minimalen Erfolgswahrscheinlichkeit und der Karte. Dann findet es den Flüchtling, entfernt ihn von der Karte und erstellt einen Suchstatus, der diese Informationen enthält. Anschließend wird das BFS ausgeführt, das wiederholt mit dem geringsten Aufwand den nächsten fälligen Status überprüft (um sicherzustellen, dass eine optimale Lösung gefunden wird). Vor dem Erweitern des Knotens werden Aufwand und Erfolgswahrscheinlichkeit mit früheren Knoten mit derselben Karte und demselben Fluchtort verglichen und es wird abgelehnt, wenn bereits eine bessere Route zu diesem Status gefunden wurde. Wenn es dies überlebt, fügt es sich der Tabelle 'seen' hinzu, damit es den Status später ablehnen kann. Das ist alles für die Leistung, und ohne sie wäre der Verzweigungsfaktor enorm. Dann wird geprüft, ob der Flüchtling von der Karte entfernt ist. Wenn es so ist, dann gewinnt es! Es verfolgt den Status zurück (jeder vorherige Status wird mit jedem Status aufgezeichnet) und erstellt den Plan (in umgekehrter Reihenfolge), bevor die BFS-Schleife verlassen wird. Andernfalls wird versucht, jede Aktion anzuwenden, und es werden alle Aktionen hinzugefügt, die auf die angewendet werden könnendue Warteschlange, bevor diese Warteschlange sortiert wird, damit wir den Status mit dem geringsten Aufwand bei der nächsten Iteration erhalten.

Formatierter und kommentierter Code:

using C=System.Console;
using System.Linq;

// ascii
//   32
// ! 33
// = 61
// . 46
// * 42
// # 35
// | 124
// 0 48

class S // SearchState
{
    string M, // map
        N=""; // plan
    int x, // pos x
        y, // pos y
        E, // effort
        c; // crouching?
    decimal P=1; // chance (Probability)

    static void Main()
    {
        int W=0, // map width
            H=0, // map height
            x, // various temps
            i, // local x
            j, // local y
            k, // position in match/smash map
            X, // s.x
            Y, // s.y

            // action loop
            f, // T idx
            m, // A idx, action mirror (direction)

            P=int.Parse(C.ReadLine()); // probability of success constraint

        string l, // line, Act 'block' params, map hash, match pairs; all sorts!
            M="", // initial map
            B, // name of action
            R="There is no hope!"; // result string

        // read map
        for(;(l=C.ReadLine())!=null; // while there is input to read
            H++,M+=l) // increment height, and append to M
            W=l.Length; // record width

        // detect the escapee
        x=M.IndexOf("|");

        // create first state, and add it to Due list
        var D=new[]{new S{M=M,x=x%W,y=x/W}}.ToList();

        // 'seen' table, stores all the states we've been in which looked similar
        for(var N=D.ToDictionary(s=>R,s=>D); // these values are meaningless (and necessarily can't interfere), we just use it to save having to spec the type
            D.Count>0; // keep going until we run out of states to expand (-> no escape)
            D.Sort((z,w)=>z.E-w.E)) // enforce Breadth First Search
        {
            // get next State to expand, and remove it from Due
            S s=D[f=0];
            D.Remove(s);

            // retrieve or create seen list
            var n=N[l=s.x+s.M+s.y+s.c]= // store it, and cache it, l is 'hash', containing map and escapee state
                N.ContainsKey(l)? // already got a seen list for ths map?
                N[l]: // then use it!
                new S[0].ToList(); // otherwise create a new (empty) one

            // perf: only proceed if we havn't seen this map with better Effort and Chance yet
            if(n.All(o=>o.P<s.P|o.E>s.E))
            {
                // record that we have been seen
                n.Add(s);
                X=s.x;
                Y=s.y;

                if((X|Y|-X/W-Y/H)<0) // check if we our outside the bounds - this took 2.5hour to write. 1 byte.
                { // quit if both are positive or both are negative
                    // freedom
                    R="Required Effort: "+s.E+s.N;

                    // finished
                    break;
                }

                // [Crouch,Effort,dx,dy,Probability],Name,MatchSmash (first 10 are mirrors)
                // 0110d,Step,*** * #*,
                // 0110d,Climb off,=** * =*,
                // 3310d,Shuffle,***** #*,
                // 2:1/_,Clamber Up,*** *##*,
                // 0420_,Short Jump,****  *  #**,
                // 0730K,Long Jump,*****   *   #***,
                // 0<1/Z,High Jump,  * **#*,
                // 0D20P,Put your back into it!,****! *! #**,
                // 0800Z,Punch,***!**#*,
                // 0800U,Kick,*****!#*,
                // 0001d,Drop,*** ,
                // 1001d,Drop (Stand),*** ,
                // 2200d,Crouch,***#,
                // 1400d,Stand,* *#,
                // 020/d,Climb Up,=***,
                // 0800Z,Stamp,***!

                // attempt to expand this node with every action
                for(var A="0110d,Step,*** * #*,0110d,Climb off,=** * =*,3310d,Shuffle,***** #*,2:1/_,Clamber Up,*** *##*,0420_,Short Jump,****  *  #**,0730K,Long Jump,*****   *   #***,0<1/Z,High Jump,  * **#*,0D20P,Put your back into it!,****! *! #**,0800Z,Punch,***!**#*,0800U,Kick,*****!#*,0001d,Drop,*** ,1001d,Drop (Stand),*** ,2200d,Crouch,***#,1400d,Stand,* *#,020/d,Climb Up,=***,0800Z,Stamp,***!".Split(','); // Act string
                    f<26;) // read A into T // (cycle over first 10 twice, making them mirrors)  (very convieniently, 3*16==48=='0'==x!)
                {
                    // 'parse' next action
                    l=A[k=f*3%48]; // [Effort,Crouch,dx,dy,Probability]
                    B=A[++k]+(f>15?" Right":f>9?"":" Left"); // action name
                    M=A[++k]; // Match and Smash table (4x?, escapee at 0,2, #: solid, !: smashable (and is smashed), .: empty,  : don't care, =: climable)
                    //c=l[1]-48; // crouching transition (0: standing -> standing, 1: crouching -> standing, 2: standing -> crouching, 3: crouching -> crouching)
                    m=f++/16*2-1;

                    // this will be the new map
                    var Q=s.M.ToArray();

                    // K is whether we are allowed to apply this action
                    var K=s.P*l[4]>=P& // within chance limit
                        s.c==l[k=0]%2; // crouching matches

                    // compare the map to the Match/Smash map, to make sure we can apply this transform (and smash any ! we meet)
                    for(j=Y-3;j++<=Y;) // for the 4 rows
                        for(i=X;i!=X+m*M.Length/4;i+=m) // for each column (a.M has height 4, but variable width)
                            if((K&= // K still true?
                                "==  *!!##*!*=*|*| o*o ".Contains(""+ // check for an allowed pairing (cache pairing in M) (this includes the escapee, much cheaper to do this than remove him)
                                    ((i|j)>=0&j<H&i<W?Q[x=j*W+i]:' ') // we are within bounds and match, we are out of bounds (empty)
                                    +M[k])) // char from MatchSmash map
                                &M[k++]==33) // if it is destructible ('!' == 33)
                                Q[x]=' '; // then blank it out (x is necessarily set by the cell check)

                    if(K) // if K holds
                        D.Add(new S{M=new string(Q),N=s.N+"\n"+B, // assemble plan as we go (this will chew up memory, but none of the problems are big enough for it to matter)
                            x=X+l[2]%48*m,y=Y+l[3]-48,c=l[0]/50,E=s.E+l[1]-48,P=s.P*l[4]/100}); // add the resulting state to Due
                }
            }
        }

        C.Write(R);
    }
}
VisualMelon
quelle
Gute Arbeit! Es amüsiert mich unendlich, dass Ihre alte Punktzahl und neue Punktzahl Anagramme voneinander sind ... lol
HyperNeutrino
Hat C # Perl geschlagen?
Esolanging Fruit