Office Escape: pianifica la tua via d'uscita!


32

È lo sprint finale ... e metà della tua squadra è ammalata. Lavori fino a tardi, ti impegni per l'ultima giornata, non vedo l'ora ... perché le luci sono spente? Non ricordo il ragazzo della sicurezza che viene in giro ... oh no! Ho lasciato le chiavi a casa!

Mentre l'orrore della situazione sprofonda, decidi che stai per fuggire .

Riepilogo dell'attività

Per effettuare la tua fuga, hai bisogno di un piano! Tuttavia, sai che qualsiasi piano ha una probabilità di fallire e piani diversi richiedono diversi sforzi.

Essendo affamato, stanco e ingegnere, decidi di scrivere un breve programma per determinare il modo migliore per sfuggire al complesso, bilanciando le preoccupazioni relative alla probabilità di successo e allo sforzo necessario.

Fai una mappa dell'edificio:

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

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

Per sfuggire all'ufficio, dovrai allontanarti dalla mappa. Qui vedi che ci sono 2 finestre ( !), o uno ti porterebbe alla libertà, ma solo una di esse accessibile. Definiamo "fuori dalla mappa" come avere i piedi fuori dai limiti della mappa

Tipi di cellule

  - 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

Le celle originariamente consumate dall'evaso considerate vuote.

Specifiche di azione

Hai un numero di possibili azioni a tua disposizione. Questi sono definiti da semplici transizioni di stato con qualche probabilità di successo intera. Ad esempio, per camminare, si sposta l'escapee di una cella, che rappresentiamo con questa transizione:

Passo

1 punto, 100%, specchio

 o.            o
 |.   -->      |
 #            #

I punti mostrano celle che devono essere vuote (o scalabili, ma non solide o distruttibili) perché ci muoviamo in essa o attraverso di essa. Il 100% significa che hai una probabilità del 100% di non farti del male e di porre fine alla tua audace fuga. Tutte le probabilità saranno percentuali intere comprese tra l'1% e il 100% incluso. Il primo diagramma mostra lo stato iniziale (in piedi su qualcosa di solido, in piedi accanto a uno spazio vuoto). Il secondo diagramma mostra lo stato del terminale (spostato nello spazio vuoto). Non ci sono requisiti per le celle non specificate (spazi, ) a sinistra (stato iniziale) per essere qualcosa in particolare. Celle non specificate (spazio,) a destra (stato terminale) dovrebbe essere lo stesso di prima (ad es. qualsiasi cosa fosse dietro la fuga, o qualunque cosa io stia camminando (sia esso spazio vuoto o altro). Nota che tutto a destra (stato terminale ) i diagrammi cambiano solo le celle da distruttibili a vuote, non possono verificarsi altri cambiamenti. "1 punto" significa che costa 1 punto: definiamo "punto" come la quantità di energia necessaria per fare un passo.

"specchio" significa che questa azione ha due forme. Viene visualizzata l'azione "destra", l'azione "sinistra" è un mirror esatto, ad esempio:

.o
.|
 # 

è la forma speculare (a sinistra) di

o.
|.
# 

L'azione destra si chiama "Destra" (es. "Step Right") L'azione sinistra si chiama "Sinistra" (es. "Step Left")

In questi diagrammi, la fuga è mostrata da

o
|

in piedi (2 unità di altezza) e

%

quando si accovaccia (alto 1 unità). Le cellule che devono essere solidi o distruttibili sono indicati da un hash, #. Le celle che non devono essere solide o distruttibili sono indicate da un punto .. Le cellule che devono essere distruttibili sono indicate da un botto !. Uno spazio vuoto appena creato viene mostrato da un carattere di sottolineatura _. xè un punto di riferimento che non si muove (non esiste, nessun vincolo su ciò che deve essere quella cella (come uno spazio )).

Nota: ignoriamo il problema della rapida decelerazione quando colpisci il pavimento e sì, in questo gioco puoi fare salti totalmente epici sulle scale)

Passo

1 punto, 100%, specchio

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

Scendi

1 punto, 100%, specchio

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

rimescolare

3 punti, 100%, specchio

 %.         %
x#   -->  x# 

Clamber Up

10 punti, 95%, specchio

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

Far cadere

0 punti, 100%

 o         
 |  -->   o
x.       x|

Drop (Stand)

0 punti, 100%

 %        o
x.  -->  x|

Salire

2 punti, 100%

 =        o
 o  -->   |
x|       x

accovacciarsi

2 punti, 100%

 o
 |  -->   %
x#       x#

stare in piedi

4 punti, 100%

 .        o
 %  -->   |
x#       x#

Salto corto

4 punti, 95%, specchio

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

Salto lungo

7 punti, 75%, specchio

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

