逆矢印迷路を解く


14

これは「矢印迷路」です。

  v      < 
>     v    
      >  ^ 
>         v
^ <       *

*マークあなたは終了しますスポット。あなたの目標は、迷路の始まりを見つけることです(したがって、逆迷路)。この場合、>2行目の1行目です。

  v------< 
S-+---v  | 
  |   >--^ 
>-+-------v
^ <       *

すべての矢印を使用する必要があることに注意してください。また、行には同じ長さのスペースが埋め込まれると想定できることに注意してください。

プログラムは、妥当な方法(stdin、ファイル、メッセージボックスなど)で迷路を入力する必要ありますが、迷路完全に無傷でなければなりません。たとえば、コンマで区切られた行を入力することはできません。入力は正確に迷路でなければなりません。

迷路の開始を適切な方法で出力する必要があります。たとえば、次のことができます

  • 開始の座標を出力します
  • 開始矢印を置き換えて迷路全体を出力します S
  • 開始矢印を除くすべての矢印を使用して迷路全体を出力します(空白はそのまま!)

どの矢印が開始矢印であるかを出力で判断できれば、問題ありません。たとえば、次の出力

"0"
"2"

改行や引用符に関係なく、開始点がどこにあるかを引き続き確認できるため、問題ありません。

これはであるため、バイト単位の最短コードが優先されます。


各矢印が他の矢印を1つだけ指していると仮定するのは合理的ですか?複数の開始点が存在する可能性があるインスタンスはありませんか?
ダニー14

「迷路の開始」は、他の各矢印が一度アクセスされる矢印ですか?言い換えれば、ダニーの質問+仮定にはループはありません。
塩奈14

3
「コンマで区切られた行を入力することはできません。入力は正確に迷路でなければなりません。」これは不要な制限のようです。「まさに迷路」はすでに行間の改行によって事実上区切られているからです。ある区切り文字を別の区切り文字よりも優先する理由
ジョナサンヴァンマトレ

1
@Doorknobそれは合理的です。なぜなら、「デリミタ」で圧縮ソリューション全体を理論的にエンコードできるからです。ただし、この制限により、特定の言語に対する特定の言語バイアスが導入されると思われます。ルールが「入力行は選択した任意の1文字で区切ることができます。すべての行は同じ文字で区切る必要があります。」上限は、プログラム動作しなければならないドメインを確立するので便利だと思います。
ジョナサンヴァンマトレ14

1
例えば、で、すなわち単に手段@Peter を指している、ではありません。今日コンピューターに戻ったら、もっと編集します。>v^>v^
ドアノブ

回答:


4

GolfScript、55バイト

:&,,{&=42>},.{.&="><^v"?[1-1&n?~.~)]=:d;{d+.&=32=}do}%-

オンラインデモ

すべての入力行に同じ長さのスペースが埋め込まれ、改行で区切られていると仮定します。入力文字列の先頭から開始矢印のバイトオフセットを出力します(たとえば12、チャレンジの迷路の例)。

具体的には、このプログラムは、他の矢印が指し示していないすべての矢印のバイトオフセットを見つけます(すべての矢印が矢印または目標を指していると仮定します。これが正しくない場合、奇妙な動作が発生する可能性があります)。デフォルトでは、そのような矢印が複数ある場合(仕様ごとに、有効な入力では使用できないはずです)、それらのオフセットは出力で単純に連結されます。必要に応じn*て、プログラムに追加して、代わりに改行で区切ることができます。

コメント付きのゴルフバージョン:

:&                     # save a copy of the input string in the variable "&"
,, { &= 42> },         # make a list of the byte offsets of all arrows 
.                      # duplicate the list and apply the following loop to it:
{
  .                    # make a copy of the original offset...
  &=                   # ...and get the corresponding character in the input
  "><^v" ?             # map the arrow character to integers 0 to 3, and...
  [ 1 -1 &n?~ .~) ]=   # ...map these to +1, -1, -len-1 or +len+1, where len is the...
  :d;                  # ...length of the first input line, and save result as "d"
  { d+ . &= 32= } do   # add d to the byte offset until another non-space is found
} %
-                      # subtract the resulting list of target offsets from the
                       # original list of arrow offsets; this should leave exactly
                       # one offset, which is left on the stack for output

1
インラインにすると3文字保存できますw
ハワード

@ハワード:ええ、そうすることができます。ありがとう!ただし、余分なスペースを必要としないように名前を変更zする&必要がありました。オトー、?~.~)すてきな笑顔を作ります。:-)
イルマリカロネン14

5

