Thời gian mê cung lục giác!


27

Thời gian cho một thách thức mê cung khác, nhưng không phải như bạn biết.

Các quy tắc cho thử thách này hơi khác so với hầu hết các thử thách mê cung. Các loại gạch được định nghĩa như sau:

  • S: Vị trí trên mê cung bạn bắt đầu tại
  • E: Vị trí bạn đang cố gắng đến
  • 0: Bức tường mà bạn không thể vượt qua
  • +: Tầng mà bạn có thể vượt qua

Bạn có thể đi theo một trong sáu hướng: lên trái, lên phải, trái, phải, xuống trái hoặc xuống phải.

\ /
-S-
/ \

Mê cung không bao bọc. Mục tiêu là tìm chuỗi đường dẫn ngắn nhất để đi từ Sđến E.

Đầu vào:

Đầu vào là các dòng phân cách không gian giống như các mê cung được hiển thị. Không có dấu cách sẽ theo một dòng.

Đầu ra:

Một chuỗi R, LFnơi

  • R xoay bạn phải (theo chiều kim đồng hồ) 60 độ
  • L xoay bạn sang trái (ngược chiều kim đồng hồ) 60 độ
  • F di chuyển bạn một không gian theo hướng bạn đang chỉ

Bạn bắt đầu chỉ left-up

Đường dẫn ngắn nhất được tính bằng độ dài của chuỗi được tạo, không phải số lượng vị trí được truy cập. Chương trình của bạn phải in đường dẫn ngắn nhất làm giải pháp.

Nếu mê cung là không thể giải quyết, bạn nên xuất ra Invalid maze!.

( >>>là đầu ra)

     0 0 0 0
    0 + 0 + 0
   0 0 0 + + 0
  0 + 0 + 0 + 0
 0 0 + + 0 0 + 0
0 0 + 0 + 0 0 + 0
 E 0 + 0 0 + + 0 
  + + 0 + 0 + 0
   0 0 0 0 0 +
    + 0 + + +
     0 S 0 0

>>>RFRFFLFLFRFFLFFFLFLFFRFLFLFRFRFRF

  + 0 0 0 0 0 0
 0 0 0 0 0 + + 0
0 0 E 0 + 0 0 + 0
 0 0 0 0 0 0 0 +
  0 + 0 0 + + +
   0 0 + + 0 0
    S + 0 0 0

>>>Invalid maze!

0 E S

>>>LF


 E + 0
0 + + +
 0 0 S
  + +

>>>FFLF

  E
 0 +
0 + +
 0 +
  S

>>>RFFLFF

 0 E + 0 0
0 + 0 0 + +
 + 0 + + + 0
  + 0 + 0 + 0
   + + + 0 S

>>>FFLFLFFRFRFFRFF

 E 0 + + 0
0 + 0 + + 0
 + + + 0 + 0
  + 0 0 0 0 0
   + + + + 0
    + 0 S 0

>>>FLFFRFFRFLF

(Lưu ý rằng một số mê cung có các giải pháp khác có cùng độ dài nhưng không được liệt kê ở đây)


27
Hy vọng cho một giải pháp Hexagony ...
bkul

3
Tôi sẽ thưởng tiền thưởng 500 điểm cho giải pháp Hexagony.
lirtosiast

@ lirtosiast2 năm sau, tôi nghĩ rằng hexagony có thể là một vấn đề cho vấn đề này;)
J Atkin

Chúng ta hãy chờ thêm một vài năm nữa.
dùng202729

Có thể có một dòng mới trailing?
dùng202729

Câu trả lời:


17

Python 2, 291 byte

def f(M):
 Y=map(max,M).index("S");X=M[Y].find("S");V={()};Q=[(0,0,0,1,"")]
 while Q:
    try:x,y,u,v,p=s=Q.pop(0);c=(Y>=y<=X-2*x)*ord(M[Y-y][X-2*x-y])
    except:c=0
    if c==69:return p
    if{c%2*s[:4]}-V:V|={s[:4]};Q+=(x+u,y+v,u,v,p+"F"),(x,y,-v,u+v,p+"R"),(x,y,u+v,-u,p+"L")
 return"Invalid maze!"

Một hàm, flấy mê cung làm danh sách các hàng và trả về một giải pháp, nếu có.

Giải trình

Thực hiện tìm kiếm theo chiều rộng đầu tiên trên biểu đồ của các cặp vị trí / hướng để tìm đường đi ngắn nhất từ Sđến E.

Điều thú vị là tìm một cách nhỏ gọn để biểu diễn các vị trí và hướng trên lưới hình lục giác, thừa nhận "bước" đơn giản (nghĩa là di chuyển theo một hướng nhất định) và xoay. Ở đây rất hấp dẫn khi sử dụng các số phức ở đây, để biểu diễn tọa độ trên lưới lục giác "thực", nhưng đây không phải là ý kiến ​​hay vì nhiều lý do, trong đó nghiêm trọng nhất là chúng ta cần phải cắm 3 ở đâu đó để làm cho nó hoạt động (sin 60 ° = √3 / 2), khi sử dụng số dấu phẩy động, sẽ không có gì nếu chúng ta cần độ chính xác tuyệt đối (ví dụ: để theo dõi các trạng thái chúng ta đã truy cập;) bạn có thể thử kích hoạt bảng điều khiển JavaScript và gõ Math.sqrt(3)*Math.sqrt(3) == 3và tự mình xem.

Nhưng, chúng ta có thể sử dụng một mẹo nhỏ! Thay vì sử dụng các số phức, hãy xác định các số lục giác trong một tĩnh tương tự, như một cặp số thực a + bh , trong đó h đóng vai trò tương tự như i tưởng tượng khi xử lý các số phức. Cũng giống như với các số phức, chúng ta có thể liên kết cặp ( a , b ) với một điểm trên mặt phẳng, trong đó trục thực chỉ đúng, trục ảo hướng lên 60 ° và cả hai đều giao nhau với hình lục giác đều của đơn vị khi thực và các phần tưởng tượng bằng 1, tương ứng. Ánh xạ hệ tọa độ này đến các ô của mê cung là chuyện nhỏ.

