Office Escape: Rencanakan jalan keluar Anda!

32

Ini adalah sprint terakhir ... dan separuh tim Anda sakit. Anda bekerja lembur, hanya membuat komitmen terakhir untuk hari itu, menanti-nanti ... mengapa lampu dimatikan? Saya tidak ingat petugas keamanan datang ... oh tidak! Saya meninggalkan kunci saya di rumah!

Ketika kengerian situasi mulai meresap, Anda memutuskan bahwa Anda akan melarikan diri .

Ringkasan Tugas

Untuk melakukan pelarian Anda, Anda perlu rencana! Namun, Anda tahu bahwa rencana apa pun memiliki kemungkinan gagal, dan rencana yang berbeda membutuhkan upaya yang berbeda.

Karena lapar, lelah, dan seorang insinyur, Anda memutuskan untuk menulis sebuah program singkat untuk menentukan cara terbaik untuk melarikan diri dari kompleks, menyeimbangkan kekhawatiran tentang kemungkinan keberhasilan dan upaya yang diperlukan.

Anda membuat peta bangunan:

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

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

Untuk keluar dari kantor, Anda harus memindahkan diri dari peta. Di sini Anda melihat ada 2 jendela ( !), salah satunya akan mengarahkan Anda ke kebebasan, tetapi hanya satu yang dapat diakses. Kami mendefinisikan 'off the map' sebagai memiliki kaki Anda di luar batas peta

Jenis sel

  - 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

Sel-sel yang semula dikonsumsi oleh pelarian dianggap kosong.

Spesifikasi Tindakan

Anda memiliki sejumlah tindakan yang memungkinkan di disposable Anda. Ini didefinisikan oleh transisi keadaan sederhana dengan beberapa probabilitas keberhasilan integer. Misalnya, untuk berjalan, Anda memindahkan sel satu pelarian, yang kami wakili dengan transisi ini:

Langkah

1 stp, 100%, mirror

 o.            o
 |.   -->      |
 #            #

Titik-titik menunjukkan sel yang harus kosong (atau dapat dipanjat, tetapi tidak solid atau dapat dirusak) baik karena kita bergerak ke dalamnya atau melewatinya. 100% berarti Anda memiliki peluang 100% untuk tidak melukai diri sendiri dan mengakhiri pelarian Anda yang berani. Semua probabilitas adalah persentase bilangan bulat antara 1% dan 100% inklusif. Diagram pertama menunjukkan keadaan awal (berdiri di atas sesuatu yang kokoh, berdiri di sebelah ruang kosong). Diagram kedua menunjukkan status terminal (dipindahkan ke ruang kosong). Tidak ada persyaratan untuk setiap sel yang tidak ditentukan (spasi, ) di sebelah kiri (keadaan awal) untuk menjadi sesuatu yang khusus. Sel yang tidak ditentukan (spasi,) di sebelah kanan (keadaan terminal) harus sama dengan sebelumnya (mis. apa pun yang ada di belakang pelarian, atau apa pun yang kebetulan saya jalani (baik itu ruang kosong atau lainnya). Perhatikan bahwa semua tangan kanan (keadaan terminal) ) diagram hanya akan mengubah sel dari yang dapat dirusak menjadi kosong, tidak ada perubahan lain yang dapat terjadi. "1 stp" berarti biayanya 1 stp: kami mendefinisikan "stp" sebagai jumlah energi yang diperlukan untuk mengambil langkah.

"Cermin" berarti tindakan ini memiliki dua bentuk. Tindakan "kanan" ditampilkan, tindakan "kiri" adalah cermin yang tepat, misalnya:

.o
.|
 # 

adalah bentuk cermin (Kiri) dari

o.
|.
# 

Tindakan yang tepat disebut "Kanan" (mis. "Langkah Kanan") Tindakan kiri disebut "Kiri" (misalnya "Langkah Kiri")

Dalam diagram ini, pelarian ditunjukkan oleh

o
|

ketika berdiri (tinggi 2 unit) dan

%

saat berjongkok (tinggi 1 unit). Sel yang harus padat atau dapat dirusak ditunjukkan dengan hash #,. Sel yang tidak boleh padat atau dapat dirusak ditunjukkan oleh sebuah titik .. Sel-sel yang harus dirusak ditandai dengan ledakan !. Ruang kosong yang baru dibuat ditunjukkan oleh garis bawah _. xadalah titik referensi yang tidak bergerak (tidak ada, tidak ada batasan pada apa sel itu harus (seperti spasi )).