Salto in alto

12 punti, 90%, specchio

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

Mettici le spalle!

20 punti, 80%, specchio

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

Punch

8 punti, 90%, specchio

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

Calcio

8 punti, 85%, specchio

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

Francobollo

8 punti, 90%

 o        o
 |  -->   |
x!       x_

Piani

Un piano è una sequenza delle azioni sopra definite. Per esempio:

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

Nota l'inclusione delle gocce. Le regole dovrebbero essere impostate per impedirti di fare qualsiasi cosa tranne cadere, ma devi ancora pianificare per questo!

Ogni piano ha uno sforzo richiesto, che è la somma degli sforzi per ogni passaggio. C'è anche una probabilità di successo, che è il prodotto delle probabilità di successo di ogni azione. Esempio semplice:

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%

Un "esempio funzionante" per la mappa nella parte superiore della pagina può essere trovato come una sintesi .

Ingresso

L'input è disponibile in due parti, un numero intero e una matrice o una stringa di caratteri.

L'intero è la probabilità minima accettabile (percentuale) di successo. Deve essere interpretato come una percentuale, quindi 80 significa che il tuo piano deve avere successo con probabilità non inferiore all'80%.

Una mappa valida è un rettangolo che include la fuga permanente (dimensione minima di 1x2) e nessun simbolo non specificato. Tutte le righe avranno la stessa lunghezza. È possibile accettare l'input come stringa delimitata monodimensionale (il delimitatore deve essere un singolo carattere coerente o una delle coppie CRLF e LFCR), come un array monodimensionale simile o un array bidimensionale. Se il formato di input scelto non indica in alcun modo la larghezza o l'altezza della mappa, è possibile accettare ulteriori argomenti per questi (è necessario dichiararlo chiaramente nella risposta). Puoi mescolare argomenti della riga di comando e input standard se ti va bene (es. Mappa da stdin, probabilità minima di successo da argv). Di seguito sono riportati esempi di mappe valide e non valide.

Valido:

o
|

Valido:

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

Non valido (nessuna fuga):

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

Non valido (l'escapee inizia sempre in piedi):

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

Non valido (simbolo non valido):

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

Non valido (non un rettangolo / righe di lunghezza diversa):

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

Puoi presumere che il tuo input sia valido (non mi interessa cosa fa il tuo programma se viene consegnato un input non valido).

Produzione

L'output è testo (ASCII). Può essere restituito come stringa o stampato sull'output standard. Il piano deve essere delimitato da un LF, CRLF o LFCR. Allo stesso modo, ci deve essere un altro LF, CRLF o LFCR dopo lo sforzo richiesto. Un'interruzione di riga finale è facoltativa.

È necessario elaborare un piano ottimale insieme allo sforzo richiesto o "Non c'è speranza!" se non esiste un tale piano. Non è necessario generare la probabilità di successo. Questo testo può avere o meno un'interruzione di riga finale.

Un piano ottimale è definito come un piano (vedi sopra) che richiede il minimo sforzo con almeno la data probabilità di successo. Si noti che i calcoli della probabilità devono essere esatti, non si può presumere che il virgola mobile sia abbastanza buono (Ecco perché non mi aspetto che li produciate). Proverò a progettare casi di test per testarlo equamente (se li supererai e non farai ipotesi stupide, potresti considerare valida la tua proposta).

Formato:

Required Effort: <effort>
<plan>

Ad esempio, per l'input

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

Un risultato appropriato sarebbe:

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

La probabilità di successo qui è del 76,5%.

Per la stessa mappa, ma con una probabilità minima di successo dell'80%, dovresti "rimetterti le spalle", il che richiederebbe maggiori sforzi ma soddisferebbe i criteri di probabilità di successo. Se la probabilità minima di successo fosse superiore all'80%, avresti bisogno di pensare un po 'più forte (colpisci o colpisci una parte della porta e rimescola). Se la probabilità minima di successo fosse del 100%, dovresti stampare "Non c'è speranza!"

Esempi

È possibile che ci siano più piani validi per un input, che l'output non deve essere esattamente questi, ma deve avere lo sforzo richiesto corretto ed essere un piano valido. Puoi utilizzare il verificatore per verificare le tue soluzioni (vedi sotto)

Ingresso:

100
o
|

Produzione:

Required Effort: 0
Drop

Ingresso:

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

Produzione:

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

Ingresso:

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

Produzione:

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

Per la stessa mappa, ma l'80%, l'output dovrebbe essere:

There is no hope!

Per la stessa mappa, ma il 50%, lo sforzo richiesto diventa 56 con un piano diverso)

Ingresso:

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

Produzione:

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

Ingresso:

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

Produzione:

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

Ingresso:

Questo è progettato per verificare una serie di false assunzioni alle quali si potrebbe cadere vittima, e di conseguenza possono sembrare un po 'strane

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

Uscita con possibilità di vincolo di successo 30:

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

Uscita con possibilità di vincolo di successo 32:

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

Usando la mappa in alto come input, con probabilità di vincolo di successo dell'1%, dovresti ottenere uno sforzo richiesto di 116 (possibilità di successo ~ 32%, questo ha richiesto circa 20 secondi per essere eseguito nel mio programma di test).

Criteri di vittoria

Questo è code-golf, può vincere il codice più corto.

Per essere idoneo, la tua funzione o programma deve funzionare ed essere in grado di risolvere ciascuno dei test sopra riportati in meno di 30 minuti su una macchina ragionevole. Il mio solutore li fa in meno di 30 secondi. Se lo script di test (sotto) viene eseguito in meno di 30 minuti, sei sicuramente pronto.

Solutore di esempio, verificatore, script di test e test case (con soluzioni)

Il codice C # per un risolutore e il verificatore di soluzioni sono disponibili qui come sintesi . Il gist contiene anche file.txt, che è una forma (abbastanza) leggibile automaticamente delle azioni sopra descritte, ed è necessario per l'esecuzione del programma. Qualsiasi discrepanza tra quel file e le specifiche non è intenzionale.

L'essenza contiene anche una serie di casi di test (inclusi tutti gli esempi sopra) e uno script di PowerShell per eseguire automaticamente un invio nei loro confronti. Se lo script indica che un determinato test ha avuto esito negativo, è possibile eseguire OfficeEscapeSolver.exe testcase<n>.txt outputFromYourProgram.txtper visualizzare ulteriori dettagli. Soluzioni esemplificative per questi casi di test sono in un altro Gist .

Tutto il codice è un disastro completo (anche se non risolto), ma non dovresti aver bisogno di allontanarti dall'argomento static void Main(...)per modificare la quantità di output (sentiti libero di usare queste informazioni, le ho fornite a tuo vantaggio!).

Passare un test-case non significa necessariamente che l'output sia ben formato, poiché lo script e il verificatore sono molto generosi. L'output deve corrispondere alle specifiche sopra riportate affinché l'invio sia valido.

Se ritieni di aver trovato un bug con il solutore o testscript, un errore file.txto una testcase non corretta, ti preghiamo di commentare questo post o di eseguire un ping su me su SE Chat; Probabilmente non noterò nessun altro tentativo di comunicare.

Non fornirò lo script di test in Bash o Batch, perché non li conosco, ma sono felice di includere una traduzione e scriverò una versione C # se la gente ne vuole una.

Post Amble

Hai domande? Non perdere tempo, chiediglielo oggi!

Questo compito ha lo scopo di richiedere uno sforzo , per dare ai golfisti seri qualcosa in cui affondare i denti.

I miei ringraziamenti ad ais523 per il suo feedback su Input / Output.

Posso fornire più testcase nel file gist se le persone vogliono di più (non vogliono che questo post diventi più) o se ne vogliono fornire alcuni.


2
Grande sfida! Ci proverò sicuramente quando avrò tempo. :)
R. Kap

Sai, i pericoli della caduta (o piuttosto della rapida decelerazione in basso) avrebbero potuto essere modellati dando alla transizione di caduta una probabilità del 95% circa. ;) Bella sfida!
Martin Ender,

puoi scappare attraverso una luce del cielo o tunnel? vale a dire la parte superiore o inferiore del campo? o solo sinistra o destra?
Moogie,

@Moogie puoi davvero! Finché i tuoi piedi sono liberi, sei libero (ad esempio, vedi il testcase 1x2, dove la soluzione è appena caduta una volta). Aggiungerò una piccola testcase da gist per testare andando dal soffitto.
VisualMelon

3
Aggiunta grazia alla domanda. Questa è una grande domanda che merita risposte.
programmatore

Risposte:


3

Perl 5, 1425 1464 1481 1469 1485 1438 byte

È stata una sfida divertente! E, sorprendentemente, sembra che io abbia il codice più corto finora con un valore inferiore a 1,5 KB! :)

Abbastanza sicuro di aver finalmente funzionato. Il delimitatore utilizzato è :e c'è un'ulteriore imbottitura di due file in alto e una colonna su entrambi i lati . Quindi per il tuo contributo di:

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

