六角形の迷路の時間!


27

別の迷路チャレンジの時間ですが、あなたが知っているようにではありません。

このチャレンジのルールは、ほとんどの迷路チャレンジとは少し異なります。タイルタイプは次のように定義されます。

  • S:迷路の開始位置
  • E:取得しようとしている場所
  • 0:交差できない壁
  • +:横断できる床

6つの方向のいずれかで移動できます:左上、右上、左、右、下左、または右下。

\ /
-S-
/ \

迷路はラップしません。目標は、から取得する最短パス文字列を見つけるSことEです。

入力:

入力は、示されている迷路のようなスペースで区切られた線です。後続スペースは行に続きません。

出力:

文字列RLおよびF場所

  • R 右(時計回り)に60度回転します
  • L 左(反時計回り)に60度回転します
  • F あなたが指している方向に1スペース移動します

指さし始める left-up

最短パスは、訪問された位置の数ではなく、生成された文字列の長さによってカウントされます。プログラムは、ソリューションとして最短パスを印刷する必要があります。

迷路が解決できない場合は、出力する必要がありますInvalid 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

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

(いくつかの迷路には同じ長さの他のソリューションがありますが、ここにはリストされていません)


27
六角形の解決策を期待しています...
bkul

3
Hexagonyソリューションに500ポイントの報奨金を授与します。
リルトシアスト

@lirtosiast2年後、私はヘキサゴニーがこの問題のストレッチかもしれないと思う;)
Jアトキン

あと数年待ちましょう。
user202729

末尾に改行を入れることはできますか?
user202729

回答:


17

Python 2、291バイト

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!"

関数、f迷路を行のリストとして取得し、ソリューションが存在する場合はそれを返します。

説明

実行から最短経路を見つけるための位置/方向のペアのグラフに幅優先探索SとをE

興味深いのは、単純な「ステップ」(つまり、特定の方向への移動)と回転を許可する六角形グリッド上の位置と方向を表すコンパクトな方法を見つけることです。ここで複素数を使用して「実際の」六角形グリッド上の座標を表すのは魅力的ですが、これはいくつかの理由からあまり良い考えではありません。最も深刻なのは、√3をプラグインする必要があるという事実ですどこかで動作させる(sin 60°=√3/ 2)。これは、浮動小数点数を使用する場合、絶対精度が必要な場合は不要です(たとえば、既に訪れた状態を追跡するためなど)。 JavaScriptコンソールを起動して入力Math.sqrt(3)*Math.sqrt(3) == 3し、自分で確認してみてください。

しかし、ちょっとしたトリックを使用できます!複素数を使用する代わりに、同様の静脈内の六角形の数値を実数のペアa + bhとして定義しましょう。ここで、hは複素数を扱うときに虚数iと同様の役割を果たします。複素数の場合と同様に、ペア(ab)を平面上の点に関連付けることができます。実際の軸は右を指し、虚軸は60°を指し、実数と虚数部はそれぞれ1です。この座標系を迷路のセルにマッピングするのは簡単です。

図1