Catatan: kami mengabaikan masalah perlambatan cepat saat Anda menyentuh lantai, dan ya, dalam game ini Anda dapat melakukan lompatan yang sangat epik ke tangga)

Langkah

1 stp, 100%, mirror

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

Turun

1 stp, 100%, mirror

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

Acak

3 stp, 100%, mirror

 %.         %
x#   -->  x# 

Naik

10 stp, 95%, cermin

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

Penurunan

0 stp, 100%

 o         
 |  -->   o
x.       x|

Jatuhkan (Berdiri)

0 stp, 100%

 %        o
x.  -->  x|

Memanjat

2 stp, 100%

 =        o
 o  -->   |
x|       x

Mendekam

2 stp, 100%

 o
 |  -->   %
x#       x#

Berdiri

4 stp, 100%

 .        o
 %  -->   |
x#       x#

Lompat Pendek

4 stp, 95%, cermin

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

Lompat jauh

7 stp, 75%, cermin

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

Loncat tinggi

12 stp, 90%, cermin

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

Masukkan kembali Anda ke dalamnya!

20 stp, 80%, cermin

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

Meninju

8 stp, 90%, cermin

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

Tendangan

8 stp, 85%, cermin

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

Stempel

8 stp, 90%

 o        o
 |  -->   |
x!       x_

Rencana

Rencana adalah urutan tindakan yang didefinisikan di atas. Sebagai contoh:

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

Perhatikan dimasukkannya tetes. Aturan harus ditetapkan untuk menghentikan Anda melakukan apa pun selain menjatuhkan, tetapi Anda masih harus merencanakannya!

Setiap rencana memiliki upaya yang diperlukan, yang merupakan jumlah dari upaya untuk setiap langkah. Ada juga probabilitas keberhasilan, yang merupakan produk dari probabilitas keberhasilan setiap tindakan. Contoh sederhana:

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%

'Contoh yang dikerjakan' untuk peta di bagian atas halaman dapat ditemukan sebagai intisari .

Memasukkan

Input datang dalam dua bagian, integer, dan array atau serangkaian karakter.

Integer adalah probabilitas keberhasilan minimum yang dapat Anda terima (persen). Itu harus ditafsirkan sebagai persentase, jadi 80 berarti rencana Anda harus berhasil dengan probabilitas tidak kurang dari 80%.

Peta yang valid adalah persegi panjang yang mencakup pelarian berdiri (ukuran minimum 1x2) dan tidak ada simbol yang tidak ditentukan. Semua baris akan memiliki panjang yang sama. Anda dapat menerima input sebagai string berdimensi 1 dimensi (pembatas harus karakter tunggal yang konsisten, atau salah satu pasangan CRLF dan LFCR), sebagai larik 1 dimensi yang serupa, atau larik 2 dimensi. Jika format input yang Anda pilih tidak menunjukkan lebar atau tinggi peta dalam beberapa cara, Anda dapat menerima argumen tambahan untuk ini (Anda harus menyatakan ini dengan jelas dalam jawaban Anda). Anda dapat mencampur argumen baris perintah dan input standar jika cocok untuk Anda (misalnya memetakan dari stdin, probabilitas keberhasilan minimum dari argv). Berikut ini adalah contoh peta yang valid dan tidak valid.

Sah:

o
|

Sah:

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

Tidak valid (tidak ada pelarian):

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

Tidak valid (pelarian selalu mulai berdiri):

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

Tidak valid (simbol tidak valid):

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

Tidak valid (bukan persegi panjang / baris panjang berbeda):

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

Anda dapat menganggap input Anda valid (Saya tidak peduli apa yang program Anda lakukan jika input yang diberikan salah).

Keluaran

Output adalah teks (ASCII). Dapat dikembalikan sebagai string, atau dicetak ke output standar. Rencana tersebut harus dibatasi oleh LF, CRLF, atau LFCR. Demikian pula, harus ada LF, CRLF, atau LFCR lain setelah Upaya yang Diperlukan. Istirahat garis trailing adalah opsional.

Anda harus mengeluarkan rencana optimal bersama dengan upaya yang diperlukan, atau "Tidak ada harapan!" jika tidak ada rencana seperti itu. Anda tidak perlu menampilkan probabilitas keberhasilan. Teks ini mungkin atau tidak memiliki trailing line break.

