Office Escape:計画を立てましょう!


32

それは最後のスプリントです...そして、あなたのチームの半分は病気です。あなたは遅く働いて、その日の最後のコミットをして、楽しみにしています...なぜライトが消えたのですか?警備員がやってくるのを覚えていません... 私は家に鍵を置いた!

状況の恐怖が沈むにつれて、あなたはあなたが逃げようとていると決める。

タスクの概要

逃げるには、計画が必要です!ただし、計画には失敗する可能性があり、計画ごとに異なる労力が必要であることはご存じでしょう。

お腹が空いていて、疲れていて、エンジニアであるあなたは、短いプログラムを書いて、複雑さから逃れるための最良の方法を決定し、成功の可能性とそれが必要とする努力のバランスを取ります。

建物の地図を作成します。

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

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

オフィスを脱出するには、マップから自分自身を移動する必要があります。ここでは、2つのウィンドウ(!)があり、どちらか一方が自由になりますが、アクセスできるのはそのうちの1つだけです。「マップ外」とは、マップの境界外に足を置くことを意味します

細胞の種類

  - 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

脱出者によって最初に消費された細胞は空になった。

アクション仕様

使い捨てで可能なアクションの数があります。これらは、整数の成功確率を持つ単純な状態遷移によって定義されます。たとえば、ウォーキングの場合、エスケープするセルを1つのセルに移動します。これを次の遷移で表します。

ステップ

1 stp、100%、ミラー

 o.            o
 |.   -->      |
 #            #

点は、中に移動するか、中を通過するために空でなければならない(または登ることができますが、固体または破壊可能ではない)セルを示しています。100%とは、自分を傷つけずに大胆な脱出を終わらせる可能性が100%あることを意味します。すべての確率は、1%から100%の間の整数パーセンテージです。最初の図は、初期状態を示しています(何か立っている、空いているスペースの隣に立っている)。2番目の図は、端末の状態(空のスペースに移動した)を示しています。左側(初期状態)の特定されていないセル(スペース)が特定のものである必要はありません。未指定のセル(スペース、)右側(終端状態)は以前と同じである必要があります(例:脱走者の背後にあるもの、またはたまたま私が歩いているもの(空きスペースなど))。 )ダイアグラムはセルを破壊可能から空に変更するだけで、他の変更は発生しません。「1 stp」は1 stpのコストを意味します。「stp」をステップに必要なエネルギー量として定義します。

「ミラー」は、このアクションに2つの形式があることを意味します。「右」アクションが表示され、「左」アクションは正確なミラーです。例:

.o
.|
 # 

の鏡(左)形式

o.
|.
# 

右のアクションは「右」と呼ばれます(例:「ステップ右」)左のアクションは「左」と呼ばれます(例:「左ステップ」)

これらの図では、脱走者は

o
|

立っているとき(高さ2ユニット)および

%

しゃがむとき(1ユニットの高さ)。固体または破壊可能である必要があるセルは、ハッシュで示され#ます。固体または破壊可能であってはならないセルは、ドットで示され.ます。破壊可能でなければならないセルは、バングで示され!ます。新しく作成された空のスペースは、アンダースコアで表示されます_x移動しない参照ポイントです(存在しない、そのセルがどうあるべきかについての制約はありません(スペースなど))。

注:床に着いたときの急速な減速の問題は無視します。はい、このゲームでは、はしごに完全に壮大なジャンプをすることができます)

ステップ

1 stp、100%、ミラー

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

登る

1 stp、100%、ミラー

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

シャッフル

3 stp、100%、ミラー

 %.         %
x#   -->  x# 

クランバーアップ

10 stp、95%、ミラー

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

ドロップ

0 stp、100%

 o         
 |  -->   o
x.       x|

ドロップ(スタンド)

0 stp、100%

 %        o
x.  -->  x|

登る

2 stp、100%

 =        o
 o  -->   |
x|       x

クラウチ

2 stp、100%

 o
 |  -->   %
x#       x#

スタンド

4 stp、100%

 .        o
 %  -->   |
x#       x#

ショートジャンプ

4 stp、95%、ミラー

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

走り幅跳び

7 stp、75%、ミラー

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

