Một con chuột với thuốc nổ


23

Bạn là một con chuột. Tất cả bạn bè chuột của bạn đã bị bắt, và bất tỉnh và bị mắc kẹt trong một mê cung chỉ có một lối vào / lối ra. Bạn tình cờ có một bản đồ hoàn hảo của mê cung, vì vậy bạn có thể vạch ra một giải pháp để xông vào và mang tất cả đến nơi an toàn. Tuy nhiên, mê cung được bảo vệ với một hệ thống an ninh sẽ kích hoạt cảnh báo nếu 1000đạt đến ngưỡng , khiến bạn bị bắt và thất bại trong nhiệm vụ giải cứu.

Từ các nghiên cứu trước đây về mê cung của bạn, mỗi ô vuông bạn bước (nghĩa là mỗi chuyển động ngang hoặc dọc - chuột không thể di chuyển theo đường chéo ) thêm 1vào bộ đếm của hệ thống an ninh. Tuy nhiên, nếu bạn đang mang một vật nặng (có thể là một khối thuốc nổ hoặc một người bạn chuột vô thức), thì nó sẽ thêm vào 2vì nó phát hiện thêm áp lực. Quảng trường ra / vào không có hệ thống bảo mật này và do đó không thêm vào quầy.

Bạn có một nguồn cung cấp thuốc nổ không giới hạn mà bạn đã mang đến lối vào, vì vậy bạn chỉ cần thổi tung tất cả các bức tường để giải phóng bạn bè. Nhưng bạn cần thận trọng với việc đó, vì mỗi vụ nổ làm tăng thêm 50khả năng chống chịu áp lực. Ngoài ra, bạn chỉ có thể mang theo một thứ một lúc, một con chuột hoặc một khối thuốc nổ. Vì mỗi khối thuốc nổ chỉ có thể kích nổ một không gian tường, điều này có nghĩa là nếu có nhiều bức tường liên tiếp, bạn cần thực hiện một chuyến đi tay không trở lại lối vào để lấy thêm.

Ví dụ làm việc thông qua

Giả sử mê cung của chúng ta trông như sau:

######
#M# E#
######

Tôi sẽ sử dụng ccho quầy. Chúng tôi bắt đầu tại Entrance, di chuyển một hình vuông bên trái trong khi mang thuốc nổ , c=2. Chúng tôi kích nổ thuốc nổ để nổ tung bức tường c=52,. Chúng tôi di chuyển hai hình vuông sang trái, tay không, để lấy c=54và bây giờ chúng tôi đang đứng trên hình vuông của con chuột. Chúng tôi đón bạn mình và di chuyển 3 hình vuông trở lại Exit, nhưng hình vuông cuối cùng không được tính vì nó không có bất kỳ cảm biến nào, vì vậy đó chỉ là 2 hình vuông có thứ gì đó trên lưng. Điều đó có nghĩa là khi chúng ta đi đến lối ra với con chuột cuối cùng, c=58ít hơn 1000, và do đó nhiệm vụ thành công.

Thử thách

Đưa ra một mê cung đầu vào, đầu ra cho dù bạn, anh hùng chuột, có thể giải cứu thành công tất cả những con chuột bị mắc kẹt trong các ràng buộc được nêu ở trên, hoặc liệu nhiệm vụ có phải là một thất bại.