Rencana optimal didefinisikan sebagai rencana (lihat di atas) yang membutuhkan upaya minimum dengan setidaknya probabilitas keberhasilan yang diberikan. Perhatikan bahwa perhitungan probabilitas Anda harus tepat, Anda mungkin tidak menganggap bahwa floating point cukup baik (Inilah sebabnya saya tidak mengharapkan Anda untuk memproduksinya). Saya akan mencoba merancang kasus uji untuk menguji secara adil ini (jika Anda lulus dan tidak membuat asumsi bodoh maka Anda dapat menganggap kiriman Anda valid).

Format:

Required Effort: <effort>
<plan>

Misalnya untuk input

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

Output yang sesuai adalah:

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

Peluang sukses di sini adalah 76,5%.

Untuk peta yang sama, tetapi probabilitas keberhasilan minimum 80%, Anda harus "Masukkan kembali ke dalamnya", yang akan membutuhkan lebih banyak usaha tetapi memenuhi kriteria probabilitas keberhasilan. Jika probabilitas keberhasilan minimum lebih besar dari 80%, Anda harus berpikir sedikit lebih keras (baik meninju atau menendang bagian pintu dan keluar). Jika probabilitas keberhasilan minimum adalah 100%, Anda harus mencetak "Tidak ada harapan!"

Contohnya

Ada kemungkinan bahwa ada lebih dari satu rencana yang valid untuk input, output Anda tidak harus persis seperti ini, tetapi harus memiliki upaya yang diperlukan yang benar, dan menjadi rencana yang valid. Anda dapat menggunakan verifikasi untuk memeriksa solusi Anda (lihat di bawah)

Memasukkan:

100
o
|

Keluaran:

Required Effort: 0
Drop

Memasukkan:

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

Keluaran:

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

Memasukkan:

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

Keluaran:

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

Untuk peta yang sama, tetapi 80%, hasilnya harus:

There is no hope!

Untuk peta yang sama, tetapi 50%, upaya yang diperlukan menjadi 56 dengan rencana yang berbeda)

Memasukkan:

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

Keluaran:

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

Memasukkan:

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

Keluaran:

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

Memasukkan:

Yang ini dirancang untuk memeriksa sejumlah asumsi salah yang mungkin menjadi korban, dan akibatnya mungkin terlihat agak aneh

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

Keluaran dengan peluang kendala keberhasilan 30:

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

Output dengan peluang kendala kesuksesan 32:

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

Dengan menggunakan peta di bagian atas sebagai input, dengan probabilitas kendala keberhasilan 1%, Anda harus mendapatkan Upaya yang Diperlukan sebesar 116 (peluang keberhasilan ~ 32%, ini membutuhkan waktu sekitar 20 detik untuk dijalankan dalam program pengujian saya).

Kriteria Kemenangan

Ini kode-golf, semoga kode terpendek menang.

Agar memenuhi syarat, fungsi atau program Anda harus bekerja dan dapat menyelesaikan masing-masing testcases di atas dalam waktu kurang dari 30 menit dengan mesin yang masuk akal. Solver saya melakukannya masing-masing dalam waktu kurang dari 30 detik. Jika skrip uji (di bawah) berjalan dalam waktu kurang dari 30 menit, Anda pasti senang.

Contoh Solver, Verifier, Test Script, dan TestCases (dengan solusi)

Kode C # untuk solver, dan verifier solusi, tersedia di sini sebagai intisari . Inti juga berisi file.txt, yang merupakan bentuk tindakan yang dapat dibaca (cukup) dari mesin yang dijelaskan di atas, dan diperlukan untuk menjalankan program. Perbedaan apa pun antara file dan spek itu tidak disengaja.

Inti juga berisi sejumlah kasus uji (termasuk semua contoh di atas), dan skrip PowerShell untuk secara otomatis menjalankan pengajuan terhadap mereka. Jika skrip memberi tahu Anda bahwa tes tertentu gagal, Anda dapat berlari OfficeEscapeSolver.exe testcase<n>.txt outputFromYourProgram.txtuntuk melihat detail lebih lanjut. Contoh solusi untuk kasus uji ini adalah di Intisari lain .

Semua kode adalah kekacauan lengkap (meskipun tidak diubah), tetapi Anda tidak perlu menyimpang jauh dari static void Main(...)untuk mengubah jumlah output (jangan ragu untuk menggunakan informasi ini, saya telah menyediakannya untuk keuntungan Anda!).

