Giải quyết một mê cung mũi tên ngược


14

Đây là một "mê cung mũi tên":

  v      < 
>     v    
      >  ^ 
>         v
^ <       *

Các *điểm đánh dấu nơi bạn sẽ hoàn thành. Mục tiêu của bạn là tìm nơi mê cung bắt đầu (do đó, mê cung đảo ngược). Trong trường hợp này, nó là dòng đầu tiên >trên dòng thứ hai.

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

Lưu ý rằng tất cả các mũi tên phải được sử dụng. Cũng lưu ý rằng bạn có thể giả sử các dòng sẽ được đệm với khoảng trắng có độ dài bằng nhau.

Chương trình của bạn phải nhập mê cung theo bất kỳ cách hợp lý nào (stdin, từ tệp, hộp thông báo, v.v.), tuy nhiên mê cung phải hoàn toàn nguyên vẹn. Ví dụ: bạn không thể nhập các dòng được phân tách bằng dấu phẩy; đầu vào phải chính xác là mê cung.

Bạn phải xuất ra điểm bắt đầu của mê cung theo bất kỳ cách hợp lý nào. Ví dụ, bạn có thể

  • xuất tọa độ của điểm bắt đầu
  • xuất toàn bộ mê cung bằng mũi tên bắt đầu được thay thế bằng S
  • xuất toàn bộ mê cung với tất cả các mũi tên trừ mũi tên bắt đầu bị loại bỏ (khoảng trắng còn nguyên vẹn!)
  • Vân vân.

Miễn là bạn có thể biết đầu ra của mình mũi tên nào là mũi tên bắt đầu, thì không sao. Ví dụ: đầu ra của

"0"
"2"

không sao, bất kể dòng mới và trích dẫn, bởi vì bạn vẫn có thể biết nơi bắt đầu.

Đây là , vì vậy mã ngắn nhất tính bằng byte sẽ giành chiến thắng.


Có hợp lý không khi cho rằng mỗi mũi tên chỉ có một mũi tên khác chỉ vào nó? Sẽ không có một trường hợp nào có thể có nhiều điểm bắt đầu ở đó?
Daniel

Có phải "bắt đầu mê cung" là một mũi tên mà từ đó mũi tên của nhau được truy cập một lần không? Nói cách khác, câu hỏi của danny + giả định không có vòng lặp.
shiona

3
"bạn không thể nhập các dòng được phân tách bằng dấu phẩy; đầu vào phải chính xác là mê cung." Điều này có vẻ như là một hạn chế không cần thiết, vì "chính xác là mê cung" đã được giới hạn trên thực tế bởi các dòng mới giữa các hàng. Tại sao ưu tiên một dấu phân cách hơn một dấu phân cách khác?
Jonathan Van Matre

1
@Doorknob Điều đó hợp lý, vì về mặt lý thuyết, người ta có thể mã hóa toàn bộ giải pháp nén trong "dấu phân cách". Tuy nhiên, tôi nghi ngờ rằng sự hạn chế đưa ra một khuynh hướng ngôn ngữ nhất định đối với các ngôn ngữ nhất định. Điều gì xảy ra nếu quy tắc là "Các hàng đầu vào có thể được phân tách bằng bất kỳ một ký tự nào bạn chọn. Tất cả các hàng phải được phân cách bằng cùng một ký tự."? Tôi nghĩ rằng giới hạn trên là hữu ích vì nó thiết lập một miền trong đó chương trình của bạn phải hoạt động.
Jonathan Van Matre

1
@ Peter Đó chỉ là phương tiện đó, ví dụ, trong >v^các >trỏ đến v, không phải là ^. Tôi sẽ chỉnh sửa nhiều thứ hơn khi tôi trở về nhà với máy tính ngày hôm nay.
Doorknob

Câu trả lời:


4

GolfScript, 55 byte

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

Bản demo trực tuyến

Giả sử rằng tất cả các dòng đầu vào được đệm với các khoảng trắng có cùng độ dài và được phân tách bằng các dòng mới. Xuất ra phần bù byte của mũi tên bắt đầu từ đầu chuỗi đầu vào (ví 12dụ như mê cung ví dụ trong thử thách).

Cụ thể, chương trình này tìm thấy các byte của tất cả các mũi tên không có mũi tên nào khác chỉ vào chúng (giả sử rằng tất cả các mũi tên đều chỉ vào một mũi tên hoặc mục tiêu; hành vi lạ có thể xảy ra nếu điều này không đúng). Theo mặc định, nếu có một số mũi tên như vậy (mà, trên mỗi thông số, không thể có trong đầu vào hợp lệ), thì phần bù của chúng sẽ chỉ được nối vào đầu ra. Nếu bạn muốn, bạn có thể nối thêm n*vào chương trình để phân tách chúng bằng các dòng mới thay thế.

Phiên bản bỏ chơi golf với ý kiế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
Bạn có thể lưu 3 ký tự nếu bạn nội tuyến w.
Howard

