사무실 탈출 : 탈출구를 계획하세요!


32

마지막 스프린트이고 팀의 절반이 아프다. 당신은 늦게 일하고 있고, 하루 동안 마지막 커밋을 만들고, 기대하고 있습니다 ... 왜 조명이 꺼졌습니까? 보안 요원이 다가오는 것을 기억하지 못합니다. 열쇠를 집에 두었습니다!

상황의 공포가 가라 앉을 때, 당신은 탈출하려고 결정합니다 .

작업 요약

탈출을 위해서는 계획이 필요합니다! 그러나 계획이 실패 할 가능성이 있으며 계획마다 다른 노력이 필요하다는 것을 알고 있습니다.

배고프고 피곤하며 엔지니어이기 때문에 성공 가능성에 대한 우려와 필요한 노력의 균형을 맞추면서 복잡한 프로그램을 피하는 가장 좋은 방법을 결정하는 간단한 프로그램을 작성하기로 결정했습니다.

건물의지도를 만듭니다.

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

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

사무실을 탈출하려면지도에서 벗어나야합니다. 여기에는 2 개의 창이 있습니다 ( !). 둘 중 하나는 자유로 이어지지 만 그 중 하나만 액세스 할 수 있습니다. 우리는 '지도 밖으로'를 발이지도의 경계 밖에있는 것으로 정의합니다.

세포 유형

  - 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 stp, 100 %, 거울

 o.            o
 |.   -->      |
 #            #

점은 세포가 이동하거나 통과하기 때문에 비어 있어야합니다 (또는 올라갈 수 있지만 단단하거나 파괴 할 수없는). 100 %는 자신이 다 치지 않고 대담한 탈출을 끝내지 않을 확률이 100 %임을 의미합니다. 모든 확률은 1 %에서 100 % 사이의 정수 백분율입니다. 첫 번째 다이어그램은 초기 상태를 보여줍니다 (빈 공간 옆에 서있는 단단한 물체 위에 있음). 두 번째 다이어그램은 터미널 상태 (빈 공간으로 이동)를 보여줍니다. 왼쪽 (초기 상태)의 지정되지 않은 셀 (공백, )에 대한 요구 사항 은 특별히 없습니다. 지정되지 않은 셀 (공간,) 오른쪽 (터미널 상태)은 이전과 같아야합니다 (예 : 탈출 자 뒤에 있던 것 또는 내가 밟고있는 모든 것 (빈 공간이거나 다른 것)) 모든 오른쪽 (터미널 상태) ) 다이어그램은 파괴 가능한 셀에서 빈 셀로만 변경되며 다른 변경은 발생하지 않습니다. "1 stp"는 1 stp의 비용을 의미합니다. "stp"는 단계를 수행하는 데 필요한 에너지 량으로 정의합니다.

"미러"는이 동작이 두 가지 형태를 가짐을 의미합니다. "오른쪽"동작이 표시되고 "왼쪽"동작은 정확한 미러입니다. 예를 들면 다음과 같습니다.

.o
.|
 # 

거울 (왼쪽) 형식입니다

o.
|.
# 

오른쪽 동작은 "오른쪽"(예 : "오른쪽 단계")입니다. 왼쪽 동작은 "왼쪽"(예 : "왼쪽 단계")입니다.

이 다이어그램에서 이스케이프는

o
|

서있을 때 (키 2 개)

%

몸을 구부릴 때 (1 단위). 단단하거나 파괴 가능한 셀은 해시로 표시됩니다 #. 단단하거나 파괴 할 수없는 셀은 점으로 표시됩니다 .. 파괴 가능해야하는 세포는 강타로 표시됩니다 !. 새로 작성된 빈 공간은 밑줄로 표시됩니다 _. x는 움직이지 않는 참조 점입니다 (존재하지 않으며 해당 셀이 무엇인지에 대한 제약이 없습니다 (space와 같은 )).