Melewati uji kasus tidak harus berarti bahwa output Anda terbentuk dengan baik, karena skrip dan verifikator sangat murah hati. Output Anda harus sesuai dengan spesifikasi di atas agar kiriman Anda valid.

Jika Anda merasa telah menemukan bug dengan solver atau script tes, ada kesalahan dalam file.txt , atau testcase cerdik, maka silakan komentar pada posting ini atau ping saya di SE Chat; Saya mungkin tidak akan memperhatikan upaya komunikasi lainnya.

Saya tidak akan memberikan skrip uji dalam Bash atau Batch, karena saya tidak mengetahuinya, tapi saya senang memasukkan terjemahan dan akan menulis versi C # jika orang menginginkannya.

Poskan Amble

Punya pertanyaan? Jangan tunda, tanyakan kepada mereka hari ini!

Tugas ini dimaksudkan untuk membutuhkan usaha , untuk memberikan pegolf serius sesuatu untuk menenggelamkan gigi mereka.

Terima kasih kepada ais523 untuk umpan baliknya pada Input / Output.

Saya dapat memberikan lebih banyak testcases dalam file inti jika orang menginginkan lebih (tidak ingin posting ini menjadi lebih lama), atau ingin memberikan sebagian dari mereka sendiri.

VisualMelon
sumber
2
Tantangan besar! Saya pasti akan mencoba ini ketika saya punya waktu. :)
R. Kap
Anda tahu, bahaya jatuh (atau lebih tepatnya perlambatan cepat di bagian bawah) bisa dimodelkan dengan memberikan transisi drop kemungkinan 95% atau lebih. ;) Tantangan yang bagus!
Martin Ender
dapatkah kamu melarikan diri melalui cahaya langit atau terowongan? yaitu atas dan atau bawah bidang? atau hanya kiri atau kanan?
Moogie
@ Moogie Anda memang bisa! Selama kaki Anda bebas, Anda bebas (misalnya, lihat testcase 1x2, di mana solusinya hanya jatuh sekali). Saya akan menambahkan testcase kecil untuk menguji inti dari langit-langit.
VisualMelon
3
Menambahkan karunia untuk dipertanyakan. Ini adalah pertanyaan hebat yang patut mendapat jawaban.
programmer5000

Jawaban:

3

Perl 5, 1425 1464 1481 1469 1485 1438 byte

Itu tantangan yang menyenangkan! Dan, yang mengejutkan, sepertinya saya memiliki kode terpendek sejauh ini dengan sedikit di bawah 1.5kB! :)

Cukup yakin saya akhirnya berhasil. Pembatas yang digunakan adalah :, dan ada bantalan ekstra dari dua baris di atas dan satu kolom di kedua sisi . Jadi untuk masukan Anda dari:

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

program saya akan mengambil: (NB: harus ada titik dua di akhir, tetapi tidak di awal!)

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

Saya menggunakan regex untuk menerjemahkan dari satu peta ke peta lain dan menyelesaikannya dengan kekerasan. Namun, saya tidak menambahkan peta ke daftar jika peta itu telah dicapai dengan sedikit usaha dan probabilitas lebih besar atau sama. Peta dihapus dari daftar setelah semua gerakan yang mungkin dari titik itu telah habis. Program berakhir dengan sukses ketika cocok dengan regex yang menunjukkan saya telah mencapai sisi atau bawah dan berakhir dengan "Tidak ada harapan!" ketika daftar peta habis.

Sayangnya, ada banyak efisiensi yang diperdagangkan untuk melepas beberapa byte, sehingga versi golfnya agak lambat;) Perl tampaknya menemukan eval khususnya sangat menyakitkan.

Tanpa kata perpisahan lebih lanjut,

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

Demi kewarasan, ada hal yang sama dengan baris baru dan beberapa komentar:

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)

Saya sudah dapat melihat beberapa tempat untuk menghilangkan beberapa byte lagi, tetapi saya belum ingin menjalani semua pengujian lagi. Kemudian! :)

Sunting: Menambahkan beberapa padding di bawah ini juga agar sesuai dengan output Anda lebih tepatnya ketika melarikan diri melalui lantai. Menghapus beberapa evals, sehingga kodenya mungkin berjalan lebih cepat sekarang juga!

