Office Escape: Lên kế hoạch cho bạn!


32

Đó là lần chạy nước rút cuối cùng ... và một nửa đội của bạn bị ốm. Bạn đang làm việc muộn, chỉ thực hiện cam kết cuối cùng trong ngày, mong chờ ... tại sao đèn lại tắt? Tôi không nhớ anh chàng an ninh đến đây ... ồ không! Tôi để chìa khóa ở nhà!

Khi nỗi kinh hoàng của tình huống chìm vào, bạn quyết định rằng mình sẽ trốn thoát .

Tóm tắt nhiệm vụ

Để thực hiện lối thoát của bạn, bạn cần một kế hoạch! Tuy nhiên, bạn biết rằng bất kỳ kế hoạch nào cũng có cơ hội thất bại, và các kế hoạch khác nhau đòi hỏi số lượng nỗ lực khác nhau.

Vì đói, mệt, và là một kỹ sư, bạn quyết định viết một chương trình ngắn để xác định cách tốt nhất để thoát khỏi sự phức tạp, cân bằng các mối quan tâm về xác suất thành công và nỗ lực cần có.

Bạn tạo một bản đồ của tòa nhà:

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

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

Để thoát khỏi văn phòng, bạn sẽ phải tự di chuyển khỏi bản đồ. Ở đây bạn thấy có 2 cửa sổ ( !), một trong hai sẽ dẫn bạn đến tự do, nhưng chỉ một trong số chúng có thể truy cập được. Chúng tôi xác định 'ra khỏi bản đồ' là đặt chân bạn ra ngoài giới hạn của bản đồ

Các loại tế bào

  - 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

Các tế bào ban đầu được tiêu thụ bởi escapee được để trống.

Thông số kỹ thuật hành động

Bạn có một số hành động có thể có sẵn của bạn. Chúng được xác định bởi các chuyển đổi trạng thái đơn giản với một số xác suất thành công số nguyên. Ví dụ, để đi bộ, bạn di chuyển một ô thoát, mà chúng tôi đại diện cho quá trình chuyển đổi này:

Bậc thang

1 stp, 100%, gương

 o.            o
 |.   -->      |
 #            #

Các dấu chấm cho thấy các ô phải trống (hoặc có thể leo lên, nhưng không rắn hoặc có thể phá hủy) vì chúng ta di chuyển vào trong nó hoặc xuyên qua nó. 100% có nghĩa là bạn có 100% cơ hội không làm tổn thương chính mình và kết thúc cuộc trốn thoát táo bạo của bạn. Tất cả các xác suất sẽ là tỷ lệ phần trăm nguyên từ 1% đến 100%. Sơ đồ đầu tiên cho thấy trạng thái ban đầu (đứng trên một cái gì đó rắn, đứng bên cạnh một khoảng trống). Sơ đồ thứ hai hiển thị trạng thái thiết bị đầu cuối (di chuyển vào không gian trống). Không có yêu cầu cho bất kỳ ô không xác định (khoảng trắng ) nào ở bên trái (trạng thái ban đầu) là bất cứ điều gì cụ thể. Các ô không xác định (không gian,) ở bên phải (trạng thái thiết bị đầu cuối) phải giống như trước (ví dụ: bất cứ thứ gì đứng sau người thoát hiểm, hoặc bất cứ điều gì tôi tình cờ bước tới (có thể là không gian trống hoặc mặt khác). ) sơ đồ sẽ chỉ thay đổi các ô từ bị phá hủy thành trống, không có thay đổi nào khác có thể xảy ra. "1 ​​stp" có nghĩa là nó tốn 1 stp: chúng tôi xác định "stp" là lượng năng lượng cần thiết để thực hiện một bước.

"Gương" có nghĩa là hành động này có hai hình thức. Hành động "phải" được hiển thị, hành động "trái" là một tấm gương chính xác, ví dụ:

.o
.|
 # 

là dạng gương (Trái) của

o.
|.
# 