il mio programma richiederebbe: (NB: ci devono essere due punti alla fine, ma non all'inizio!)

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

Uso regex per tradurre da una mappa all'altra e risolvere con la forza bruta. Tuttavia, non aggiungo mappe all'elenco se quella mappa è già stata raggiunta con meno sforzo e probabilità maggiore o uguale. Le mappe vengono rimosse dall'elenco una volta esauriti tutti i possibili movimenti da quel punto. Il programma termina con successo quando corrisponde a una regex che mostra che ho raggiunto il lato o il fondo e termina con "Non c'è speranza!" quando l'elenco delle mappe è esaurito.

Sfortunatamente, c'è stata una grande quantità di efficienza scambiata per decollare alcuni byte, quindi la versione golfata è piuttosto lenta;) Perl sembra trovare gli eval in particolare piuttosto dolorosi.

Senza ulteriori indugi,

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;}}}}

Per motivi di sanità mentale, ecco la stessa cosa con le nuove righe e alcuni commenti:

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)

Riesco già a vedere un paio di posti per strappare ancora qualche byte, ma non voglio ancora ripetere tutti i test. Dopo! :)

Modifica: sono state aggiunte alcune imbottiture di seguito per adattarle in modo più preciso all'uscita nel pavimento. Rimossi alcuni degli eval, quindi ora il codice potrebbe essere più veloce!

Modifica: non gestiva le scale e le gocce abbastanza bene. Ancora non gestisce le scale nel modo giusto ... Sto provando a sistemarlo adesso.


Sono contento che qualcun altro si sia divertito! Temo di non poterlo accettare così com'è attualmente, dal momento che non puoi supporre che l'input abbia quelle righe extra o il riempimento in alto (ma a ~ 1,5kB, l'inserimento immediato non dovrebbe danneggiare troppo!). Non ho Perl su questa macchina, ma proverò a trovare un modo per testarlo oggi, quindi posso verificare che funzioni e funzioni in un intervallo di tempo ragionevole e riferire!
VisualMelon

1
@VisualMelon Nessun problema, ho cambiato il metodo di input e ho aggiunto manualmente il padding. Tende a esplodere nei puzzle più grandi, ma funziona in un lasso di tempo ragionevole per la maggior parte dei casi di test.
Chris,

Non ancora testato questo, ma noto che hai detto che utilizza una regex per rilevare quando esci dal lato o dal fondo, ma puoi anche sfuggire dalla parte superiore (vedi testcase10 che è stato aggiunto a questo scopo), nel caso in cui ti perdessi questo
VisualMelon

1
@VisualMelon Ah, ho pensato che per sfuggire al tetto la fuga avrebbe dovuto salire in cima alla stanza e poi camminare di lato, fuori dal tetto. Vedo ora la frase pertinente. Lo riparerò :)
Chris,

2
Potresti aggiungere un link TIO?
programmatore

3

C #, 1814 1481 1395 byte

Che schifo !! Sono davvero piuttosto contento di questo ora!

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);}}

Provalo online

Programma completo, porta input a STDIN, output a STDOUT. Essenzialmente una riscrittura del mio risolutore originale, usando un BFS semplice e inefficiente implementato per trovare il percorso ottimale. È ragionevolmente veloce, non può essere molto più lento della mia altra implementazione (non l'ho ancora cronometrato), sicuramente funziona entro il limite di tempo. Gran parte del costo è la tabella delle azioni, che è codificata come valori separati da virgola che registrano il nome, la mappa "match / smash" e altre proprietà di ogni azione disponibile.

Inizia leggendo la minima probabilità di successo e la mappa. Quindi individua la fuga, lo rimuove dalla mappa e crea uno "stato di ricerca" contenente queste informazioni. Quindi, esegue il BFS, che esamina ripetutamente il prossimo stato dovuto con il minimo sforzo (assicurando che trovi una soluzione ottimale). Prima di espandere il nodo, confronta lo sforzo e la probabilità di successo con i nodi precedenti con la stessa mappa e posizione di fuga e si rifiuta se è già stato trovato un percorso migliore verso questo stato. Se sopravvive a questo, si aggiunge alla tabella "visto" in modo da poter rifiutare lo stato in seguito. Questo è tutto per le prestazioni e senza di esso il fattore di ramificazione sarebbe enorme. Quindi controlla se la fuga è fuori dalla mappa. Se lo è, allora vince! Rintraccia lo stato (ogni stato precedente viene registrato con ogni stato) e crea il piano (al contrario) prima di uscire dal ciclo BFS. Altrimenti, prova ad applicare ogni azione e aggiunge qualsiasi cosa possa essere applicata adue coda, prima di ordinare questa coda in modo da ottenere il minimo sforzo nella successiva iterazione.

Codice formattato e commentato:

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);
    }
}

Bel lavoro! Mi diverto all'infinito che il tuo vecchio punteggio e il nuovo punteggio siano anagrammi l'uno dell'altro ... lol
HyperNeutrino

C # ha battuto Perl?
Esolanging Fruit
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.