Sunting: Tidak menangani tangga dan jatuh dengan benar. Masih tidak menangani tangga dengan benar ... Mencoba memperbaikinya sekarang.

Chris
sumber
Senang orang lain bersenang-senang dengan itu! Saya takut bahwa saya tidak dapat menerima ini seperti saat ini, karena Anda tidak dapat mengasumsikan bahwa input dengan baris-baris tambahan atau padding di atas (tetapi pada ~ 1.5kB, hanya memasukkan langsung tidak boleh terluka) terlalu banyak!). Saya tidak memiliki Perl pada mesin ini, tetapi saya akan mencoba dan menemukan cara untuk menguji ini hari ini, sehingga saya dapat memeriksanya bekerja dan berjalan dalam kerangka waktu yang masuk akal, dan melaporkan kembali!
VisualMelon
1
@VisualMelon Tidak masalah, saya mengubah metode input dan menambahkan padding secara manual. Memang cenderung meledak dalam teka-teki yang lebih besar, tetapi berjalan dalam kerangka waktu yang masuk akal untuk sebagian besar kasus uji Anda.
Chris
Masih belum menguji ini, tetapi saya perhatikan Anda mengatakan bahwa ini menggunakan regex untuk mendeteksi ketika Anda pergi dari samping atau bawah, tetapi Anda juga dapat melarikan diri dari atas (lihat testcase10 yang ditambahkan untuk tujuan ini), kalau-kalau Anda tidak terjawab ini
VisualMelon
1
@VisualMelon Ah, saya berasumsi bahwa untuk melarikan diri dari atap, pelarian harus naik ke atas ruangan dan kemudian berjalan ke samping, dari atap. Saya melihat kalimat yang relevan sekarang. Saya akan memperbaikinya :)
Chris
2
Bisakah Anda menambahkan tautan TIO?
programmer5000
3

C #, 1814 1481 1395 byte

Betapa kerasnya !! Saya benar-benar senang dengan ini sekarang!

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

Cobalah secara Online

Program yang lengkap, mengambil input ke STDIN, output ke STDOUT. Pada dasarnya menulis ulang pemecah asli saya, menggunakan BFS sederhana dan tidak efisien diimplementasikan untuk menemukan jalur yang optimal. Ini cukup cepat, tidak bisa jauh lebih lambat daripada implementasi saya yang lain (saya belum benar-benar menghitung waktunya), tentu berjalan dalam batas waktu. Sebagian besar biaya adalah tabel Tindakan, yang dikodekan sebagai nilai terpisah koma yang mencatat nama, peta 'cocok / hancurkan', dan properti lainnya dari setiap tindakan yang tersedia.

Dimulai dengan membaca dalam probabilitas minimum keberhasilan dan peta. Kemudian itu menemukan pelarian, menghapusnya dari peta, dan membuat 'kondisi pencarian' yang mengandung informasi ini. Kemudian, ia melakukan BFS, yang berulang kali melihat status jatuh tempo berikutnya dengan sedikit usaha (memastikan ia menemukan solusi optimal). Sebelum memperluas node, ia membandingkan upaya dan probabilitas keberhasilannya dengan node sebelumnya dengan peta yang sama dan lokasi pelarian, dan menolaknya sendiri jika sudah ditemukan rute yang lebih baik untuk keadaan ini. Jika itu bertahan, ini menambahkan dirinya ke tabel 'terlihat' sehingga ia bisa menolak status nanti. Ini semua untuk kinerja, dan tanpa itu faktor percabangan akan sangat besar. Kemudian memeriksa apakah pelarian dari peta. Jika ya, maka ia menang! Ini melacak kembali keadaan (setiap keadaan sebelumnya direkam dengan masing-masing negara) dan membangun rencana (secara terbalik) sebelum keluar dari loop BFS. Kalau tidak, ia mencoba menerapkan setiap tindakan, dan menambahkan apa pun yang dapat diterapkan kedue antrian, sebelum menyortir antrian ini sehingga kita mendapatkan usaha yang paling tidak menyatakan iterasi berikutnya.

Kode yang diformat dan dikomentari:

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
sumber
Pekerjaan yang baik! Tak henti-hentinya menghibur saya bahwa skor lama dan skor baru Anda adalah anagram satu sama lain ... lol
HyperNeutrino
Apakah C # telah mengalahkan Perl?
Buah Esolanging