Hành động bên phải được gọi là "Phải" (ví dụ: "Bước phải") Hành động bên trái được gọi là "Trái" (ví dụ: "Bước trái")

Trong các sơ đồ này, escapee được hiển thị bởi

o
|

khi đứng (cao 2 đơn vị) và

%

khi cúi xuống (cao 1 đơn vị). Các tế bào phải rắn hoặc có thể phá hủy được biểu thị bằng hàm băm , #. Các tế bào không phải là rắn hoặc phá hủy được chỉ định bởi một dấu chấm .. Các tế bào phải bị phá hủy được chỉ định bởi một tiếng nổ !. Một không gian trống mới được tạo được hiển thị bởi một dấu gạch dưới _. xlà một điểm tham chiếu không di chuyển (nó không tồn tại, không có ràng buộc đối với ô đó phải là gì (như một khoảng trắng )).

Lưu ý: chúng tôi bỏ qua vấn đề giảm tốc nhanh khi bạn chạm sàn và vâng, trong trò chơi này, bạn có thể thực hiện cú nhảy hoàn toàn sử thi lên thang)

Bậc thang

1 stp, 100%, gương

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

Trèo xuống

1 stp, 100%, gương

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

Xáo trộn

3 stp, 100%, gương

 %.         %
x#   -->  x# 

Ngao lên

10 stp, 95%, gương

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

Rơi vãi

0 stp, 100%

 o         
 |  -->   o
x.       x|

Thả (Đứng)

0 stp, 100%

 %        o
x.  -->  x|

Trèo lên

2 stp, 100%

 =        o
 o  -->   |
x|       x

Ngọa tào

2 stp, 100%

 o
 |  -->   %
x#       x#

Đứng

4 stp, 100%

 .        o
 %  -->   |
x#       x#

Nhảy ngắn

4 stp, 95%, gương

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

Nhảy xa

7 stp, 75%, gương

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

Nhảy cao

12 stp, 90%, gương

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

Đặt lưng vào đó!

20 stp, 80%, gương

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

Cú đấm

8 stp, 90%, gương

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

Đá

8 stp, 85%, gương

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

Con tem

8 giây, 90%

 o        o
 |  -->   |
x!       x_

Các kế hoạch

Một kế hoạch là một chuỗi các hành động được xác định ở trên. Ví dụ:

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

Lưu ý bao gồm các giọt. Các quy tắc nên được thiết lập để ngăn bạn làm bất cứ điều gì trừ bỏ, nhưng bạn vẫn phải lập kế hoạch cho nó!

Bất kỳ kế hoạch nào cũng có một nỗ lực cần thiết, đó là tổng của những nỗ lực cho từng bước. Ngoài ra còn có một xác suất thành công, là sản phẩm của xác suất thành công của mỗi hành động. Ví dụ đơn giản:

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%

Một 'ví dụ hoạt động' cho bản đồ ở đầu trang có thể được tìm thấy dưới dạng ý chính .

Đầu vào

Đầu vào có hai phần, một số nguyên và một mảng hoặc chuỗi ký tự.

Số nguyên là xác suất thành công tối thiểu (phần trăm) được chấp nhận của bạn. Nó được hiểu là tỷ lệ phần trăm, vì vậy 80 có nghĩa là kế hoạch của bạn phải thành công với xác suất không dưới 80%.

Bản đồ hợp lệ là một hình chữ nhật bao gồm thoát hiểm đứng (kích thước tối thiểu 1x2) và không có ký hiệu không xác định. Tất cả các hàng sẽ có cùng chiều dài. Bạn có thể chấp nhận đầu vào dưới dạng một chuỗi phân cách 1 chiều (dấu phân cách phải là một ký tự nhất quán hoặc một trong các cặp CRLF và LFCR), như một mảng 1 chiều tương tự hoặc một mảng 2 chiều. Nếu định dạng đầu vào được chọn của bạn không biểu thị chiều rộng hoặc chiều cao của bản đồ theo một cách nào đó, bạn có thể chấp nhận các đối số bổ sung cho các đối số này (bạn phải nêu rõ điều này trong câu trả lời của mình). Bạn có thể trộn các đối số dòng lệnh và đầu vào tiêu chuẩn nếu nó phù hợp với bạn (ví dụ: ánh xạ từ stdin, xác suất thành công tối thiểu từ argv). Dưới đây là ví dụ bản đồ hợp lệ và không hợp lệ.