iとは異なり、定数hh 2 = h -1の関係で定義されます(hを解くと洞察が得られる場合があります)。上記の関係を使用して、複素数のように六角形の数を追加および乗算できます:(a + bh)+(c + dh)=(a + c)+(b + dh
および(a + bh)・(c + dh)=(ac - bd)+( +ad + bc + bdh。これらの演算は、対応する複雑な演算と同じ幾何学的解釈を持ちます:加算はベクトル加算で、乗算はスケーリングと回転です。特に、六角形の数値を反時計回りに60°回転させるには、hを乗算します:
a + bh)・h = -b +(a + bh、および同じ数値を時計回りに60°回転させるには、除算しますによってh
a + bh)/ h =(a bh)・(1- h)=(a + b)-ah。たとえば、右を指す六角形の単位、1 =(1、0)、完全な円、反時計回りに、hを 6回掛けることで、次のようになります。
(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)。

プログラムはこの方法で六角形の数字を使用して、迷路内の現在の位置と現在の方向を表し、指定された方向に進み、方向を左右に回転させます。


31

六角形、2437バイト

待望のプログラムはこちらです:

(.=$>({{{({}}{\>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'&?={&?#<$

オンラインでお試しください!

「読み取り可能」バージョン:

                             ( . = $ > ( { { { ( { } } { \ > 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 ' & ? = { & ? # < $

Esoteric IDEでテスト済み:TIOはいくつかの大きなテストケースでタイムアウトする場合がありますが、すべて検証済みです。Timwiのおかげで、IDEなしではこれは不可能でした。

かなりの空きスペースがありますので、これを横の長さ28の六角形(横の長さ29の代わりに)に合わせることができたかもしれませんが、それは大規模なタスクになるので、たぶんそれを試みるつもりはありません。

基本的な説明

画像をクリックすると、より大きく詳細なバージョンが表示されます。

関数

関数
注:部門は一般に正しいですが、時折大まかな推測になる場合があります。

このコードは非常に「機能的」です-Hexagonyが許す限り。このコードには8つの主要な関数があり、上の図でラベルが付けられており、呼び出された番号で名前が付けられています(したがって、命令ポインター番号はそのmod 6です)。呼び出しの(大まかな)順序では、それらは次のとおりです(引用された名前は、後で説明するメモリ内の場所です)。

  • S:出発関数は-次に3つの経路を有する「パス・スタック」を開始し、「参照配列」まで入力及び設定を読み取りFRおよびLメイン処理の準備。命令ポインター0は機能0に移動し、実行は機能1に移動します。
  • 1(-11):メイン関数-2を使用してパスを取得し、3を使用してその有効性を確認し、有効な場合は機能-110 / -10を2回、4を3回使用して新しいパスを「パス」にコピーしますスタック」、それ自体に戻ることによって終了します。パスが終了位置にある場合、関数5を呼び出すことができます。
  • 2:処理の準備ができている「パススタック」から次のパスを取得し、スタックにパスが残っていない場合は関数-1を呼び出します。関数1に戻ります。
  • 3:値のペアと移動番号を取得し、「参照配列」をチェックして、現在のパスが有効な場所で終了したかどうかを確認します。有効な場所は、最初の3移動以内の開始、または+最初に到達した2移動以内のいずれかです。関数1に戻ります。
  • -10 / -110:現在のパスをコピーします。関数1に戻ります。
  • 0:機能1を使用して、移動の方向を管理しFます。関数1に戻ります。
  • 4:電流経路のコピーを取得し、いずれかの機能を有する同一のパスに1つの変更を連結FRまたはL添付。関数1に戻ります。
  • 5:パスを取得し、正しいパス(例:)を出力してFFLF、プログラムを終了します。
  • -1:印刷Invalid maze!して終了します。
  • (二重矢印):スペースが不足しているため、機能1 / -11は機能-1の上のスペースに移動する必要がありました。

記憶

メモリレイアウト
注:図についてはEsoteric IDEに再度感謝します

メモリは、3つの主要部分で構成されています。

  • 参照配列:グリッドは2列離れて保存され、各ステップに値があります:
    • 0のいずれかを表し 0より多くの移動前に任意の方向に場所を終了するために必要とされるよりもアクセスしたか、有効な場所を。
    • 1 +はまだ到達していないを表します。
    • (大きい数字)は、任意の方向にその場所を出るのに十分な動きがあるはずの手番を表します。
    • 10も改行を表します。これらは、最後の空白以外の文字の直後にあると仮定して到達することはありません。
  • Rail:左側に-1単一のsで構成され、-2メモリポインタがコア処理領域にすばやく戻ることができます。
  • パススタック:テストされていない各パスをパスIDの順に格納します(これは移動番号に直接関連しているため、短いパスが最初にテストされます)。パスは次のように保存されます。
    パスレイアウト
    • Rot:現在のパスの終点での回転:0で左上、時計回りに5まで増加
    • 移動:現在の移動番号(指示-1)
    • パス:電流経路と第四に格納されているFRLとして123それぞれ
    • x / y:現在のパスの終わりの座標:x + 1 -1s右、y値上(ただし、参照データからレールを分離するためにy = 0は1として処理されます)

その他の重要なメモリの場所:

  1. のx / yはEここに保存されます。
  2. このスペースは、メモリ内外のパスを移行するために使用されます。
  3. この場所は、処理中に各パスが保存される場所の中心です。

次のステップは、プログラムを通してプログラムを実行し、最短の迷路ルートを見つけることです。
ベスカ

誰かがそれを投稿することを知っています。最後に... /別の計画もありますが、おそらくあなたよりも少ないコードで済むはずです。実際に実装する時間はありません。
user202729

@ user202729は興味深いものです。この方法は、おそらく少なくとも2サイズ下までゴルフできますが、ほぼ確実にもっと良いものがあります。
boboquack

1
@lirtosiastを待っています。
Jアトキン

1
遅延の謝罪。
リルトシアスト

6

Python 3、466バイト

深さ優先検索などを使用した場合、おそらく小さくなっていたでしょう。この怪物はダイクストラを使用し、非常に高速ですが、非常に長いです。

このコードはS、迷路で複数行の文字列を受け取り、結果を返す関数を定義しています。

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]

これがコードのテストです。

非ゴルフ

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

わあとてもいいです これはあなたが書くのにどれくらいかかりましたか?
Jアトキン

1
@JAtkinまあ、ファイルは1.5時間前に作成されましたが、実際にコードの作業に費やした時間はわかりません。また、ここは午前3時なので、私の生産性は明らかに最大です。
PurkkaKoodari

ニース、私は2+時間を費やし、私のほとんどはすでに標準的な迷路のために書かれていました。
Jアトキン

未使用のバージョンはありますか?
Jアトキン

1
@JAtkin必要なのは、最初に向きを変える必要があるかもしれないからです。開始位置がなければ動作しL,,Rます。
PurkkaKoodari

3

Groovy、624バイト。フォア!

時間は大きなボールでボールを転がします。argとして複数行の文字列を取りますQ

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!")}

ゴルフされていないバージョン:

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バイト

完全なプログラム。STDINからの入力を受け入れ、STDOUTに出力します。

編集:ラップ処理にバグがあり(特定のテストケースで破損しなかった)、1バイト追加されたので、それを補うためにもう少しゴルフをしました。

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

地図を読んで、最初に追加します (各行して終了位置を確認し、戻ってスペースの負荷を追加してマップを長方形にし、右側にスペースの行を追加することで開始します(これにより、以下で説明するように、ラッピングチェックを行います)。この中のある時点で長方形の幅を計算し、マップの全長を確認します。

次に、幅優先検索のすべてを初期化します。2つの大きな配列が作成されます。1つは検索で探索する必要があるすべての状態を格納し、もう1つは各状態に到達するまでのルートを記録します。初期状態が期限付き配列に追加され、頭と尾のポインターが上記のように事前に設定されます。すべてが1から始まります。

次に、尾が頭に衝突するか、少なくとも頭に衝突したように見えるまで繰り返します。訪問した状態ごとに、左または右に回転した同じ位置に新しい状態を追加し、次に前方に移動した状態に追加しようとします。方向にはインデックスが付けられ、初期方向(デフォルトは0)が「左上」に対応します。

状態をキューに入れようとすると、右側のスペースの列が「ここにいることを許可されていますか?」によって選択されるため、状態はバインドチェックされますが、ラップチェックはされません。チェックしてください(スペースにいることはできません)。状態がキューに入れられている場合は、Eセルにあるかどうかを確認し、セルにある場合は、キューの先頭をマイナス自体に設定します。これにより、メインループが終了し、プログラムの最後の行に印刷が指示されます失敗メッセージではなく、対応するルートを出力します(拡張する状態がなくなると表示されます(テールがヘッドにクラッシュします)。

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

このサイトでのほとんどのグラフ検索と同様に、C#構造体を活用しています。これはデフォルトでリテラル値で比較されます。


2

Python 2、703バイト

他の2つのバージョンほどではありませんが、少なくともうまくいきます。M迷路に設定します。

私は迷路を解決した経験がないので、それは総当たり的なアプローチで行われます。そこでは、それ自体を乗り越えることを伴わない、可能な解決策をすべて見つけます。最短のターンからターンを計算し、それから最短の結果を選択します。

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)

乱雑なバージョン

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

あなたは置き換えることができますif heading != required_heading: while heading != required_heading: だけでwhile heading != required_heading:
Jアトキン

笑おかげええ、私はgolfedバージョンをやったときに、私はほんの数以上の文字剃り落とすに管理しているので、私は今、そのビットをやる、元のコードを更新しなかったことなど、いくつかのことに気づいたのだ
ピーター

いいね!(15文字分を満たす)
Jアトキン

<これは認識されないHTMLタグなので、SEは好きではありません。>
CalculatorFeline
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.