解决反向箭头迷宫


14

这是一个“箭头迷宫”:

  v      < 
>     v    
      >  ^ 
>         v
^ <       *

*标志的地方在那里你会完成。您的目标是找到迷宫的起始位置(因此称为反向迷宫)。在这种情况下,它>是第二行的第一行。

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

请注意,必须使用所有箭头。另请注意,您可以假设将用等长的空格填充行。

您的程序必须以任何合理的方式输入迷宫(从文件,消息框等输入stdin),但是迷宫必须是完整的。例如,您不能输入以逗号分隔的行;输入必须完全是迷宫。

您必须以任何合理的方式输出迷宫的起点。例如,您可以

  • 输出起点的坐标
  • 输出整个迷宫,开始箭头替换为 S
  • 输出除开始箭头外的所有箭头的整个迷宫(保留空白)!
  • 等等

只要您可以通过输出判断哪个箭头是开始箭头,那么就可以了。例如,输出

"0"
"2"

没关系,无论换行和引号如何,因为您仍然可以知道开始的位置。

这是,因此以字节为单位的最短代码将获胜。


假设每个箭头只有一个指向它的箭头是否合理?不会有可能存在多个起点的实例吗?
Danny

“迷宫的开始”是一个箭头,从该箭头可以一次访问另一个箭头吗?换句话说,丹尼的问题+假设没有循环。
shiona 2014年

3
“您不能输入用逗号分隔的行;输入必须完全是迷宫。” 这似乎是不必要的限制,因为事实上 “迷宫”实际上已经由行之间的换行符分隔。为什么要优先于一个定界符?
乔纳森·范·马特雷

1
@Doorknob这是合理的,因为理论上可以在“定界符”中编码整个压缩解决方案。但是,我确实怀疑该限制会对某些语言造成某种语言偏见。如果规则是“输入行可以由您选择的任何一个字符分隔。所有行必须由相同的字符分隔”怎么办?我认为上限是有用的,因为它确定了程序必须在其中运行的域。
乔纳森·范·马特雷2014年

1
@Peter,例如,在只是意味着>v^>所指向的v,不是^。今天,当我回到计算机时,我将编辑更多内容。
门把手

Answers:


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

@霍华德:嗯,我可以。谢谢!不过必须重命名z&避免需要额外的空间。OTOH,?~.~)笑得很漂亮。:-)
Ilmari Karonen 2014年

5

GolfScript(101 100个字节)

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

输出的形式[[x y]]是坐标都基于0。

在线演示

处理分为两个阶段:第一阶段将迷宫转变为[x y dx dy]元组数组;第二阶段将迷宫变为元组数组。第二阶段将每个箭头/星号映射到其指向的箭头/星号。(星号被认为指向自己)。根据问题的定义,此地图的结果中没有一个箭头,这就是解决方案。


当您发布此消息时,我只是粘贴我的答案。我们有相同的想法,但您成功地实现了目标。好一个!
Vereos 2014年

@PeterTaylor我不能看到它处理通过点的情况下正确这是在评论中提到。
霍华德

@霍华德,我不知道那是什么情况。将要求澄清。
彼得·泰勒

您能张贴一个输入和输出示例吗?
DavidC

@DavidCarraher,请参阅在线演示。;'STUFF'模拟STUFF通过stdin的供应。
彼得·泰勒

2

数学491 323

取消评论

该过程从结束符(“ *”)开始,找到指向该结束符的箭头,依此类推,直到到达起点为止。

函数f [迷宫]。

(* 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 2014年

我没有遵循代码,但是解决“输入现在是迷宫”问题的方法很有趣!+1 ...“ STDIN具有普遍性”的信徒人数惊人。
belisarius博士2014年

我很高兴您赞赏输入问题的解决方案。
DavidC

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个字节。为了清楚起见,下面提供了带有映射in的ungolf版本。

$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 y与基于0的索引一样返回起点。

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), ...]从头到尾的所有步骤。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.