Có hiệu lực:

o
|

Có hiệu lực:

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

Không hợp lệ (không có escapee):

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

Không hợp lệ (escapee luôn bắt đầu đứng):

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

Không hợp lệ (ký hiệu không hợp lệ):

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

Không hợp lệ (không phải hình chữ nhật / hàng có độ dài khác nhau):

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

Bạn có thể cho rằng đầu vào của bạn là hợp lệ (Tôi không quan tâm chương trình của bạn sẽ làm gì nếu nó được trao đầu vào không hợp lệ).

Đầu ra

Đầu ra là văn bản (ASCII). Có thể được trả lại dưới dạng chuỗi hoặc in ra đầu ra tiêu chuẩn. Kế hoạch phải được phân định bởi một LF, CRLF hoặc LFCR. Tương tự, phải có một LF, CRLF hoặc LFCR khác sau nỗ lực cần thiết. Một ngắt dòng là tùy chọn.

Bạn phải đưa ra một kế hoạch tối ưu cùng với nỗ lực cần có hoặc "Không có hy vọng!" nếu không có kế hoạch như vậy tồn tại Bạn không cần phải đưa ra xác suất thành công. Văn bản này có thể có hoặc không có ngắt dòng.

Một kế hoạch tối ưu được định nghĩa là một kế hoạch (xem ở trên) đòi hỏi nỗ lực tối thiểu với ít nhất xác suất thành công nhất định. Lưu ý rằng tính toán xác suất của bạn phải chính xác, bạn có thể không cho rằng dấu phẩy động là đủ tốt (Đây là lý do tại sao tôi không mong đợi bạn xuất chúng). Tôi sẽ cố gắng thiết kế các trường hợp kiểm tra để kiểm tra một cách công bằng điều này (nếu bạn vượt qua chúng và không đưa ra bất kỳ giả định nào thì bạn có thể xem xét việc gửi của mình hợp lệ).

Định dạng:

Required Effort: <effort>
<plan>

Ví dụ: cho đầu vào

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

Một đầu ra thích hợp sẽ là:

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

Xác suất thành công ở đây là 76,5%.

Đối với cùng một bản đồ, nhưng xác suất thành công tối thiểu là 80%, bạn sẽ phải "Đặt lưng vào đó", điều này đòi hỏi nhiều nỗ lực hơn nhưng hoàn thành tiêu chí xác suất thành công. Nếu xác suất thành công tối thiểu lớn hơn 80%, bạn cần suy nghĩ kỹ hơn một chút (đấm hoặc đá qua một phần cánh cửa và lách ra). Nếu xác suất thành công tối thiểu là 100%, bạn sẽ phải in ra "Không có hy vọng!"

Ví dụ

Có thể có nhiều hơn một gói hợp lệ cho một đầu vào, đầu ra của bạn không cần phải chính xác, nhưng nó phải có nỗ lực cần thiết chính xác và là một kế hoạch hợp lệ. Bạn có thể sử dụng trình xác minh để kiểm tra các giải pháp của mình (xem bên dưới)

Đầu vào:

100
o
|

Đầu ra:

Required Effort: 0
Drop

Đầu vào:

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

Đầu ra:

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

Đầu vào:

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

Đầu ra:

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

Đối với cùng một bản đồ, nhưng 80%, đầu ra phải là:

There is no hope!

Đối với cùng một bản đồ, nhưng 50%, nỗ lực cần thiết trở thành 56 với một kế hoạch khác)

Đầu vào:

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

Đầu ra:

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

Đầu vào:

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

Đầu ra:

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

Đầu vào:

Cái này được thiết kế để kiểm tra một số giả định sai mà người ta có thể trở thành nạn nhân, và do đó có thể trông hơi kỳ quặc

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