GolfScript(101 100バイト)

n/:g,,{:&g=:r,,{&1$r='^v<>*'?70429 3base 2/=++}/}%{,4=},.{2<}%:&\{2/~\{[~2$~@+(@@+(\]&1$?)!}do\;}%^`

出力は、[[x y]]座標が両方とも0ベースの形式です。

オンラインデモ

処理は2つのフェーズに分かれています。最初のフェーズでは、迷路を[x y dx dy]タプルの配列に変換します。2番目のフェーズでは、各矢印/アスタリスクが指す矢印/アスタリスクにマップします。(アスタリスクは自分自身を指していると見なされます)。問題の定義により、このマップの結果にはない矢印が1つだけあり、それが解決策です。


あなたがこれを投稿している間に私はちょうど私の答えを貼り付けていました。私たちも同じ考えを持っていましたが、あなたはそれをうまくゴルフすることに成功しました。良いですね!
ヴェレオス14

@PeterTaylor コメントで言及されているポイントスルーケースを正しく処理していることがわかりません。
ハワード

@Howard、そのケースが何なのかわかりません。明確化を求めます。
ピーターテイラー14

入力と出力の例を親切に投稿しますか?
DavidC 14

@DavidCarraher、オンラインデモをご覧ください。stdin ;'STUFF'STUFF介した供給をシミュレートします。
ピーターテイラー14

2

Mathematica 491 323

コメントなしゴルフ

プロシージャは、フィニッシュ( "*")から始まり、それを指す矢印を見つけて、開始に達するまで続きます。

関数、f [maze]。

(* positions of the arrowheads *)
aHeads[a_]:=Position[m,#]&/@{"^","v",">","<"}

(* position of the final labyrinth exit*)
final[a_]:=Position[a,"*"][[1]];


(* find arrowheads that point to the current location at {r,c} *)
aboveMe[{r_,c_},a_]:=Cases[aHeads[a][[2]],{r1_,c}/;r1<r]
belowMe[{r_,c_},a_]:=Cases[aHeads[a][[1]],{r1_,c}/;r1>r]
rightOfMe[{r_,c_},a_]:=Cases[aHeads[a][[4]],{r,c1_}/;c1>c]
leftOfMe[{r_,c_},a_]:=Cases[aHeads[a][[3]],{r,c1_}/;c1<c]

(*find the precursor arrowhead*)
precursor[{loc_,a_,list_:{}}]:=

(* end the search when the precursor has already been traversed or when there is no precursor *)
Which[MemberQ[list,loc],list,
loc=={},list,True,


(* otherwise find the next precursor *)

前駆体[{Flatten [{aboveMe [loc、a]、belowMe [loc、a]、rightOfMe [loc、a]、leftOfMe [loc、a]}、2]、a、Prepend [list、loc]}]]

(* return the path through the maze from start to finish *)
f[maze_]:= precursor[{final[maze[[1]]],maze[[1]]}]

ゴルフ

f@z_:=Module[{p,h,m=z[[1]]},h@a_:=Position[a,#]&/@{"^","v",">","<","*"};
  p[{v_,a_,j_:{}}]:=Module[{r,c,x=Cases},{r,c}=v;
  Which[MemberQ[j,v],j,v=={},j,True,
  p[{Flatten[{x[h[a][[2]],{r1_,c}/;r1<r],x[h[a][[1]],{r1_,c}/;r1>r],
  x[h[a][[4]],{r,c1_}/;c1>c],x[h[a][[3]],{r,c1_}/;c1<c]},2],a,Prepend[j,v]}]]];
  p[{Position[m,"*"][[1]],m}]]

迷路。順序付けられた各ペアには、セルの行と列が含まれます。たとえば、{2、3}は行2、列3のセルを示します。

maze=Grid[Normal@ SparseArray[{{5, 5} -> "*",{1, 2} -> "v", {1, 5} -> "<",{2, 1} -> ">",
   {2, 3} -> "v",{3, 3} -> ">", {3, 5} -> "^",{4, 1} -> ">", {4, 5} -> "v",{5, 1} -> "^", 
   {5, 2} -> "<",{_, _} -> " "}]]

迷路


入力

f[maze]

出力:開始から終了までのパス。

{{2、1}、{2、3}、{3、3}、{3、5}、{1、5}、{1、2}、{5、2}、{5、1}、{ 4、1}、{4、5}、{5、5}}


入力形式が間違っています-「入力は正確に迷路でなければなりません」。
ドアノブ

入力は迷路そのものです。
DavidC 14

私はコードをフォローしていませんが、「入力が迷路になった」ということを解決する方法は陽気です!+1 ...「STDIN is universal」の信者の数は驚くべきものです。
ベリサリウス博士14

入力の問題の解決策に感謝します。
DavidC 14

1

私はこれを解決する良い方法を見つけたと思いますが、たまたまゴルフをするのが嫌になりました。私はこれがずっと短くなると思うので、他の人がそれが良いと思うならそれを使うことができるように私は私の考えを説明するつもりです。

すべての矢印を使用する必要がある場合、すべての矢印は別の矢印で示されますが、1つを除き、それがソリューションです。

つまり、実際に迷路を逆方向に再生する必要はありませんが、左上のものから始めて、各迷路の最も近いポイント可能な矢印をチェックするだけです。これは、大きな迷路の場合の非常に簡単な方法です(4つの方向すべてをチェックする必要はありませんが、1つだけをチェックする必要があるため)。

私のソリューションは次のとおりです。

PHP、622バイト

$h=fopen("a.txt","r");$b=0;while(($z=fgets($h))!==false){$l[$b]=str_split($z,1);$b++;}$v=array("^","<","v",">");$s=array();for($i=0;$i<count($l);$i++){for($j=0;$j<count($l[0]);$j++){if(in_array($l[$i][$j],$v)){switch($l[$i][$j]){case"^":$c=$i-1;while($l[$c][$j]==" ")$c--;$s[]=$c.",".$j;break;case"v":$c=$i+1;while($l[$c][$j]==" ")$c++;$s[]=$c.",".$j;break;case"<":$c=$j-1;while($l[$i][$c]==" ")$c--;$s[]=$i.",".$c;break;case">":$c=$j+1;while($l[$i][$c]==" ")$c++;$s[]=$i.",".$c;break;}}}}for($i=0;$i<count($l);$i++){for($j=0;$j<count($l[0]);$j++){if(in_array($l[$i][$j],$v)){if(!in_array($i.",".$j,$s)){echo$i.",".$j;}}}}

ゴルフをしていない:

$h=fopen("a.txt","r");
$b=0;
while(($z=fgets($h))!==false) {
    $l[$b]=str_split($z,1);
    $b++;
}
//Input ends here
$v = array("^","<","v",">");
$s = array();
//Here i check every arrow, and save every pointed one in $s
for($i=0;$i<count($l);$i++){
    for($j=0;$j<count($l[0]);$j++){
        if(in_array($l[$i][$j],$v)){
            switch($l[$i][$j]) {
                case "^":
                    $c=$i-1;
                    while ($l[$c][$j]==" ")
                        $c--;
                    $s[]=$c.",".$j;
                    break;
                case "v":
                    $c=$i+1;
                    while ($l[$c][$j]==" ")
                        $c++;
                    $s[]=$c.",".$j;
                    break;
                case "<":
                    $c=$j-1;
                    while ($l[$i][$c]==" ")
                        $c--;
                    $s[]=$i.",".$c;
                    break;
                case">":
                    $c=$j+1;
                    while ($l[$i][$c]==" ")
                        $c++;
                    $s[]=$i.",".$c;
                    break;
            }
        }
    }
}
//I check if the arrow is in $s. If not, we have a solution.
for($i=0;$i<count($l);$i++){
    for($j=0;$j<count($l[0]);$j++){
        if (in_array($l[$i][$j],$v)){
            if (!in_array($i.",".$j,$s)){
                echo$i.",".$j;
            }
        }
    }
}

1

PHP -492バイト

$r=split("\n",$m);$h=count($r);foreach($r as &$k)$k=str_split($k);$l=count($r[0]);$e=strpos($m,"*")+1-$h;$a=$x=$e%$l;$b=$y=floor(($e-$x)/$l);do{$c=0;for(;--$a>=0;){if($r[$b][$a]==">"){$x=$a;$c++;}if($r[$b][$a]!=" ")break;}$a=$x;for(;--$b>=0;){if($r[$b][$a]=="v"){$y=$b;$c++;}if($r[$b][$a]!=" ")break;}$b=$y;for(;++$a<$l;){if($r[$b][$a]=="<"){$x=$a;$c++;}if($r[$b][$a]!=" ")break;}$a=$x;for(;++$b<$h;){if($r[$b][$a]=="^"){$y=$b;$c++;}if($r[$b][$a]!=" ")break;}$b=$y;}while($c>0);echo "$x-$y";

このソリューションは、マップがローカル変数で見つかることを前提としています$m。渡すための最短の方法は、経由で$_GET$m=$_GET['m'];14バイトです。読みやすくするために、変数にマップが含まれるバージョンはありません。

$m=<<<EOT
  v      < 
>     v    
      >  ^ 
>         v
^ <       * 
EOT;

$r=split("\n",$m);
$h=count($r);
foreach($r as &$k)
    $k=str_split($k);
$l=count($r[0]);

$e=strpos($m,"*")+1-$h;

$a=$x=$e%$l;
$b=$y=floor(($e-$x)/$l);
do{
$c=0;
for(;--$a>=0;)
    {
        if($r[$b][$a]==">"){$x=$a;$c++;}
        if($r[$b][$a]!=" ")break;
    }
$a=$x;
for(;--$b>=0;)
    {
        if($r[$b][$a]=="v")
            {
                $y=$b;
                $c++;
            }
        if($r[$b][$a]!=" ")break;

    }
$b=$y;
for(;++$a<$l;)
    {
        if($r[$b][$a]=="<")
            {
                $x=$a;
                $c++;
            }
        if($r[$b][$a]!=" ")break;
    }
$a=$x;
for(;++$b<$h;)
    {
        if($r[$b][$a]=="^")
            {
                $y=$b;
                $c++;
            }
        if($r[$b][$a]!=" ")break;
    }
$b=$y;
}while($c>0);
echo "$x-$y";

1

K、281 277 258

{{$[&/x in*:'{{~"*"=x 1}{(s;k . s;k;s:*1_w@&(k ./:w:{{x@&x in y}[(*:'{(x[1]@x 0;x 1)}\[x;(z;y)]);i]}[(h!b,b,a,a:#k:x 2)m;(h!(0 1+;0 -1+;1 0+;-1 0+))m:x 1;x 0])in"*",h:"><v^")}\(x;y;z;x)}[*x;y .*x;y];*x;.z.s[1_x]y]}[i@&~(x ./:i::,/(!#x),/:\:!b::#*x)in" *";x]}

これは以前のバージョンです

solve:{[x]
    //j - indices of all possible starting points
    //i - every index
    j::i@&~(x ./:i::,/(!a:#x),/:\:!b:#*x) in " *";

    h::">v<^";

    //d - dictionary mapping each directional character to
    //    increment/decerement it needs to apply to the x/y axis
    d::h!((::;1+);(1+;::);(::;-1+);(-1+;::));

    //e - dictionary mapping each directional character to
    //    the maximum number of moves it should make in a 
    //    given direction
    e::h!b,a,b,a;

    //f - function to produce the indices of each point that is 
    //    passed once we move in a certain direction from a 
    //    certain index
    f::{{x@&x in y}[(last'{(x[0];x[0]@'x 1)}\[x;(y;z)]);i]};

    //g - function that, given a starting and a direction,
    //    moves in that direction until hitting another directional
    //    character. It then moves in the new direction etc. until
    //    it reaches the end point -- *
    g::{[x;y;z]
        {[x]
            q:x 0;m:x 1; k:x 2;
            w:f[e m;d m;q];
            s:*1_w@&(k ./:w)in h,"*";
            m:k . s;
            (s;m;k;s)}\[{~"*"=x 1};(x;y;z;x)]};

    // recursive function that starts at the first possible starting point
    // and plots its way to the end. If all other potential starting points
    // have been touched in this path, then this is the correct starting point.
    // else, recursively call the function with the next possible starting point
    :{$[min "b"$j in last'g[*x;y . *x;y];*x;.z.s[1_x;y]]}[j;x]
  }

x y0ベースのインデックスと同様に開始点を返します。

k)maze
"  v      < "
">     v    "
"      >  ^ "
">         v"
"^ <       *"
k)solve maze
1 0

1

Python 422

with open("m.txt","r") as f:m=f.read().split("\n")
p=[(v.find("*"),p) for p,v in enumerate(m) if "*" in v][0]
g=[]
def f(a):
    x,y=b,c=a
    for p,i in enumerate((lambda x:[l[x] for l in m])(x)):
        if i in "^>v<" and((p<y and i=="v")or(p>y and i=="^")):return b,p
    for p,i in enumerate(m[y]):
        if i in "^>v<" and((p<x and i==">")or(p>x and i=="<")):return p,c
while True:
    z=f(p)
    if z in g:break
    else:g.append(z);p=z
print p

入力はと呼ばれるファイルにありますm.txt。出力は(x, y)最後ですが、最後のprintステートメントをに変更するprint gと、出力は[(x, y), (x, y), ...]、最後から最初までのすべてのステップを含むリストになります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.