참고 : 우리는 바닥에 닿았을 때 빠른 감속 문제를 무시하고 그렇습니다.이 게임에서는 사다리로 완전히 장엄한 점프를 할 수 있습니다)

단계

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%

페이지 상단의지도에 대한 '실제 예제' 는 요점 으로 찾을 수 있습니다 .

입력

입력은 정수와 배열 또는 문자열로 구성됩니다.

정수는 귀하의 최소 허용 확률 (%)입니다. 백분율로 해석되므로 80은 계획이 80 % 이상의 확률로 성공해야 함을 의미합니다.

유효한 맵은 스탠딩 이스케이프 (최소 크기 1x2)를 포함하고 지정되지 않은 기호가없는 사각형입니다. 모든 행의 길이는 같습니다. 입력을 1 차원 구분 문자열 (구분자는 단일 일관된 문자이거나 CRLF 및 LFCR 쌍 중 하나 여야 함), 유사한 1 차원 배열 또는 2 차원 배열로 사용할 수 있습니다. 선택한 입력 형식이 어떤 식 으로든 맵의 너비 나 높이를 나타내지 않는 경우 추가 인수를 사용할 수 있습니다 (답변에 명확하게 명시해야 함). 명령 행 인수와 표준 입력이 자신에게 적합한 경우 혼합 할 수 있습니다 (예 : stdin의 맵, argv의 최소 성공 확률). 다음은 유효하고 유효하지 않은 맵의 예입니다.

유효한:

o
|

유효한:

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

유효하지 않음 (이스케이프 없음) :

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

유효하지 않음 (탈출이 항상 시작됩니다) :

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

유효하지 않은 (유효하지 않은 기호) :

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

유효하지 않습니다 (직사각형 / 다른 길이의 행이 아님) :

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

입력 내용이 유효하다고 가정 할 수 있습니다 (잘못된 입력을 받으면 프로그램이 수행하는 작업은 중요하지 않습니다).

산출

출력은 텍스트 (ASCII)입니다. 문자열로 반환되거나 표준 출력으로 인쇄 될 수 있습니다. 계획은 LF, CRLF 또는 LFCR로 구분되어야합니다. 마찬가지로, 필요한 노력 후에 다른 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 # 코드 및 솔루션 검증 도구는 여기서 gist로 사용할 수 있습니다 . 요지에는 또한 file.txt위에서 설명한 동작을 읽을 수있는 (충분한) 형태의 프로그램이 포함되어 있으며 프로그램을 실행하는 데 필요합니다. 해당 파일과 사양이 일치하지 않습니다.

요지는 또한 여러 가지 테스트 사례 (위의 모든 예제 포함)와 이에 대한 제출을 자동으로 실행하는 PowerShell 스크립트를 포함합니다. 스크립트가 특정 테스트에 실패했음을 알려 주면 OfficeEscapeSolver.exe testcase<n>.txt outputFromYourProgram.txt자세한 내용을 볼 수 있습니다 . 이러한 테스트 사례에 대한 예제 솔루션은 다른 요지에 있습니다.

모든 코드는 완전한 엉망이지만 (골프가 풀리지는 않지만) 출력량 static void Main(...)을 변경하기 위해 멀리 벗어날 필요는 없습니다 (이 정보를 자유롭게 사용하십시오, 나는 당신의 이익을 위해 그것을 제공했습니다!).

테스트 사례를 통과했다고해서 스크립트와 검증자가 매우 관대하기 때문에 출력이 제대로 구성되어있는 것은 아닙니다. 제출물이 유효하려면 출력물이 위의 사양과 일치해야합니다.

솔버 나 테스트 스크립트에 버그가 있거나,에 오류가 file.txt있거나, dodgy 테스트 케이스 가 있다고 생각되면 이 게시물에 댓글을 달거나 SE Chat에 나를 핑하십시오. 아마도 다른 의사 소통 시도는 눈치 채지 못할 것입니다.