@Howard: Huh, vậy tôi có thể. Cảm ơn! Tuy nhiên, phải đổi tên zđể &tránh cần thêm một không gian. OTOH, ?~.~)làm cho một nụ cười khá đẹp. :-)
Ilmari Karonen

5

GolfScript ( 101 100 byte)

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

Đầu ra ở dạng [[x y]]tọa độ đều dựa trên 0.

Bản demo trực tuyến

Quá trình xử lý gồm hai giai đoạn: giai đoạn đầu biến mê cung thành một mảng các [x y dx dy]bộ dữ liệu; giai đoạn thứ hai ánh xạ mỗi mũi tên / dấu sao vào mũi tên / dấu hoa thị mà nó trỏ tới. (Dấu hoa thị được coi là chỉ vào chính họ). Theo định nghĩa của vấn đề, có chính xác một mũi tên không nằm trong kết quả của bản đồ này và đó là giải pháp.


Tôi chỉ dán câu trả lời của tôi trong khi bạn đăng này. Chúng tôi có cùng một ý tưởng, nhưng bạn đã xoay sở thành công. Đẹp quá
Vereos

@PeterTaylor tôi không thể thấy rằng nó xử lý các điểm thông qua trường hợp một cách chính xác được đề cập trong các ý kiến.
Howard

@Howard, tôi không biết trường hợp đó là gì. Sẽ yêu cầu làm rõ.
Peter Taylor

Bạn có vui lòng gửi một ví dụ về đầu vào và đầu ra của bạn?
DavidC

@DavidCarraher, xem bản demo trực tuyến. ;'STUFF'mô phỏng cung cấp STUFFqua stdin.
Peter Taylor

2

Toán học 491 323

Ung dung với ý kiến

Quy trình bắt đầu từ kết thúc ("*"), tìm mũi tên chỉ vào nó, và cứ thế cho đến khi bắt đầu.

Hàm, f [mê cung].

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

tiền thân [{Flatten [{phía trên [[,

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

Chơi gôn

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

Thí dụ

Mê cung. Mỗi cặp theo thứ tự chứa hàng và cột của một ô. Ví dụ: {2, 3} biểu thị ô ở hàng 2, cột 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} -> "<",{_, _} -> " "}]]

mê cung


Đầu vào

f[maze]

Đầu ra : Đường dẫn từ đầu đến cuối.

{{2, 1}, {2, 3}, {3, 3}, {3, 5}, {1, 5}, {1, 2}, {5, 2}, {5, 1}, { 4, 1}, {4, 5}, {5, 5}}


Định dạng đầu vào của bạn sai - "đầu vào phải chính xác là mê cung".
Doorknob

Đầu vào bây giờ là mê cung chính nó.
DavidC

Tôi đã không tuân theo mã, nhưng cách bạn giải quyết "đầu vào bây giờ là mê cung" thật vui nhộn! +1 ... số lượng tín đồ trong "STDIN là phổ quát" thật đáng kinh ngạc.
Tiến sĩ belisarius

Tôi rất vui vì bạn đánh giá cao giải pháp cho vấn đề đầu vào.
DavidC

1

Tôi nghĩ rằng tôi đã tìm thấy một cách tốt để giải quyết vấn đề này, nhưng tôi đã vô tình chơi golf. Tôi đoán đây có thể là CÁCH ngắn hơn, vì vậy tôi sẽ giải thích ý tưởng của mình để những người khác có thể sử dụng nó nếu họ thấy nó tốt.

Nếu mỗi mũi tên phải được sử dụng, thì tất cả các mũi tên sẽ được chỉ bởi một mũi tên khác, ngoại trừ một mũi tên, đó là giải pháp của chúng tôi.

Điều này có nghĩa là chúng ta thực sự không phải chơi mê cung ngược, nhưng, bắt đầu từ góc trên bên trái, chúng ta chỉ cần kiểm tra mũi tên có thể chỉ ra gần nhất cho mỗi cái. Đây là một painsaver thực sự cho mê cung lớn hơn (vì bạn không phải kiểm tra tất cả bốn hướng, nhưng chỉ một hướng).

Đây là giải pháp của tôi:

PHP, 622 byte

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

Ung dung:

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

$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";

Giải pháp này cho rằng bản đồ có thể được tìm thấy trong biến cục bộ $m. Phương pháp ngắn nhất tôi có để truyền đó là thông qua $_GET: $m=$_GET['m'];ở mức 14 byte. Một phiên bản không có bản đồ với biến bản đồ được cung cấp dưới đây để đọc rõ ràng.

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

Đây là phiên bản cũ hơn

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

Trả về điểm bắt đầu như x yvới 0 chỉ số dựa trên.

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

1

Con trăn 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

Đầu vào là trong một tập tin gọi là m.txt. Đầu ra là (x, y)nhưng nếu bạn thay đổi câu lệnh in cuối cùng thành print g, đầu ra sẽ là một danh sách giống như [(x, y), (x, y), ...]với tất cả các bước để có được từ đầu đến cuối.

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.