高跳び

12 stp、90%、ミラー

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

それに背を向けて!

20 stp、80%、ミラー

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

パンチ

8 stp、90%、ミラー

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

キック

8 stp、85%、ミラー

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

切手

8 stp、90%

 o        o
 |  -->   |
x!       x_

予定

計画は、上記で定義された一連のアクションです。例えば:

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

ドロップが含まれていることに注意してください。ルールは、ドロップ以外の操作を停止するように設定する必要がありますが、まだ計画する必要があります!

どの計画にも必要な労力があります。これは、各ステップの労力の合計です。成功確率もあります。これは、各アクションの成功確率の積です。簡単な例:

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%

ページの上部にあるマップの「実用的な例」は、要点として見つけることができます。

入力

入力は、整数と、文字の配列または文字列の2つの部分で構成されます。

整数は、成功の最小許容(パーセント)確率です。パーセンテージとして解釈されるため、80は計画が80%以上の確率で成功する必要があることを意味します。

有効なマップは、スタンディングエスケープ(最小サイズ1x2)を含み、未指定のシンボルを含まない長方形です。すべての行は同じ長さになります。入力は、1次元の区切り文字列(区切り文字は単一の一貫した文字、またはCRLFとLFCRのペアのいずれかでなければなりません)、同様の1次元配列、または2次元配列として受け入れることができます。選択した入力形式が何らかの方法でマップの幅または高さを示さない場合、これらの追加の引数を受け入れることができます(これを回答で明確に述べる必要があります)。必要に応じて、コマンドライン引数と標準入力を混在させることができます(たとえば、stdinからのマップ、argvからの最小成功確率)。以下は、有効なマップと無効なマップの例です。

有効:

o
|

有効:

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

無効(エスケープなし):

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

無効(エスケープが常に立ち上がる):

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

無効(無効な記号):

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

無効です(長方形/異なる長さの行ではありません):

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

入力が有効であると仮定することができます(無効な入力が渡​​された場合、プログラムが何をするかは気にしません)。

出力

出力はテキスト(ASCII)です。文字列として返されるか、標準出力に出力されます。計画は、LF、CRLF、またはLFCRで区切る必要があります。同様に、Required Effortの後に別のLF、CRLF、またはLFCRが必要です。末尾の改行はオプションです。

最適な計画を、それが必要とする努力とともに出力するか、「希望はありません!」そのような計画が存在しない場合。成功の確率を出力する必要はありません。このテキストには、末尾の改行がある場合とない場合があります。

最適な計画とは、少なくとも所定の成功確率で最小限の労力を必要とする計画(上記参照)として定義されます。確率の計算は正確でなければならないことに注意してください。浮動小数点が十分であると仮定することはできません(これが出力を期待しない理由です)。私はこれを公正にテストするためにテストケースを設計しようとします(それらに合格し、仮の仮定を立てない場合は、提出物が有効であると考えるかもしれません)。

フォーマット:

Required Effort: <effort>
<plan>

たとえば、入力用

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

適切な出力は次のとおりです。

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

ここで成功する確率は76.5%です。

同じマップで、成功の最小確率が80%の場合、「それに戻る」必要があります。これは、より多くの労力を必要としますが、成功確率の基準を満たします。成功の最小確率が80%を超える場合は、少し難しく考える必要があります(ドアの一部をパンチまたはキックしてシャッフルアウト)。成功の最小確率が100%の場合、「希望はありません!」と印刷する必要があります。

入力に対して複数の有効なプランがある可能性があります。出力は正確にこれらである必要はありませんが、正しい必要な作業が必要であり、有効なプランである必要があります。検証ツールを使用してソリューションを確認できます(以下を参照)

入力:

100
o
|

出力:

Required Effort: 0
Drop

入力:

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

出力:

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

入力:

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

出力:

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

同じマップで、80%の場合、出力は次のようになります。

There is no hope!

同じマップで、50%の場合、必要な作業量は異なるプランで56になります)

入力:

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

出力:

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

入力:

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

出力:

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

入力:

これは、犠牲になる可能性のある多くの誤った仮定をチェックするように設計されており、その結果、少し奇妙に見えるかもしれません

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