나는 Bash 또는 Batch로 테스트 스크립트를 제공하지 않을 것입니다. 알 수 없기 때문에 번역을 포함하게되어 기쁘고 사람들이 원하는 경우 C # 버전을 작성하게됩니다.

포스트 앰블

질문이 있습니까? 지체하지 말고 오늘 물어보십시오!

이 작업은 진지한 골퍼들에게 양치질 할 무언가를주기 위해 노력필요합니다 .

입력 / 출력에 대한 피드백에 대해 ais523에게 감사드립니다.

사람들이 더 많은 것을 원하거나 (이 게시물이 더 이상되기를 원하지 않는 경우) 더 많은 테스트 케이스를 제공 할 수 있습니다.


2
큰 도전! 나는 시간이있을 때 확실히이 샷을 줄 것이다. :)
R. Kap

낙하 전이에 95 % 정도의 확률을 부여함으로써 낙하의 위험 (또는 바닥의 빠른 감속)을 모델링 할 수 있습니다. ;) 좋은 도전!
Martin Ender

천공이나 터널을 통해 탈출 할 수 있습니까? 즉, 필드의 상단과 하단? 아니면 왼쪽이나 오른쪽?
Moogie

@Moogie 당신은 실제로 할 수 있습니다! 발이 비어있는 한 자유 롭습니다 (예 : 솔루션이 한 번만 떨어지는 1x2 테스트 케이스 참조). 천장에서 떨어지는 것을 테스트하기 위해 작은 테스트 케이스를 추가하겠습니다.
VisualMelon

3
질문에 현상금을 추가했습니다. 이것은 답변이 필요한 훌륭한 질문입니다.
programmer5000

답변:


3

Perl 5, 1425 1464 1481 1469 1485 1438 바이트

재미있는 도전이었습니다! 그리고 놀랍게도, 지금까지 1.5kB 미만의 코드가 가장 짧은 것 같습니다! :)

내가 마침내이 일을했다고 확신합니다. 사용 된 분리 문자는 :상단에 두 개의 행과 양쪽에 하나의 열이 추가로 채워집니다 . 따라서 다음을 입력하십시오.

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

내 프로그램은 다음과 같습니다. (NB : 끝에 콜론이 있어야하지만 처음에는 없어야합니다!)

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

정규 표현식을 사용하여 한 맵에서 다른 맵으로 변환하고 무차별 대입으로 해결합니다. 그러나 적은 노력과 더 크거나 같은 확률로 해당 맵에 도달 한 경우 목록에 맵을 추가하지 않습니다. 해당 지점에서 가능한 모든 움직임이 소진되면 목록에서 맵이 제거됩니다. 프로그램이 정규식과 일치하면 성공적으로 종료됩니다. 정규식과 일치하면 측면이나 하단에 도달했으며 "희망이 없습니다!"로 끝납니다. 지도 목록이 소진 된 경우

불행히도, 몇 바이트를 없애기 위해 많은 효율성이 떨어져 나갔기 때문에 골프 버전은 다소 느리다.

더 이상 고민하지 않고

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 문제 없음, 입력 방법을 변경하고 패딩을 수동으로 추가했습니다. 더 큰 퍼즐에서 터지는 경향이 있지만 대부분의 테스트 사례에 적합한 시간 내에 실행됩니다.
Chris

여전히 이것을 테스트하지는 않았지만, 정규식을 사용하여 측면이나 바닥을 떠날 때 감지하지만 상단을 벗어날 수도 있습니다 ( 이 목적을 위해 추가 된 testcase10 참조 ). 이것
VisualMelon

1
@VisualMelon 아, 나는 지붕에서 탈출하기 위해 탈출자가 방의 꼭대기에 도착한 다음 지붕에서 옆으로 걸어 가야한다고 가정했습니다. 나는 지금 관련 문장을 본다. 수정하겠습니다 :)
Chris

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을 이겼습니까?
Esolanging 과일
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.