Hình 1

Không giống như i , hằng số h được xác định bởi mối quan hệ h 2 = h - 1 (giải quyết cho h có thể tiết lộ một số hiểu biết.) Và đó là nó! Số hình lục giác có thể được thêm và nhân, sử dụng các mối quan hệ trên, giống như số phức: ( một + bh ) + ( c + dh ) = ( một + c ) + ( b + d ) h ,
và ( một + bh ) · ( c + dh ) = ( ac - bd) + ( quảng cáo + bc + bd ) h . Các hoạt động này có cùng cách hiểu hình học như các đối tác phức tạp của chúng: phép cộng là phép cộng vector và phép nhân là tỷ lệ và phép quay. Cụ thể, để xoay một số lục giác 60 ° ngược chiều kim đồng hồ, chúng ta nhân nó với h :
( a + bh ) · h = - b + ( a + b ) h , và để xoay cùng một số 60 ° theo chiều kim đồng hồ, chúng ta chia bởi h :
( a + bh ) / h = ( a +bh ) · (1 - h ) = (a + b) - ah . Ví dụ: chúng ta có thể lấy số lục giác đơn vị chỉ đúng, 1 = (1, 0), một vòng tròn đầy đủ, đi ngược chiều kim đồng hồ, bằng cách nhân nó với h sáu lần:
(1, 0) · h = (0, 1 ); (0, 1) · h = (-1, 1); (-1, 1) · h = (-1, 0); (-1, 0) · h = (0, -1); (0, -1) · h = (1, -1);
(1, -1) · h = (1, 0).

Chương trình sử dụng các số lục giác theo cách này để thể hiện vị trí hiện tại trong mê cung và hướng hiện tại, để tiến theo hướng đã chỉ định và để xoay hướng sang trái và sang phải.


31

Lục giác , 2437 byte

Chương trình được chờ đợi từ lâu ở đây:

(.=$>({{{({}}{\>6'%={}{?4=$/./\_><./,{}}{<$<\?{&P'_("'"#<".>........_..\></</(\.|/<>}{0/'$.}_.....><>)<.$)).><$./$\))'"<$_.)><.>%'2{/_.>(/)|_>}{{}./..>#/|}.'/$|\})'%.<>{=\$_.\<$))<>(|\4?<.{.%.|/</{=....$/<>/...'..._.>'"'_/<}....({{>%'))}/.><.$./{}{\>$\|$(<><$?..\\<.}_>=<._..\(/.//..\}\.)))))<...2/|$\){}/{..><>).../_$..$_>{0#{{((((/|#.}><..>.<_.\(//$>))<(/.\.\})'"#4?#\_=_-..=.>(<...(..>(/\")<((.\=}}}\>{}{?<,|{>/...(...>($>{)<.>{=P&/(>//(_.)\}=#=\4#|)__.>"'()'\.'..".(\&P'&</'&\$_></}{)<\<0|\<.}.\"\.(.(.(/(\..{.>}=P/|><.(...(..."/<.{"_{{=..)..>})<|><$}}/\}}&P<\(/._...>\$'/.>}/{}}{)..|/(\'.<(\''"")$/{{}})<..'...}}>3#./\$<}|.}|..$.><${{}/>.}}{{<>(""''/..>){<}\?=}{\._=/$/=_>)\{_\._..>)</{\=._.....>(($>}}<.>5#.\/}>)<>-/(.....{\<>}}{{/)\$>=}}}))<...=...(\?{{{?<\<._...}.><..\}}/..>'P&//(\......(..\})"'/./&P'&P{}}&P'<{}\{{{({{{(.\&P=<.><$"&1}(./'"?&'&"\.|>}{?&"?&'P&/|{/&P''</(\..>P&{/&/}{}&'&},/"&P'&?<.|\}{&?"&P'&P'<._.>"&}\(>))<\=}{}<.{/}&?"&"&/"&"?&}\.|>?&"?&{{}}?&//x'&{((<._\($|(}.\/}{/>=&'P&"&/".{3?<.|\"&P'&P}{}&P'<.>&{}}?&"&'P&\=}}<.}/2?".?''5?"/?1{(}\."..../{},<../&//&"&P'&P'&"&"</{}}{{/>"?1''?.'({/}}{}<..>?&"?&}}$>)|P/<.>"&'P&'P&"&"&{/........._/"\$#1}/._.........|,($<'"}'?/_$P#"$0'${)$})$)|........(>/\.#1?<$<|.....>?&}$>=?&"?&/1$..>I;n;v;a;l;i;d;P0;m;a\|\"(}}({=/..$_...\"&P=},}}&P'<.|><....................;...>1"(}}){=/_....>'P&'P&}}_?&/#.>}?4'%\/<...@;1P;e;z<._><>"))'?=<.$$=..\&P}{&</\"><_'|/'&=}<.>{{.<.........|>(/>3")}}){=/=/_.>}P&"?/"<).}_.>?4{=:<.|_...........\$\2$'>4")}}({/."\{&P'&?/><.?|>P...."/=(>(/./(}{{\..>(<>(<>?5'"((..'/...#,</,}{{\.......;.F>..\(...}....._.._..._..._........__..'$......\.<R..$.>))<$}{{&P'&?}<.\$$.\...................$\.<>L\.\(('_"\>}P&"?&{/__/=(.(<.>_)..<...>....\..._.<.....&?=\}=&?"&<.."'>.\>))<.|>))\.|$.>&"?&{{}=P&}?&=}/{\.>&{{P/{">)<|\{<(|\(_(<>\_\?"&P'&P}{{{&<=_.>\&\?"&?<|'{/(/>{{/_>.{/=/\\.>'P&"?&"?&"?/._(\)\\>?&"/_|.>/.$/|$..\\><..\&?}{{}&P'&<}.._>{<|\{}<._$>-")<.>_)<|{)$|..>}=P&"?&"?/...{"./>'P&/=_\{?(/>(<>\(|)__.\&?}}{}&P<}.$.\&P'&P'&<\})))&=<\)<'.'_,><.>"?&'P&'/.|>?&{{}?&"?/>&"?&"?&}}<.".(\\\&?={&P<{..\"&?"&P'&<.?....|.$'\$/\"/.,.>{}{}=/..>&'P&}{{}P/\{}&P{(&?"&?"<'.(\&?"&<}..\?"&?"&<.>P&={}}?&}}P&'P&/.'.>&"?/..>P&}}{{P/\}&P'&?={&?<$}=\"."\P'<{..\'&P'&<....>'P&{}P&"?&{{<\\..>&/$.>}{?&"?/|'$&.P&$P\$'&P={(/..\P\\.\{&?"&?\...\?{{}=<$&P'&P<.,./<?\...{}=P\"&<.>=P&""'?&'P&'/$.#1.>{?1#=$\&'P/\}&P'&?={(,}<._?_&\&?{=&{*=}4<.>P&"?&"?&'P&/1_$>}?&}}=?&){?/\{}&P'&?={&?#<$

Hãy thử trực tuyến!

Phiên bản "có thể đọc":

                             ( . = $ > ( { { { ( { } } { \ > 6 ' % = { } { ? 4 = $ / .
                            / \ _ > < . / , { } } { < $ < \ ? { & P ' _ ( " ' " # < " .
                           > . . . . . . . . _ . . \ > < / < / ( \ . | / < > } { 0 / ' $
                          . } _ . . . . . > < > ) < . $ ) ) . > < $ . / $ \ ) ) ' " < $ _
                         . ) > < . > % ' 2 { / _ . > ( / ) | _ > } { { } . / . . > # / | }
                        . ' / $ | \ } ) ' % . < > { = \ $ _ . \ < $ ) ) < > ( | \ 4 ? < . {
                       . % . | / < / { = . . . . $ / < > / . . . ' . . . _ . > ' " ' _ / < }
                      . . . . ( { { > % ' ) ) } / . > < . $ . / { } { \ > $ \ | $ ( < > < $ ?
                     . . \ \ < . } _ > = < . _ . . \ ( / . / / . . \ } \ . ) ) ) ) ) < . . . 2
                    / | $ \ ) { } / { . . > < > ) . . . / _ $ . . $ _ > { 0 # { { ( ( ( ( / | #
                   . } > < . . > . < _ . \ ( / / $ > ) ) < ( / . \ . \ } ) ' " # 4 ? # \ _ = _ -
                  . . = . > ( < . . . ( . . > ( / \ " ) < ( ( . \ = } } } \ > { } { ? < , | { > /
                 . . . ( . . . > ( $ > { ) < . > { = P & / ( > / / ( _ . ) \ } = # = \ 4 # | ) _ _
                . > " ' ( ) ' \ . ' . . " . ( \ & P ' & < / ' & \ $ _ > < / } { ) < \ < 0 | \ < . }
               . \ " \ . ( . ( . ( / ( \ . . { . > } = P / | > < . ( . . . ( . . . " / < . { " _ { {
              = . . ) . . > } ) < | > < $ } } / \ } } & P < \ ( / . _ . . . > \ $ ' / . > } / { } } {
             ) . . | / ( \ ' . < ( \ ' ' " " ) $ / { { } } ) < . . ' . . . } } > 3 # . / \ $ < } | . }
            | . . $ . > < $ { { } / > . } } { { < > ( " " ' ' / . . > ) { < } \ ? = } { \ . _ = / $ / =
           _ > ) \ { _ \ . _ . . > ) < / { \ = . _ . . . . . > ( ( $ > } } < . > 5 # . \ / } > ) < > - /
          ( . . . . . { \ < > } } { { / ) \ $ > = } } } ) ) < . . . = . . . ( \ ? { { { ? < \ < . _ . . .
         } . > < . . \ } } / . . > ' P & / / ( \ . . . . . . ( . . \ } ) " ' / . / & P ' & P { } } & P ' <
        { } \ { { { ( { { { ( . \ & P = < . > < $ " & 1 } ( . / ' " ? & ' & " \ . | > } { ? & " ? & ' P & /
       | { / & P ' ' < / ( \ . . > P & { / & / } { } & ' & } , / " & P ' & ? < . | \ } { & ? " & P ' & P ' <
      . _ . > " & } \ ( > ) ) < \ = } { } < . { / } & ? " & " & / " & " ? & } \ . | > ? & " ? & { { } } ? & /
     / x ' & { ( ( < . _ \ ( $ | ( } . \ / } { / > = & ' P & " & / " . { 3 ? < . | \ " & P ' & P } { } & P ' <
    . > & { } } ? & " & ' P & \ = } } < . } / 2 ? " . ? ' ' 5 ? " / ? 1 { ( } \ . " . . . . / { } , < . . / & /
   / & " & P ' & P ' & " & " < / { } } { { / > " ? 1 ' ' ? . ' ( { / } } { } < . . > ? & " ? & } } $ > ) | P / <
  . > " & ' P & ' P & " & " & { / . . . . . . . . . _ / " \ $ # 1 } / . _ . . . . . . . . . | , ( $ < ' " } ' ? /
 _ $ P # " $ 0 ' $ { ) $ } ) $ ) | . . . . . . . . ( > / \ . # 1 ? < $ < | . . . . . > ? & } $ > = ? & " ? & / 1 $
  . . > I ; n ; v ; a ; l ; i ; d ; P 0 ; m ; a \ | \ " ( } } ( { = / . . $ _ . . . \ " & P = } , } } & P ' < . |
   > < . . . . . . . . . . . . . . . . . . . . ; . . . > 1 " ( } } ) { = / _ . . . . > ' P & ' P & } } _ ? & / #
    . > } ? 4 ' % \ / < . . . @ ; 1 P ; e ; z < . _ > < > " ) ) ' ? = < . $ $ = . . \ & P } { & < / \ " > < _ '
     | / ' & = } < . > { { . < . . . . . . . . . | > ( / > 3 " ) } } ) { = / = / _ . > } P & " ? / " < ) . } _
      . > ? 4 { = : < . | _ . . . . . . . . . . . \ $ \ 2 $ ' > 4 " ) } } ( { / . " \ { & P ' & ? / > < . ? |
       > P . . . . " / = ( > ( / . / ( } { { \ . . > ( < > ( < > ? 5 ' " ( ( . . ' / . . . # , < / , } { { \
        . . . . . . . ; . F > . . \ ( . . . } . . . . . _ . . _ . . . _ . . . _ . . . . . . . . _ _ . . ' $
         . . . . . . \ . < R . . $ . > ) ) < $ } { { & P ' & ? } < . \ $ $ . \ . . . . . . . . . . . . . .
          . . . . . $ \ . < > L \ . \ ( ( ' _ " \ > } P & " ? & { / _ _ / = ( . ( < . > _ ) . . < . . . >
           . . . . \ . . . _ . < . . . . . & ? = \ } = & ? " & < . . " ' > . \ > ) ) < . | > ) ) \ . | $
            . > & " ? & { { } = P & } ? & = } / { \ . > & { { P / { " > ) < | \ { < ( | \ ( _ ( < > \ _
             \ ? " & P ' & P } { { { & < = _ . > \ & \ ? " & ? < | ' { / ( / > { { / _ > . { / = / \ \
              . > ' P & " ? & " ? & " ? / . _ ( \ ) \ \ > ? & " / _ | . > / . $ / | $ . . \ \ > < . .
               \ & ? } { { } & P ' & < } . . _ > { < | \ { } < . _ $ > - " ) < . > _ ) < | { ) $ | .
                . > } = P & " ? & " ? / . . . { " . / > ' P & / = _ \ { ? ( / > ( < > \ ( | ) _ _ .
                 \ & ? } } { } & P < } . $ . \ & P ' & P ' & < \ } ) ) ) & = < \ ) < ' . ' _ , > <
                  . > " ? & ' P & ' / . | > ? & { { } ? & " ? / > & " ? & " ? & } } < . " . ( \ \
                   \ & ? = { & P < { . . \ " & ? " & P ' & < . ? . . . . | . $ ' \ $ / \ " / . ,
                    . > { } { } = / . . > & ' P & } { { } P / \ { } & P { ( & ? " & ? " < ' . (
                     \ & ? " & < } . . \ ? " & ? " & < . > P & = { } } ? & } } P & ' P & / . '
                      . > & " ? / . . > P & } } { { P / \ } & P ' & ? = { & ? < $ } = \ " . "
                       \ P ' < { . . \ ' & P ' & < . . . . > ' P & { } P & " ? & { { < \ \ .
                        . > & / $ . > } { ? & " ? / | ' $ & . P & $ P \ $ ' & P = { ( / . .
                         \ P \ \ . \ { & ? " & ? \ . . . \ ? { { } = < $ & P ' & P < . , .
                          / < ? \ . . . { } = P \ " & < . > = P & " " ' ? & ' P & ' / $ .
                           # 1 . > { ? 1 # = $ \ & ' P / \ } & P ' & ? = { ( , } < . _ ?
                            _ & \ & ? { = & { * = } 4 < . > P & " ? & " ? & ' P & / 1 _
                             $ > } ? & } } = ? & ) { ? / \ { } & P ' & ? = { & ? # < $

Đã thử nghiệm trên IDE bí truyền: TIO có thể hết thời gian đối với một số trường hợp thử nghiệm lớn hơn nhưng tất cả đã được xác minh. Rất cám ơn Timwi, điều này sẽ không thể thực hiện được nếu không có IDE.

Có khá nhiều không gian trống, vì vậy tôi có thể lắp nó vào một hình lục giác 28 cạnh dài (thay vì chiều dài 29) nhưng đó sẽ là một nhiệm vụ lớn nên có lẽ tôi sẽ không thử.

Giải thích cơ bản

Nhấp vào hình ảnh cho một phiên bản lớn hơn và chi tiết hơn.

Chức năng

Chức năng
Lưu ý: Sự phân chia nói chung là chính xác nhưng đôi khi có thể là một phỏng đoán sơ bộ.

Mã này khá "chức năng" - nhiều như Hexagony cho phép. Có tám hàm chính trong mã này được dán nhãn trong sơ đồ trên, được đặt tên theo các số mà chúng được gọi (vì vậy số con trỏ lệnh của chúng là số mod 6). Theo thứ tự (thô) của cuộc gọi, chúng là (tên được trích dẫn là vị trí trong bộ nhớ sẽ được giải thích sau):

  • S: Chức năng khởi động - đọc đầu vào và bộ lên "mảng tài liệu tham khảo", sau đó bắt đầu "con đường ngăn xếp" với ba lối đi F, RLsẵn sàng cho việc xử lý chính. Con trỏ lệnh 0 di chuyển đến chức năng 0 trong khi thực thi chuyển sang chức năng 1.
  • 1 (-11): Hàm chính - sử dụng 2 để nhận đường dẫn, 3 để kiểm tra tính hợp lệ của nó và nếu hợp lệ sẽ chuyển sang hàm -110 / -10 hai lần và sau đó 4 ba lần để sao chép các đường dẫn mới vào "đường dẫn ngăn xếp ", hoàn thiện bằng cách trở về chính nó. Có thể gọi hàm 5 nếu đường dẫn ở vị trí cuối.
  • 2: Lấy đường dẫn tiếp theo ra khỏi "ngăn xếp đường dẫn" sẵn sàng để xử lý, gọi hàm -1 nếu không còn đường dẫn nào trên ngăn xếp. Trả về hàm 1.
  • 3: Lấy một cặp giá trị cũng như số di chuyển và kiểm tra "mảng tham chiếu" để xem liệu đường dẫn hiện tại đã kết thúc tại một vị trí hợp lệ hay chưa. Vị trí hợp lệ là điểm bắt đầu trong 3 lần di chuyển đầu tiên hoặc bất kỳ +trong 2 lần di chuyển đầu tiên của địa điểm đó. Trả về hàm 1.
  • -10 / -110: Sao chép đường dẫn hiện tại. Trả về hàm 1.
  • 0: Giúp chức năng 1 để quản lý hướng di chuyển với F. Trả về hàm 1.
  • 4: Đưa một bản sao của con đường hiện tại và liên kết với nhau với chức năng 1 thay đổi nó vào con đường cùng với một trong hai F, Rhoặc Lnối. Trả về hàm 1.
  • 5: Lấy đường dẫn và in ra đường dẫn chính xác (ví dụ FFLF), sau đó chấm dứt chương trình.
  • -1: In Invalid maze!và chấm dứt.
  • (Mũi tên kép): Do thiếu không gian, chức năng 1 / -11 đã phải đi vào không gian bên trên chức năng -1.

Ký ức

Bố cục bộ nhớ
Lưu ý: Cảm ơn IDE bí mật một lần nữa cho sơ đồ

Bộ nhớ bao gồm ba phần chính:

  • Mảng tham chiếu: Lưới được lưu trữ các cột cách nhau 2, với một giá trị ở mỗi bước:
    • 0 đại diện hoặc là một , 0hoặc một nơi hợp lệ mà được truy cập di chuyển nhiều hơn trước hơn sẽ được yêu cầu để thoát khỏi vị trí theo hướng nào.
    • 1 đại diện cho một +chưa đạt được.
    • (số cao hơn) đại diện cho số di chuyển trong đó sẽ có đủ di chuyển để thoát khỏi địa điểm theo bất kỳ hướng nào.
    • 10 cũng đại diện cho một dòng mới: những điều này không bao giờ đạt được với giả định rằng chúng ngay lập tức đi theo nhân vật không phải là khoảng trắng cuối cùng.
  • Đường sắt: Bao gồm -1một s -2ở bên trái, cho phép con trỏ bộ nhớ nhanh chóng quay trở lại khu vực xử lý lõi.
  • Ngăn xếp đường dẫn: Lưu trữ từng đường dẫn chưa được kiểm tra theo thứ tự ID đường dẫn (liên quan trực tiếp đến số di chuyển để các đường dẫn ngắn hơn được kiểm tra trước). Đường dẫn được lưu trữ như sau:
    Bố cục đường dẫn
    • Rot: góc quay ở cuối đường dẫn hiện tại: 0 cho hướng lên trái và tăng theo chiều kim đồng hồ lên 5
    • Di chuyển: số di chuyển hiện tại (hướng dẫn - 1)
    • Đường dẫn: các đường dẫn hiện tại, lưu trữ trong bậc bốn với F, R, Lnhư 1, 2, 3tương ứng
    • x / y: tọa độ ở cuối đường dẫn hiện tại: x + 1 -1s ngay sau đó y giá trị lên (mặc dù y = 0 được xử lý là 1 dù sao cho mục đích tách đường ray khỏi dữ liệu tham chiếu)

Các vị trí bộ nhớ quan trọng khác:

  1. X / y của Eđược lưu trữ ở đây.
  2. Không gian này được sử dụng để chuyển các đường dẫn vào và ra khỏi bộ nhớ.
  3. Vị trí này là trung tâm nơi mỗi đường dẫn được lưu trữ trong quá trình xử lý.

Bước tiếp theo là chạy chương trình của bạn thông qua chương trình của bạn để tìm con đường mê cung ngắn nhất.
Veskah

Tôi biết ai đó sẽ đăng nó. Cuối cùng ... / Tôi cũng có một kế hoạch khác, có lẽ nên lấy ít mã hơn của bạn. Không bao giờ thực sự có thời gian để thực hiện nó.
dùng202729

@ user202729 sẽ rất thú vị khi nghe về nó. Tôi có thể nói phương pháp này có thể chơi được ít nhất 2 kích cỡ, nhưng gần như chắc chắn có thứ gì đó tốt hơn ngoài kia.
boboquack

1
Chỉ chờ @lirtosiast.
J Atkin

1
Xin lỗi vì sự chậm trễ.
lirtosiast

6

Python 3, 466 byte

Có lẽ đã kết thúc nhỏ hơn nếu tôi sử dụng tìm kiếm theo chiều sâu hoặc một cái gì đó. Sự quái dị này sử dụng Dijkstra và khá nhanh, nhưng rất dài.

Mã xác định một hàm Slấy một chuỗi nhiều dòng với mê cung và trả về kết quả.

def F(M,L,c):y=M[:M.index(c)].count("\n");return L[y].index(c),y
def S(M):
 L=M.split("\n");Q=[("",)+F(M,L,"S")+(0,)];D={};R=range;H=len;U=R(2**30)
 while Q:
  C,*Q=sorted(Q,key=H);w,x,y,d=C
  for e in R(H(L)>y>-1<x<H(L[y])>0<H(D.get(C[1:],U))>H(w)and(L[y][x]in"+SE")*6):D[C[1:]]=w;E=(d+e)%6;Q+=[(w+",R,RR,RRR,LL,L".split(",")[e]+"F",x+[-1,1,2,1,-1,-2][E],y+[-1,-1,0,1,1,0][E],E)]
 J=min([D.get(F(M,L,"E")+(d,),U)for d in R(6)],key=H);return[J,"Invalid maze!"][J==U]

Đây là một bài kiểm tra mã.

Bị đánh cắp

def find_char(maze, lines, char):
    y = maze[:maze.index(char)].count("\n")
    return lines[y].index(char), y
def solve(maze):
    lines = maze.split("\n")
    x, y = find_char(maze, lines, "S")
    queue = [("", x, y, 0)]
    solutions = {}
    very_long = range(2**30)
    x_for_direction = [-1,1,2,1,-1,-2]
    y_for_direction = [-1,-1,0,1,1,0]
    rotations = ["","R","RR","RRR","LL","L"]
    while len(queue) > 0:
        queue = sorted(queue, key=len)
        current, *queue = queue
        route, x, y, direction = current
        if 0 <= y < len(lines) and 0 <= x < len(lines[y]) and lines[y][x] in "+SE" and len(solutions.get(current[1:], very_long)) > len(route):
            solutions[current[1:]] = route
            for change in range(6):
                changed = (direction + change) % 6
                queue += [(route + rotations[change] + "F", x + x_for_direction[changed], y + y_for_direction[changed], changed)]
    end_x, end_y = find_char(maze, lines, "E")
    solution = min([solutions.get((end_x, end_y, direction), very_long) for direction in range(6)], key=len)
    return "Invalid maze!" if solution == very_long else solution

Wow, rất đẹp. Bạn mất bao lâu để viết?
J Atkin

1
@JAtkin Vâng, tệp đã được tạo cách đây 1,5 giờ, mặc dù tôi không chắc chắn tôi đã dành bao nhiêu thời gian để làm việc với mã. Ngoài ra, bây giờ là 3 giờ sáng, nên năng suất của tôi rõ ràng là tối đa.
PurkkaKoodari

Thật tuyệt, tôi đã dành hơn 2 giờ, và hầu hết của tôi đã được viết cho một mê cung tiêu chuẩn.
J Atkin

Bạn có một phiên bản không linh hoạt?
J Atkin

1
@JAtkin Điều đó là cần thiết, bởi vì bạn có thể cần phải quay đầu lại khi bắt đầu. Nếu không có vị trí bắt đầu, nó sẽ làm việc với L,,R.
PurkkaKoodari

3

Groovy, 624 byte. Trán!

Thời gian có được quả bóng lăn với một lớn. Đưa chuỗi nhiều dòng như argQ

Q={a->d=[0]*4
a.eachWithIndex{x,y->f=x.indexOf('S');e=x.indexOf('E');
if(f!=-1){d[0]=f;d[1]=y}
if(e!=-1){d[2]=e;d[3]=y}}
g=[]
s={x,y,h,i,j->if(h.contains([x, y])|y>=a.size()||x>=a[y].size()|x<0|y<0)return;k = a[y][x]
def l=h+[[x, y]]
def m=j
def n=1
if(h){
o=h[-1]
p=[x,y]
q=[p[0]-o[0],p[1]-o[1]]
n=[[-2,0]:0,[-1,-1]:1,[1,-1]:2,[2,0]:3,[1,1]:4,[-1,1]:5][q]
r=n-i
m=j+((r==-5|r==5)?' LR'[(int)r/5]:['','R','RR','LL','L'][r])+'F'}
if(k=='E')g+=m
if(k=='+'|k=='S'){s(x-2,y,l,n,m)
s(x+2,y,l,n,m)
s(x+1,y+1,l,n,m)
s(x+1,y-1,l,n,m)
s(x-1,y+1,l,n,m)
s(x-1,y-1,l,n,m)}}
s(d[0],d[1],[],1,'')
print(g.min{it.size()}?:"Invalid maze!")}

Phiên bản bị đánh cắp:

def map =
        """
  + 0 0 0 0 0 0
 0 0 0 0 0 + + 0
0 0 E 0 + 0 0 + 0
 0 0 0 0 0 0 0 +
  0 + 0 0 + + +
   0 0 + + 0 0
    S + 0 0 0""".split('\n').findAll()
//map =
//        """
// 0 + +
//E + 0 S 0
// 0 0 0 +
//  + + +""".split('\n').findAll()

//map = [""]// TODO remove this, this is type checking only
//map.remove(0)
//reader = System.in.newReader()
//line = reader.readLine()
//while (line != '') {
//    map << line
//    line = reader.readLine()
//}

startAndEnd = [0, 0, 0, 0]
map.eachWithIndex { it, idx ->
    s = it.indexOf('S'); e = it.indexOf('E');
    if (s != -1) {
        startAndEnd[0] = s; startAndEnd[1] = idx
    }
    if (e != -1) {
        startAndEnd[2] = e; startAndEnd[3] = idx
    }
}

def validPaths = []
testMove = { x, y, visited ->// visited is an array of x y pairs that we have already visited in this tree
    if (visited.contains([x, y]) || y >= map.size() || x >= map[y].size() || x < 0 || y < 0)
        return;


    def valueAtPos = map[y][x]
    def newPath = visited + [[x, y]]

    if (valueAtPos == 'E') validPaths += [newPath]
    if (valueAtPos == '+' || valueAtPos == 'S') {
        println "$x, $y passed $valueAtPos"
        testMove(x - 2, y, newPath)
        testMove(x + 2, y, newPath)

        testMove(x + 1, y + 1, newPath)
        testMove(x + 1, y - 1, newPath)

        testMove(x - 1, y + 1, newPath)
        testMove(x - 1, y - 1, newPath)
    }
}

//if (!validPath) invalid()
testMove(startAndEnd[0], startAndEnd[1], [])
println validPaths.join('\n')

//println validPath

def smallest = validPaths.collect {
    def path = ''
    def orintation = 1
    it.inject { old, goal ->
        def chr = map[goal[1]][goal[0]]
        def sub = [goal[0] - old[0], goal[1] - old[1]]
        def newOrin = [[-2, 0]: 0, [-1, -1]: 1, [1, -1]: 2, [2, 0]: 3, [1, 1]:4, [-1, 1]:5][sub]
        def diff = newOrin - orintation// 5L -5R
        def addedPath= ((diff==-5||diff==5)?' LR'[(int)diff/5]:['', 'R', 'RR', 'LL', 'L'][diff]) + 'F'//(diff == 0) ? '' : (diff > 0 ? 'R'*diff : 'L'*(-diff)) + 'F'
//        println "old:$old, goal:$goal chr $chr, orintation $orintation, sub:$sub newOrin $newOrin newPath $addedPath diff $diff"
        path += addedPath
        orintation = newOrin
        goal
    }
    path
}.min{it.size()}
//println "paths:\n${smallest.join('\n')}"
if (smallest)
    println "path $smallest"
else
    println "Invalid maze!"

3

C #, 600 574 byte

Hoàn thành chương trình, chấp nhận đầu vào từ STDIN, xuất ra STDOUT.

Chỉnh sửa: có một lỗi trong xử lý bọc (không phá vỡ bất kỳ trường hợp thử nghiệm nào) đã thêm 1 byte, vì vậy tôi đã chơi golf thêm một chút để bù lại.

using Q=System.Console;struct P{int p,d;static void Main(){string D="",L;int w=0,W=0,o,n=1;for(;(L=Q.ReadLine())!=null;D+=L)w=(o=(L+="X").Length+1)>w?o:w;for(;W<D.Length;)D=D.Insert(W+1,"".PadLeft(D[W++]>87?w-W%w:0));P[]K=new P[W*6];var T=new string[W*6];P c=K[o=0]=new P{p=D.IndexOf('S')};for(System.Action A=()=>{if(c.p>=0&c.p<W&System.Array.IndexOf(K,c)<0&&D[c.p]%8>0){T[n]=T[o]+L;K[n]=c;n=D[c.p]==69?-n:n+1;}};o<n;o++){c=K[o];L="R";c.d=++c.d%6;A();L="L";c.d=(c.d+4)%6;A();L="F";c=K[o];c.p+=new[]{~w,1-w,2,1+w,w-1,-2}[c.d%6];A();}Q.WriteLine(n>0?"Invalid maze!":T[-n]);}}

Nó bắt đầu bằng cách đọc trên bản đồ, nối thêm ( vào từng dòng để nó biết nơi kết thúc và có thể quay lại và thêm vào một khoảng trống để tạo bản đồ hình chữ nhật và với một hàng khoảng trống ở bên phải (điều này giúp tiết kiệm chúng tôi thực hiện kiểm tra gói như sẽ được giải thích dưới đây). Nó tính ra chiều rộng của hình chữ nhật tại một số điểm trong đó và xác định tổng chiều dài của Bản đồ.

Tiếp theo, nó khởi tạo mọi thứ cho Breadth-First-Search. Hai mảng lớn được tạo ra, một để lưu trữ tất cả các trạng thái chúng ta cần khám phá trong tìm kiếm của mình, còn lại để ghi lại tuyến đường chúng ta đã đi để đến từng tiểu bang. Trạng thái ban đầu được thêm vào mảng do, với các con trỏ đầu và đuôi được cài đặt sẵn ở đâu đó bên trên. Tất cả mọi thứ là 1 chỉ mục.

Sau đó chúng tôi lặp đi lặp lại cho đến khi cái đuôi đâm vào đầu, hoặc ít nhất là nó dường như đã đâm vào đầu. Đối với mỗi trạng thái chúng tôi đã truy cập, chúng tôi cố gắng thêm một trạng thái mới tại cùng một vị trí nơi chúng tôi được xoay sang trái hoặc phải, và sau đó một trạng thái mà chúng tôi đã di chuyển về phía trước. Các hướng được lập chỉ mục, với hướng ban đầu (mặc định là0 ) tương ứng với "hướng lên trên".

Khi chúng ta cố gắng xếp hàng một trạng thái, nó bị kiểm tra ràng buộc, nhưng không được kiểm tra, bởi vì các cột của không gian ở phía bên phải, được chọn bởi "chúng ta có được phép ở đây không?" kiểm tra (bạn không được phép ở trên không gian). Nếu trạng thái được xếp hàng, sau đó chúng tôi kiểm tra xem nó có trên Eô không và nếu có, chúng tôi đặt phần đầu của hàng đợi tự trừ đi, điều này khiến cho vòng lặp chính thoát ra và cho dòng cuối cùng của chương trình in ra tuyến đường tương ứng, thay vì thông báo lỗi (cho biết nếu chúng ta hết trạng thái để mở rộng (đuôi đâm vào đầu)).

using Q=System.Console;

// mod 8 table (the block of zeros is what we are after - it's everywhere we /can't/ go)
//   0 (space)
// O 0
// X 0
// S 3
// + 3
// E 5

struct P
{
    int p,d;
    static void Main()
    {
        // it's probably a bad thing that I have my own standards for naming this stupid read sequence by now
        string D="", // map
        L; // line/path char

        int w=0, // width
        W=0, // full length
        o, // next state to expand
        n=1; // next state to fill

        for(;(L=Q.ReadLine())!=null;D+=L) // read in map
            w=(o=(L+="X").Length+1)>w?o:w; // assertain max length (and mark end, and remove any need for wrap checking)

        // now we need to add those trailing spaces...
        for(;W<D.Length;)
            D=D.Insert(W+1,"".PadLeft(D[W++]>87?w-W%w:0)); // inject a load of spaces if we hit an X

        P[]K=new P[W*6]; // create space for due states (can't be more states than 6*number of cells)
        var T=new string[W*6]; // create space for routes (never done it this way before, kind of exciting :D)
        P c=K[o=0]=new P{p=D.IndexOf('S')}; // set first state (assignment to c is just to make the lambda shut up about unassigned variables)

        // run bfs
        for(

            System.Action A=()=> // this adds c to the list of states to be expanded, if a whole load of checks pass
            {
                if(//n>0& // we havn't already finished - we don't need this, because we can't win on the first turn, so can't win unless we go forward, which we check last
                   c.p>=0&c.p<W& // c is within bounds
                   System.Array.IndexOf(K,c)<0&& // we havn't seen c yet (the && is to prevent the following lookup IOBing)
                   D[c.p]%8>0) // and we can move here (see table at top of code)
                {
                    T[n]=T[o]+L; // store route
                    K[n]=c; // store state
                    n=D[c.p]==69?-n:n+1; // check if we are at the end, if so, set n to be negative of itself so we know, and can look up the route (otherwise, increment n)
                }
            }

            ;o<n;o++) // o<n also catches n<0
        {
            c=K[o]; // take current
            L="R"; // say we are going right
            c.d=++c.d%6; // turn right
            A(); // go!

            L="L"; // say we are going left
            c.d=(c.d+4)%6; // turn left
            A(); // go!

            L="F"; // say we - you get the picture
            c=K[o];
            c.p+=new[]{~w,1-w,2,1+w,w-1,-2}[c.d%6]; // look up direction of travel (~w = -w-1)
            A();
        }

        // check if we visited the end
        Q.WriteLine(n>0?"Invalid maze!":T[-n]); // if n<0, then we found the end, so spit out the corresponding route, otherwise, the maze is invlida
    }
}

Giống như hầu hết các Tìm kiếm đồ thị của tôi trên trang web này, tôi đang sử dụng tốt các cấu trúc C #, mặc định để so sánh theo giá trị bằng chữ.


2

Python 2, 703 byte

Không tốt như hai phiên bản còn lại, nhưng ít nhất nó cũng hoạt động được haha. Đặt Mvào mê cung.

Vì tôi không có kinh nghiệm trong việc giải quyết các mê cung, nó chỉ đi theo một cách tiếp cận vũ phu, nơi nó sẽ tìm thấy tất cả các giải pháp mà nó có thể không liên quan đến việc vượt qua chính nó. Nó tính toán các lượt từ những cái ngắn nhất, và sau đó chọn kết quả ngắn nhất từ ​​đó.

z=zip;d=z((-1,1,-2,2,-1,1),(-1,-1,0,0,1,1));E=enumerate;D={};t=tuple;o=list;b=o.index
for y,i in E(M.split('\n')):
 for x,j in E(o(i)):
  c=(x,y);D[c]=j
  if j=='S':s=c
  if j=='E':e=c
def P(s,e,D,p):
 p=o(p);p.append(s);D=D.copy();D[s]=''
 for i in d:
  c=t(x+y for x,y in z(s,i))
  if c not in p and c in D:
   if D[c]=='E':L.append(p+[c])
   if D[c]=='+':P(c,e,D,p)
def R(p):
 a=[0,1,3,5,4,2];h=d[0];x=p[0];s=''
 for c in p[1:]:
  r=t(x-y for x,y in z(c,x));n=0
  while h!=r:n+=1;h=d[a[(b(a,b(d,h))+1)%6]]
  s+=['L'*(6-n),'R'*n][n<3]+'F';x=t(x+y for x,y in z(x,h))
 return s
L=[];P(s,e,D,[])
try:l=len(min(L))
except ValueError:print"Invalid maze!"
else:print min([R(i)for i in L if len(i)==l],key=len)

Phiên bản lộn xộn lộn xộn:

maze = """
     0 0 0 0
    0 + 0 + 0
   0 0 0 + + 0
  0 + 0 + 0 + 0
 0 0 + + 0 0 + 0
0 0 + 0 + 0 0 + 0
 E 0 + 0 0 + + 0 
  + + 0 + 0 + 0
   0 0 0 0 0 +
    + 0 + + +
     0 S 0 0
     """
directions = [(-1, -1), (1, -1),
              (-2, 0), (2, 0),
              (-1, 1), (1, 1)]


maze_dict = {}
maze_lines = maze.split('\n')
for y, row in enumerate(maze_lines):
    if row:
        for x, item in enumerate(list(row)):
            coordinates = (x, y)
            maze_dict[coordinates] = item
            if item == 'S':
                start = coordinates
            elif item == 'E':
                end = coordinates

list_of_paths = []


def find_path(start, end, maze_dict, current_path=None):
    if current_path is None:
        current_path = []
    current_path = list(current_path)
    current_path.append(start)
    current_dict = maze_dict.copy()
    current_dict[start] = '0'

    for direction in directions:
        new_coordinate = (start[0] + direction[0], start[1] + direction[1])

        if new_coordinate in current_path:
            pass

        elif new_coordinate in current_dict:
            if current_dict[new_coordinate] == 'E':
                list_of_paths.append(current_path + [new_coordinate])
                break
            elif current_dict[new_coordinate] == '+':
                find_path(new_coordinate, end, current_dict, current_path)


find_path(start, end, maze_dict)


def find_route(path):

    heading_R = [0, 1, 3, 5, 4, 2]
    heading = (-1, -1)
    current_pos = path[0]
    current_heading = directions.index(heading)
    output_string = []
    for coordinate in path[1:]:
        required_heading = (coordinate[0] - current_pos[0], coordinate[1] - current_pos[1])

        count_R = 0
        while heading != required_heading:
            count_R += 1
            heading_index = directions.index(heading)
            heading_order = (heading_R.index(heading_index) + 1) % len(heading_R)
            heading = directions[heading_R[heading_order]]

        if count_R:
            if count_R > 3:
                output_string += ['L'] * (6 - count_R)
            else:
                output_string += ['R'] * count_R

        output_string.append('F')
        current_pos = (current_pos[0] + heading[0], current_pos[1] + heading[1])
    return ''.join(output_string)


routes = []
try:
    min_len = len(min(list_of_paths))
except ValueError:
    print "Invalid maze!"
else:
    for i in list_of_paths:
        if len(i) == min_len:
            routes.append(find_route(i))

    print 'Shortest route to end: {}'.format(min(routes, key=len))

Bạn có thể thay thế if heading != required_heading: while heading != required_heading: chỉ bằngwhile heading != required_heading:
J Atkin

Vâng cảm ơn haha, tôi đã nhận thấy một vài điều bao gồm cả khi thực hiện phiên bản chơi gôn, chỉ không cập nhật mã gốc, tôi sẽ làm điều đó ngay bây giờ vì tôi vừa mới tìm cách loại bỏ thêm một vài nhân vật
Peter

Tốt đẹp! (điền 15 char tối thiểu)
J Atkin

<Đây là thẻ HTML không được nhận dạng, vì vậy SE không thích.>
CalculatorFeline
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.