成功の可能性制約30の出力:

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

成功の可能性制約32の出力:

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

上部のマップを入力として使用し、成功の確率を1%に制限すると、116の必要な努力が得られるはずです(成功の確率〜32%、これはテストプログラムで実行するのに約20秒かかりました)。

勝利基準

これはコードゴルフです。最短のコードが勝つかもしれません。

資格を得るには、機能またはプログラムが機能し、妥当なマシンで30分以内に上記の各テストケースを解決できる必要があります。私のソルバーは、それぞれ30秒以内にそれらを実行します。テストスクリプト(下記)が30分以内に実行される場合は、ぜひ行ってください。

ソルバー、検証、テストスクリプト、およびテストケースの例(ソリューション付き)

ソルバーのC#コードとソリューション検証ツールは、ここで要点として利用できます。要点にはが含まれますfile.txt。これは、上記で説明したアクションの機械可読(十分)な形式であり、プログラムの実行に必要です。そのファイルと仕様の間の矛盾は意図的なものではありません。

要旨には、多数のテストケース(上記のすべての例を含む)と、それらに対して自動的に送信を実行するPowerShellスクリプトも含まれています。特定のテストが失敗したことをスクリプトが示している場合は、実行OfficeEscapeSolver.exe testcase<n>.txt outputFromYourProgram.txtして詳細を確認できます。これらのテストケースのソリューション例は、別のGistにあります。

すべてのコードは完全に混乱していますがstatic void Main(...)、出力量を変更するために遠くに迷う必要はありません(この情報を自由に使用してください、私はあなたのためにそれを提供しました!)。

スクリプトと検証ツールは非常に寛大なので、テストケースに合格することは必ずしも出力が適切に形成されていることを意味しません。提出を有効にするには、出力が上記の仕様と一致する必要があります。

ソルバーまたはテストスクリプトのバグ、エラーfile.txt、または危険なテストケースを見つけたと思われる場合は、この投稿にコメントするか、SEチャットでpingしてください。私はおそらく他のコミュニケーションの試みに気付かないでしょう。

BashやBatchでテストスクリプトを提供することはありません。それらがわからないからです。しかし、翻訳を含めて喜んで、人々が望むならC#バージョンを書きます。

ポストアンブル

質問がありますか?遅れないで、今日彼らに聞いてください!

このタスクは、真剣なゴルファーに歯を沈める何かを与えるための努力必要とすることを意図しています

入力/出力に関するフィードバックに対するais523に感謝します。

人々がもっと欲しければ(この投稿がこれ以上長くならないように)、または自分自身のいくつかを提供したいなら、gistファイルでより多くのテストケースを提供できます。


2
素晴らしい挑戦です!時間があったら絶対に試してみます。:)
R.カップ

落下の危険性(または下部の急激な減速)は、ドロップトランジションに95%程度の確率を与えることでモデル化できたはずです。;)ナイスチャレンジ!
マーティンエンダー

スカイライトやトンネルを通って脱出できますか?すなわち、フィールドの上部または下部ですか?または左か右だけですか?
ムージー

@Moogie本当にできる!あなたの足が自由である限り、あなたは自由です(例えば、1x2のテストケースを参照してください。ソリューションは1回だけドロップされます)。天井から外れることをテストするために、要点に小さなテストケースを追加します。
VisualMelon

3
質問に報奨金を追加しました。これは答えに値する素晴らしい質問です。
Programmer5000

回答:


3

Perl 5、1425 1464 1481 1469 1485 1438バイト

それは楽しいチャレンジでした!そして、驚いたことに、私はこれまでのところ、1.5kB未満で最も短いコードを持っているように見えます!:)

ようやくこれが機能するようになったと確信しています。使用される区切り文字は:であり、上部に2行、両側に1列の余分なパディングがあります。だからあなたの入力のために:

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

私のプログラムは次のようになります:(注:コロンは最後にある必要がありますが、先頭にはありません!)

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