Đầu vào

  • Một mê cung 2D ở bất kỳ định dạng có thể chấp nhận (chuỗi đa dòng, mảng chuỗi, v.v.).
  • Đối với thử thách này, tôi sẽ sử dụng #cho cả tường bên trong và bên ngoài, Mcho những người bạn chuột và Echo lối vào.
  • Lối vào sẽ không bao giờ liền kề với một bức tường bên trong (sẽ luôn có ít nhất một không gian để di chuyển tự do).
  • Bạn có thể thay thế bất kỳ ký tự ASCII có thể in nào bạn muốn miễn là nó phù hợp. Điều này không cho phép bạn sử dụng hai biểu tượng khác nhau cho các bức tường bên trong so với các bức tường bên ngoài, miễn là bạn duy trì tính nhất quán (ví dụ: nếu bạn chọn sử dụng @cho các bức tường bên trong và để lại #cho bên ngoài, mọi bức tường bên trong phải @mọi bức tường bên ngoài #).
  • Mê cung sẽ luôn được bao bọc hoàn toàn bởi các bức tường, nhưng không nhất thiết phải là hình chữ nhật. Nếu muốn, bạn có thể giả sử rằng mê cung được đệm bằng khoảng trắng để tạo đầu vào hình chữ nhật (tùy chọn).
  • Mê cung có thể có các phần không thể truy cập mà không có thuốc nổ.
  • Bạn không thể kích hoạt các bức tường bên ngoài của mê cung.

Đầu ra

Một giá trị trung thực / falsey . Sự thật cho "Có, con chuột có thể giải cứu mọi con chuột khác" hoặc Falsey cho "Không, hệ thống báo động sẽ bị ngắt."

Những quy định

  • Một chương trình đầy đủ hoặc một chức năng được chấp nhận.
  • Sơ hở tiêu chuẩn bị cấm.
  • Đây là vì vậy tất cả các quy tắc chơi gôn thông thường đều được áp dụng và mã ngắn nhất (tính bằng byte) sẽ thắng.

Ví dụ

Ví dụ thật, cách nhau bởi các dòng trống.

#####
#M E#
#####

######
#M# E#
######

########
#E  # M#
#   #  #
#   #  #
#      #
########

#############################
#    ##      #       #      #
#  M ## M    #       #      #
#    ##      #   M   #    E #
#M   ##      #       #      #
#############################

###############
#MMMMMMMMMMMMM#
#MMMMMMMMMMMMM#
#MMMMMMMMMMMMM#
#MMMMMMMMMM MM#
#MMMMMMMMMMMME#
###############

Ví dụ Falsey, cách nhau bởi các dòng trống

#############################
#M   ##      ##      ##     #
#  M ## M    ##      ##     #
#    ##      ##  M   ##   E #
#M   ##      ##      ##     #
#############################
#############################
                     ########
                     ########
                     #   #  #
                     # M # M#
                     ########

              #####
              # M #
              #####
              #####
              #####
              #####
###################
# # # ##   ## # # #
#M#M#M## E ##M#M#M#
# # # ##   ## # # #
###################
#######
######
#####
####
# M#
####

###############
#MMMMMMMMMMMMM#
#MMMMMMMMMMMMM#
#MMMMMMMMMMMMM#
#MMMMMMMMMMMMM#
#MMMMMMMMMMMME#
###############


3
@AlexA. Xin lỗi vì bạn phải học nó từ một người lạ trên Internet. ;-)
admBorkBork

2
Tôi nghi ngờ hầu hết mọi người sẽ có một thời gian khó khăn để giải quyết điều này với mã thông thường, chứ đừng nói đến việc chơi golf. Đó là một thách thức lớn mà tôi không may hiện không có thời gian để làm việc.
Moshe Katz

2
Có thể chấp nhận có một char khác cho các bức tường bên ngoài (vì chúng không bị phá hủy)?
Tensibai

2
@Moshe Katz , chắc chắn bạn không có thời gian. Bạn không muốn cứu Mäuse.
msh210

Câu trả lời:


19

Perl, 216 215 byte

Bao gồm +2 cho -0p

Cung cấp đầu vào trên STDIN. Sử dụng %cho các bức tường bên ngoài, #cho các bức tường bên trong, 0cho các không gian trống, 8cho chuột và rcho vị trí bắt đầu. Toàn bộ các bảng phải được đệm để nó tạo thành một hình chữ nhật. Bạn có thể chuyển đổi và chạy các ví dụ như:

cat dynamite.txt | perl -p0e 's/.+/$a^=$&/egr;s//sprintf"%-*s",length$a,$&/eg;1while/\n/,s/^ *\K#|#(?= *$)|^ *.{@{-}}\K#|\A[^\n]*\K#|#(?=[^\n]*\n\z)|#(?=.{@{-}} *$)/%/sm;y/ EM/0x2/' | dynamite.pl