Đầu ra với cơ hội hạn chế thành công 30:

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

Đầu ra với cơ hội hạn chế thành công 32:

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

Sử dụng bản đồ ở trên cùng làm đầu vào, với xác suất ràng buộc thành công 1%, bạn sẽ nhận được Nỗ lực cần thiết là 116 (cơ hội thành công ~ 32%, điều này mất khoảng 20 giây để chạy trong chương trình thử nghiệm của tôi).

Tiêu chí chiến thắng

Đây là môn đánh gôn, có thể là đoạn mã ngắn nhất sẽ thắng.

Để đủ điều kiện, chức năng hoặc chương trình của bạn phải hoạt động và có thể giải quyết từng thử nghiệm trên trong vòng dưới 30 phút trên một máy hợp lý. Người giải quyết của tôi làm chúng mỗi trong dưới 30 giây. Nếu tập lệnh kiểm tra (bên dưới) chạy trong dưới 30 phút, bạn chắc chắn sẽ ổn.

Ví dụ Trình giải, Trình xác minh, Tập lệnh kiểm tra và TestCase (có giải pháp)

Mã C # cho người giải và trình xác minh giải pháp, có sẵn ở đây dưới dạng ý chính . Các ý chính cũng chứa file.txt, là một dạng máy có thể đọc được (đủ) của các hành động được mô tả ở trên và được yêu cầu để chương trình chạy. Bất kỳ sự khác biệt giữa tập tin đó và thông số kỹ thuật là không cố ý.

Ý chính cũng chứa một số trường hợp thử nghiệm (bao gồm tất cả các ví dụ ở trên) và tập lệnh PowerShell để tự động chạy đệ trình chống lại chúng. Nếu tập lệnh cho bạn biết rằng một thử nghiệm cụ thể đã thất bại, bạn có thể chạy OfficeEscapeSolver.exe testcase<n>.txt outputFromYourProgram.txtđể xem thêm chi tiết. Các giải pháp ví dụ cho các trường hợp thử nghiệm này nằm trong một Gist khác .

Tất cả các mã là một mớ hỗn độn (mặc dù không được mã hóa), nhưng bạn không cần phải đi xa static void Main(...)để thay đổi số lượng đầu ra (hãy sử dụng thông tin này, tôi đã cung cấp nó vì lợi ích của bạn!).

Vượt qua một trường hợp thử nghiệm không nhất thiết có nghĩa là đầu ra của bạn được hình thành tốt, vì tập lệnh và trình xác minh rất hào phóng. Đầu ra của bạn phải phù hợp với đặc điểm kỹ thuật ở trên để trình của bạn có hiệu lực.

Nếu bạn nghĩ rằng bạn đã tìm thấy một lỗi với người giải hoặc bản kiểm tra, một lỗi trong file.txthoặc một bản kiểm tra tinh ranh, thì vui lòng nhận xét về bài đăng này hoặc nếu không ping tôi trên SE Chat; Tôi có lẽ sẽ không nhận thấy bất kỳ nỗ lực nào khác để giao tiếp.

Tôi sẽ không cung cấp tập lệnh thử nghiệm trong Bash hoặc Batch, vì tôi không biết chúng, nhưng tôi rất vui khi bao gồm một bản dịch và sẽ viết một phiên bản C # nếu mọi người muốn.

Bài viết có thể

Có câu hỏi nào không? Đừng trì hoãn, hãy hỏi họ ngay hôm nay!

Nhiệm vụ này có nghĩa là đòi hỏi nỗ lực , để cung cấp cho những người chơi golf nghiêm túc một cái gì đó để chìm vào răng của họ.

Tôi cảm ơn ais523 vì phản hồi của anh ấy về Đầu vào / Đầu ra.

Tôi có thể cung cấp thêm các testcase trong tệp chính nếu mọi người muốn nhiều hơn (không muốn bài đăng này trở nên dài hơn) hoặc muốn cung cấp một số của riêng họ.