正規表現を使用して、あるマップから別のマップに変換し、総当たりで解決します。ただし、より少ない労力で、または同等以上の確率でマップに既に到達している場合は、リストにマップを追加しません。そのポイントからのすべての可能な動きが使い果たされると、マップはリストから削除されます。プログラムは、側面または下部に到達したことを示す正規表現と一致し、「希望はありません!」で終了すると正常に終了します。マップのリストが使い果たされたとき。

残念なことに、数バイトを取り除くためにかなりの効率が犠牲になったため、ゴルフバージョンはかなり遅いです;)Perlは特にevalsが非常に苦痛だと感じているようです。

それ以上の助力なしで、

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

正気のために、ここに改行といくつかのコメントがあります:

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)

私はすでにいくつかの場所を見て、さらに数バイトを削減することができますが、まだすべてのテストをやり直したくありません。後!:)

編集:床を抜けるときに出力をより正確に合わせるために、下にもいくつかのパディングを追加しました。評価の一部を削除したため、コードの実行速度が向上する可能性があります!

編集:はしごを処理しておらず、非常に適切にドロップします。まだはしごを正しく処理しません...今それを修正しようとしています。


他の誰かがそれを楽しんでくれてうれしいです!入力の上部に余分な行やパディングがあるとは考えられないため、現時点ではこれを受け入れられないのではないかと心配しています(ただし、〜1.5kBでは、そのまま挿入するだけで問題はありません)過度に!)。私はこのマシンにPerlを持っていませんが、今日これをテストする方法を見つけようとするので、それが適切な時間枠で動作し実行されることを確認し、報告します!
VisualMelon

1
@VisualMelon問題ありません。入力方法を変更し、手動でパディングを追加しました。大きなパズルでは爆発する傾向がありますが、ほとんどのテストケースでは妥当な時間枠で実行されます。
クリス

まだこれをテストしていませんが、これは正規表現を使用して側面または底面から外れたことを検出すると言いましたが、上に逃げることもできます(この目的のために追加されたtestcase10を参照してください)これ
VisualMelon

1
@VisualMelonああ、私は屋根から脱出するために、脱出者が部屋の上に乗ってから、屋根から離れて横に歩かなければならないと思いました。現在、関連する文が表示されています。私はそれを修正します:)
クリス

2
TIOリンクを追加できますか?
Programmer5000

3

C#、1814 1481 1395バイト

なんてスロー!私はこれに今かなり満足しています!

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

オンラインで試す

完全なプログラム。STDINへの入力、STDOUTへの出力を受け取ります。基本的に元のソルバーを書き直し、シンプルで非効率的に実装されたBFSを使用して最適なパスを見つけます。それは適度に高速で、他の実装よりも遅くなることはありません(実際には時間を計りませんでした)、確かに制限時間内に実行されます。コストの多くは、名前、「一致/スマッシュ」マップ、および使用可能な各アクションの他のプロパティを記録するコンマ区切り値としてエンコードされるアクションテーブルです。

それは、成功の最小確率とマップを読み込むことから始まります。次に、脱走者を特定し、地図から彼を削除し、この情報を含む「検索状態」を作成します。次に、BFSを実行します。これにより、次の適切な状態が最小限の労力で繰り返し確認されます(最適なソリューションが見つかるようにします)。ノードを展開する前に、同じマップとエスケープされた場所を持つ以前のノードとの努力と成功の確率を比較し、この状態へのより良いルートがすでに見つかった場合、それ自体を拒否します。これを生き残った場合、それは「見える」テーブルに自分自身を追加し、後で状態を拒否できるようにします。これはすべてパフォーマンスのためであり、それなしでは分岐要素は非常に大きくなります。次に、脱走者が地図から外れているかどうかを確認します。もしそうなら、それは勝ちです!BFSループを終了する前に、状態をバックトラックし(以前の各状態が各状態とともに記録されます)、プランを構築します(逆に)。それ以外の場合、すべてのアクションを適用しようとし、適用可能なアクションを追加しますdue このキューを並べ替えてから、次の反復で最小の労力状態を取得します。

書式設定されコメントされたコード:

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

良くやった!あなたの古いスコアと新しいスコアがお互いのアナグラムであることは私を無限に楽しませてくれます... lol
HyperNeutrino

C#はPerlに勝っていますか?
エソランジングフルーツ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.