dynamite.pl:

#!/usr/bin/perl -0p
sub f{@a{@_}||=push@{$%+($&?$1?50:$&=~8?0:$&&"5"?2:1:0)},@_}f$_;for(@{$%}){f y/xr|/ytx/r;{f s/\pL\d/$&^(E&$&)x2/er}{f s/(q|s|y)#/$&^"\x01\x13"/er}my$o;{$\|=/x/>/2/;$o.="
"while s/.$/$o.=$&,""/meg}f$o}$%++>999|$\||redo}{

Thay thế các \xhhlối thoát cho số điểm yêu cầu.

Chương trình không thể xử lý thực tế các trường hợp phức tạp. Đặc biệt, nó không thể xử lý bất kỳ trường hợp thất bại. Điều này là do có quá nhiều cách khác nhau để làm nổ tung các bức tường bên trong hoặc nhặt chuột để tìm kiếm trở nên quá rộng và sử dụng quá nhiều bộ nhớ mặc dù ít nhất nó đủ thông minh để không bao giờ xử lý cùng một trạng thái nhiều lần. Giới hạn áp suất phải được hạ xuống 100hoặc hơn cho thời gian chạy và sử dụng bộ nhớ có thể chịu được.

Giải trình

Tôi sử dụng mẫu bit của một ký tự để thể hiện trạng thái của một trường:

contains victim: 0000 0010
has hero:        0100 0000
carry dynamite   0000 0001
carry mouse      0000 0100
home             0000 1000
walkable         0001 0000 (not really needed but results in shorter regexes)
make printable   0010 0000
wall             0010 xxxx (bit patterns not very important,
permawall        0010 xxxx  just avoid letters and digits)

Ví dụ, anh hùng ( 01000000) mang thuốc nổ ( 00000001) phải ở một nơi anh ta có thể đi bộ ( 00010000) và chúng tôi muốn tất cả các giá trị có thể in được ASCII ( 00100000). Lấy bitwise orcủa tất cả các bitmasks 01110001này là mã ASCII cho q. Tổng cộng điều này trở thành ::

p: hero                     r hero on victim
q: hero carrying dynamite   s hero carrying dynamite on victim
t: hero carrying mouse      v hero carrying mouse on victim

x : hero at home
y : hero at home carrying dynamite
| : hero at home carrying mouse

0: empty  without hero
8: home   without hero
2: victim without hero

%: permanent wall
#: normal wall

Chương trình sẽ chỉ xem xét anh hùng di chuyển sang phải (vòng quay được giải thích sau sẽ đảm nhiệm các hướng khác). Các bitmasks được chọn cẩn thận sao cho anh hùng luôn được đại diện bằng một chữ cái và một nơi anh ta có thể di chuyển đến bằng một chữ số (ngoại trừ anh hùng ở nhà mang theo một nạn nhân, nhưng một lần nữa điều này là cố ý để di chuyển duy nhất của anh hùng sẽ bị rơi nạn nhân). Vì vậy, một anh hùng có thể tiến về phía trước được kết hợp bởi /\pL\d/. Chuỗi con phù hợp phải được sửa đổi để anh hùng và những gì anh ta mang theo được xóa khỏi ký tự đầu tiên và thêm vào ký tự thứ hai, có thể được thực hiện với một bitwise xorvới cùng giá trị cho cả hai nhân vật. Giá trị xor bao gồm bit hero ( 01000000), bit nổ ( 00000001) và bit carry chuột ( 00000100). Họ cùng nhau orđến01000101đó là ASCII E. Vì vậy, di chuyển anh hùng trở thành:

s/\pL\d/$&^(E&$&)x2/e

Người anh hùng có thể làm nổ tung một bức tường nếu anh ta đứng ngay trước nó và đang mang thuốc nổ ( q, shoặc y). Người anh hùng sẽ mất thuốc nổ ( xorvới 00000001) và bức tường #sẽ thay đổi thành một lối đi 0(xor với 00010011), vì vậy

s/(q|s|y)#/$&^"\x01\x13"/e

Để xử lý các hướng khác, toàn bộ bảng được xoay (bảng xoay kết thúc ở $o):

my$o;$o.="\n"while s/.$/$o.=$&,""/meg

Ngoài việc di chuyển, anh hùng còn có một số lựa chọn khác mà anh ta có thể thực hiện:

When at home, pick up dynamite:                   x -> y
When on victim not carrying anything pick him up: r -> t
When at home carrying a victim, drop him off:     | -> x

Điều này được thực hiện bởi

y/xr|/ytx/

Hội đồng quản trị kết thúc nếu anh hùng ở nhà không mang theo gì ( x) và không còn nạn nhân nào để giải cứu (không 2). Điều này có thể được kiểm tra thuận tiện bằng cách sử dụng

/x/>/2/

Một khi bảng được giải quyết tôi muốn ghi nhớ trạng thái này và cuối cùng in nó. Vì vậy, tôi mang cờ "được giải quyết" $\và in vào cuối chương trình mà không in $_, vì vậy

$\|=/x/>/2/  ...   }{

Các trạng thái được xử lý ở áp suất 0 được giữ trong @0, ở áp suất 1 trên @1vv. Áp suất hiện tại được giữ trong $%. Việc sử dụng $nhoặc một cái gì đó giống như nó sẽ ngắn hơn nhưng mã không hoạt động nếu biến không được khởi tạo thành thứ gì đó bởi vì tự động hóa sẽ thay đổi $nthành tham chiếu ARRAY. Việc xử lý các trạng thái ở áp suất nhất định được thực hiện bằng cách sử dụng forchứ không phải mapvì với một forbạn có thể mở rộng mảng trong khi nó vẫn đang được lặp lại và sẽ nhận các phần tử mới. Điều này là cần thiết bởi vì các phép quay và các lựa chọn trường đơn lẻ của anh hùng xảy ra trong 0 thời gian và kết thúc trong cùng một mảng áp lực. Vì vậy, vòng lặp cho một áp lực nhất định được thực hiện bởi

for(@{$%}){...}

Điều này được lặp lại cho đến khi áp suất đạt 1000 hoặc tìm thấy giải pháp:

$%++>999|$\||redo

Tất cả những gì còn lại là thêm các trạng thái mới được phát hiện vào mảng áp suất tương ứng của chúng. Điều đó sẽ được thực hiện bởi chương trình con f. Chúng tôi chỉ muốn thêm một trạng thái nếu nó chưa được nhìn thấy. Các tiểu bang đã được nhìn thấy trước đây được giữ trong %anhư vậy:

sub f{@a{@_}||=push@$n, @_}

$nđại diện cho áp lực mới cho một nhà nước. Tôi sẽ rút ra rằng từ trạng thái mà các biến regex vẫn có do kết quả của hành động của anh hùng dẫn đến lời kêu gọi này:

if $1 is set it was from s/(q|s|y)#/$&^"\x01\x13"/e which blows a wall -> 50
else if $& is set it was from s/\pL\d/$&^(E&$&)x2/e, so the hero moves.
    if $& contains 8 the hero went home -> 0
    else if the hero has carry bits (5) -> 2
    else                                   1
else ($& was not set) it was from y/xr|/ytx/r -> 0

Điều này dẫn đến công thức sau đây cho $n:

$%+($&?$1?50:$&=~8?0:$&&"5"?2:1:0)

Tất cả các thay thế có được một rsửa đổi để họ trả lại trạng thái thay đổi và để trạng thái hiện tại $_một mình. fsau đó được gọi vào trạng thái thay đổi này, vì vậy bạn nhận được mã như

f y/xr|/ytx/r;

Bởi vì việc tính toán $nnhu cầu các biến regex, họ phải mặc định bỏ đặt trong trường hợp các thay thế không thay đổi gì (vì điều kiện để kích hoạt chúng không được đáp ứng). Tôi cũng không được chọn bất kỳ biến regex nào từ vòng lặp trước. Do đó, sự thay thế được gói trong {}các khối để lưu và khôi phục trạng thái regex. Đó là cách bạn nhận được các tuyên bố như

{f s/\pL\d/$&^(E&$&)x2/er}

Cụ thể, vòng quay được bao bọc để nó gọi fmà không có biến regex và đóng góp áp suất bằng 0.

Điều duy nhất vẫn phải làm là bắt đầu @0với trạng thái ban đầu khi bắt đầu

f$_

Đây là trong vòng lặp chính vì vậy nó cũng cố gắng thêm $_vào các mảng áp lực sau này, nhưng vì trạng thái ban đầu sẽ %akhông có gì xảy ra.

Về cơ bản, tất cả điều này về cơ bản tìm ra giải pháp ngắn nhất bằng thuật toán của Dijkstra . Có một vấn đề tiềm năng mặc dù. Mã hiện tại sẽ không thêm trạng thái nếu nó được khám phá lại với áp suất thấp hơn so với khám phá đầu tiên. Tôi đã không thể xây dựng một bảng sẽ kích hoạt điều này, nhưng cũng không thể chứng minh điều đó là không thể.


3
Ooo, hấp dẫn. Điều này ngắn hơn đáng kể so với tôi mong đợi bất kỳ câu trả lời. Bạn có thể thêm một chút giải thích? Tôi không thực sự mò mẫm Perl.
admBorkBork

3
@TimmyD Ok, giải thích thêm với đủ chi tiết để mà ngay cả một lập trình perl không nên nhận được ít nhất một ấn tượng về cách thức hoạt động
Tôn Hospel

1
Rất ấn tượng!
Emigna

Chơi golf tuyệt vời, điều đó thực sự ấn tượng ... Khi tôi nghĩ rằng tôi không tệ khi chơi golf với Perl, tôi sẽ xem các môn đánh gôn của bạn và cảm giác đó biến mất khá nhanh!
Dada

13

JavaScript, 863 834 785 781 byte

Đã lưu 29 byte nhờ vào ETHproductions
Lưu 53 byte nhờ Jordan

L=[]
f=(S,r="",R="",p=0,s=S.replace(RegExp(r),R),l=`((.|\n){${s.split`
`[0].length}})`,q=p+1,o=p+2,n=p+50)=>s in L|p>999?1e3:!/M/.test(s,L[s]=0)&/E/.test(s)?p:Math.min(...[[/ E/,"me",q],[/ E/,"de",o],[/ME/,"ce",q],[/E /,"em",q],[/E /,"ed",o],[/EM/,"ec",q],[`E${l} `,"e$1m",q],[`E${l} `,"e$1d",o],[`E${l}M`,"e$1c",q],[` ${l}E`,"m$1e",q],[` ${l}E`,"d$1e",o],[`M${l}E`,"c$1e",q],[/ m/,"m ",q],[/m /," m",q],[`m${l} `," $1m",q],[` ${l}m`,"m$1 ",q],[/ (d|c)/,"$1 ",o],[/(d|c) /," $1",o],[`(d|c)${l} `," $2$1",o],[` ${l}(d|c)`,"$3$1 ",o],[/d#/,"m ",n],[/#d/," m",n],[`#${l}d`," $1m",n],[`d${l}#`,"m$1 ",n],[/mM/," c",q],[/Mm/,"c ",q],[`M${l}m`,"c$1 ",q],[`m${l}M`," $1c",q],[/[mc]e/," E",p],[/e[mc]/,"E ",p],[`e${l}[mc]`,"E$1 ",p],[`[mc]${l}e`," $1E",p]].map(a=>f(s,...a)))
F=s=>f(s)<1e3

Đưa đầu vào dưới dạng một chuỗi nhiều dòng.

Điều này xác định một hàm ẩn danh sử dụng hàm đệ quy fđể xác định xem bạn có tắt báo thức hay không trước khi lấy tất cả chuột. ftrở lại 1000nếu áp suất trên 1000 (để tránh đệ quy vô tận), trả lại áp suất nếu không còn chuột để giải cứu và chuột thoát ra và trả lại áp suất tối thiểu của tất cả các di chuyển có thể từ trạng thái hiện tại. Nó sử dụng một mảng Lđể theo dõi các vị trí đã truy cập trong đó L[pos]==0nếu nó được truy cập và không xác định nếu không. Điều này có thể không cần thiết, nhưng nó ngăn chuột thực hiện các động tác vô ích và ít nhất là ném các lỗi đệ quy. (Điều này không có nghĩa là bạn nên xác định lạiL nếu bạn đang thử nghiệm điều này nhiều lần)

Điều này sử dụng định dạng trong câu hỏi khác hơn là nó yêu cầu bạn sử dụng một ký tự khác cho các bức tường bên ngoài. (Bất cứ điều gì khác ngoài# MEmecd )

Phiên bản dễ đọc hơn:

stateList = []
f=(s,regex="",replacement="",pressure=0,state=s.replace(regexp(regex),replacement),line=`((.|\n){${state.split("\n")[0].length}})`)=>{
    if (state in stateList || pressure > 999) return 1e3
    if (!/M/.test(state) && /E/.test(state)) return pressure

    stateList[state] = 0

    return [
        [/ E/,"me",pressure+1],
        [/ E/,"de",pressure+2],
        [/ME/,"ce",pressure+1],
        [/E /,"em",pressure+1],
        [/E /,"ed",pressure+2],
        [/EM/,"ec",pressure+1],
        [`E${line} `,"e$1m",pressure+1],
        [`E${line} `,"e$1d",pressure+2],
        [`E${line}M`,"e$1c",pressure+1],
        [` ${line}E`,"m$1e",pressure+1],
        [` ${line}E`,"d$1e",pressure+2],
        [`M${line}E`,"c$1e",pressure+1],
        [/ m/,"m ",pressure+1],
        [/m /," m",pressure+1],
        [`m${line} `," $1m",pressure+1],
        [` ${line}m`,"m$1 ",pressure+1],
        [/ ([dc])/,"$1 ",pressure+2],
        [/([dc]) /," $1",pressure+2],
        [`([dc])${line} `," $2$1",pressure+2],
        [` ${line}([dc])`,"$3$1 ",pressure+2],
        [/d#/,"m ",pressure+50],
        [/#d/," m",pressure+50],
        [`#${line}d`," $1m",pressure+50],
        [`d${line}#`,"m$1 ",pressure+50],
        [/mM/," c",pressure+1],
        [/Mm/,"c ",pressure+1],
        [`M${line}m`,"c$1 ",pressure+1],
        [`m${line}M`," $1c",pressure+1],
        [/[mc]e/," E",pressure],
        [/e[mc]/,"E ",pressure],
        [`e${line}[mc]`,"E$1 ",pressure],
        [`[mc]${line}e`," $1E",pressure]
    ].map(a=>f(state,...a)).reduce((a,b)=>a-b<0?a:b) //reduce used for support in more browsers.
}
s=>f(s)>1e3

Khoảng trắng vô dụng tại s in L|p > 999.
Yytsi

@TuukkaX Cảm ơn bạn đã nhắc nhở tôi về điều đó, bytecount dành cho phiên bản chưa có khoảng trắng.
DanTheMan

Xem bạn có thể lưu byte bằng cách gói mã vào evalvà thay thế @bằng $1(không chắc điều này có hoạt động không, nhưng bạn viết $1rất nhiều)
Cyoce

Tôi nghĩ rằng bạn có thể tiết kiệm được một bó bằng cách tạo fmột lớp lót:f=(...)=>s in L|p>999?1e3:!/M/.test(s,L[s]=0)&/E/.test(s)?p:Math.min(...
Sản xuất ETH

@Cyoce Tôi sử dụng $118 lần và .replace("@","$1")là 18 byte. Tôi không thấy cách nào để kéo nó ra.
DanTheMan
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.