2
Thử thách lớn! Tôi chắc chắn sẽ cung cấp cho một shot này khi tôi có thời gian. :)
R. Kap

Bạn biết đấy, sự nguy hiểm của việc rơi (hay đúng hơn là giảm tốc nhanh ở phía dưới) có thể đã được mô hình hóa bằng cách cho phép chuyển tiếp thả có xác suất 95% hoặc hơn. ;) Thử thách đẹp!
Martin Ender

bạn có thể trốn thoát dù đèn trời hay đường hầm? tức là trên cùng và dưới cùng của lĩnh vực? hay chỉ trái hay phải?
Moogie

@Moogie bạn thực sự có thể! Miễn là đôi chân của bạn được tự do, bạn được tự do (ví dụ: xem thử nghiệm 1x2, trong đó giải pháp chỉ là thả một lần). Tôi sẽ thêm một testcase nhỏ vào ý chính để kiểm tra đi ra khỏi trần nhà.
VisualMelon

3
Đã thêm tiền thưởng cho câu hỏi. Đây là một câu hỏi tuyệt vời mà xứng đáng có câu trả lời.
lập trình

Câu trả lời:


3

Perl 5, 1425 1464 1481 1469 1485 1438 byte

Đó là một thử thách thú vị! Và thật đáng kinh ngạc, có vẻ như tôi có mã ngắn nhất cho đến nay chỉ dưới 1,5kB! :)

Khá chắc chắn rằng cuối cùng tôi đã làm việc này. Dấu phân cách được sử dụng là :, và có thêm phần đệm của hai hàng trên cùng và một cột ở hai bên . Vì vậy, cho đầu vào của bạn về:

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

chương trình của tôi sẽ mất: (NB: phải có dấu hai chấm ở cuối, nhưng không phải ở đầu!)

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

Tôi sử dụng regexes để dịch từ bản đồ này sang bản đồ khác và giải quyết bằng vũ lực. Tuy nhiên, tôi không thêm bản đồ vào danh sách nếu bản đồ đó đã đạt được với ít nỗ lực hơn và xác suất lớn hơn hoặc bằng nhau. Bản đồ được xóa khỏi danh sách một khi tất cả các chuyển động có thể từ thời điểm đó đã hết. Chương trình kết thúc thành công khi nó phù hợp với biểu thức chính quy cho thấy tôi đã đạt được phía bên hoặc phía dưới và kết thúc bằng "Không có hy vọng!" khi danh sách bản đồ cạn kiệt.

Thật không may, có rất nhiều hiệu quả được giao dịch để lấy đi một vài byte, vì vậy phiên bản chơi golf khá chậm;) Perl dường như thấy các evals đặc biệt khá đau đớn.

Không cần quảng cáo thêm,

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

Vì lợi ích của sự tỉnh táo, đây là điều tương tự với các dòng mới và một vài bình luận:

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)

Tôi đã có thể thấy một vài nơi để giảm bớt một vài byte, nhưng tôi chưa muốn trải qua tất cả các thử nghiệm nữa. Một lát sau! :)

Chỉnh sửa: Đã thêm một số phần đệm bên dưới để phù hợp với đầu ra của bạn chính xác hơn khi thoát qua sàn. Đã xóa một số evals, vì vậy mã cũng có thể chạy nhanh hơn bây giờ!

Chỉnh sửa: Không xử lý thang và giảm hoàn toàn đúng. Vẫn không xử lý thang hoàn toàn đúng ... Đang cố gắng khắc phục điều đó ngay bây giờ.


Vui mừng khi có người khác vui vẻ với nó! Tôi sợ rằng tôi không thể chấp nhận điều này như hiện tại, vì bạn không thể cho rằng đầu vào có thêm các hàng hoặc phần đệm ở trên cùng (nhưng ở mức ~ 1,5kB, chỉ cần chèn ngay lập tức sẽ không bị tổn thương quá nhiều!). Tôi không có Perl trên máy này, nhưng tôi sẽ thử và tìm cách kiểm tra cái này ngay hôm nay, vì vậy tôi có thể kiểm tra nó hoạt động và chạy trong khung thời gian hợp lý và báo cáo lại!
VisualMelon

1
@VisualMelon Không có vấn đề gì, tôi đã thay đổi phương thức nhập liệu và thêm phần đệm vào bằng tay. Nó không có xu hướng nổ tung trong các câu đố lớn hơn, nhưng nó chạy trong một khung thời gian hợp lý cho hầu hết các trường hợp thử nghiệm của bạn.
Chris

Vẫn chưa thử nghiệm điều này, nhưng tôi lưu ý rằng bạn nói rằng điều này sử dụng regex để phát hiện khi bạn đi từ bên cạnh hoặc phía dưới, nhưng bạn cũng có thể thoát khỏi đầu (xem testcase10 được thêm vào cho mục đích này), chỉ trong trường hợp bạn bỏ lỡ này
VisualMelon

1
@VisualMelon Ah, tôi cho rằng để thoát khỏi mái nhà, người trốn thoát sẽ phải lên trên phòng và sau đó đi bộ sang một bên, ra khỏi mái nhà. Tôi thấy câu liên quan bây giờ. Tôi sẽ sửa nó :)
Chris

2
Bạn có thể thêm một liên kết TIO?
lập trình

3

C #, 1814 1481 1395 byte

Thật là một khẩu hiệu !! Tôi thực sự khá hài lòng với điều này bây giờ!

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

Dùng thử trực tuyến

Hoàn thành chương trình, đưa đầu vào vào STDIN, đầu ra thành STDOUT. Về cơ bản là viết lại bộ giải gốc của tôi, sử dụng BFS đơn giản và không hiệu quả để tìm đường dẫn tối ưu. Nó khá nhanh, không thể chậm hơn nhiều so với triển khai khác của tôi (mặc dù tôi chưa thực sự hẹn giờ), chắc chắn chạy trong giới hạn thời gian. Phần lớn chi phí là bảng Hành động, được mã hóa thành các giá trị riêng biệt bằng dấu phẩy ghi lại tên, bản đồ 'khớp / đập' và các thuộc tính khác của mỗi hành động khả dụng.

Nó bắt đầu bằng cách đọc trong xác suất thành công tối thiểu và bản đồ. Sau đó, nó xác định vị trí người trốn thoát, xóa anh ta khỏi bản đồ và tạo ra một 'trạng thái tìm kiếm' chứa thông tin này. Sau đó, nó thực hiện BFS, liên tục xem xét trạng thái do tiếp theo với nỗ lực ít nhất (đảm bảo nó tìm ra giải pháp tối ưu). Trước khi mở rộng nút, nó so sánh nỗ lực và xác suất thành công của nó với các nút trước đó có cùng vị trí và bản đồ thoát hiểm và từ chối chính nó nếu đã tìm thấy tuyến đường tốt hơn cho trạng thái này. Nếu nó tồn tại điều này, nó sẽ tự thêm vào bảng 'đã thấy' để nó có thể từ chối trạng thái sau này. Đây là tất cả cho hiệu suất, và nếu không có nó, yếu tố phân nhánh sẽ rất lớn. Sau đó, nó kiểm tra xem escapee có ở ngoài bản đồ không. Nếu có, thì nó thắng! Nó theo dõi lại trạng thái (mỗi trạng thái trước được ghi lại với mỗi trạng thái) và xây dựng kế hoạch (ngược lại) trước khi thoát khỏi vòng lặp BFS. Mặt khác, nó cố gắng áp dụng mọi hành động và thêm bất kỳ hành động nào có thể được áp dụng chodue xếp hàng, trước khi sắp xếp hàng đợi này để chúng ta có được trạng thái lặp lại ít nỗ lực nhất.

Mã định dạng và nhận xét:

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

Công việc tốt! Điều thú vị với tôi là điểm số cũ và điểm số mới của bạn là đảo chữ của nhau ... lol
HyperNeutrino

C # đã đánh bại Perl?
Esolanging Fruit
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.