Решите обратную стрелку лабиринта


14

Это «стрелка лабиринта»:

  v      < 
>     v    
      >  ^ 
>         v
^ <       *

В *отмечает место , где вы закончите. Ваша цель - найти, где начинается лабиринт (следовательно, обратный лабиринт). В данном случае это первый >на второй строке.

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

Обратите внимание, что все стрелки должны быть использованы. Также обратите внимание, что вы можете предположить, что строки будут дополнены пробелами равной длины.

Ваша программа должна вводить лабиринт любым разумным способом (стандартный, из файла, окна сообщения и т. Д.), Однако лабиринт должен быть полностью неповрежденным. Например, вы не можете вводить строки, разделенные запятыми; вход должен быть точно лабиринт.

Вы должны вывести начало лабиринта любым разумным способом. Например, вы могли бы

  • вывести координаты старта
  • выведите весь лабиринт со стрелкой начала, замененной на S
  • вывести весь лабиринт со всеми стрелками, кроме удаленной стартовой (пробел не поврежден!)
  • и т.п.

До тех пор, пока по выходным данным вы можете определить, какая стрелка является стрелкой начала, все в порядке. Например, вывод

"0"
"2"

все в порядке, независимо от новых строк и кавычек, потому что вы все еще можете сказать, где было начало.

Это , поэтому выиграет самый короткий код в байтах.


Разумно ли предположить, что каждая стрелка имеет только одну стрелку, указывающую на нее? Не будет случая, когда может быть несколько отправных точек?
Дэнни

Является ли «начало лабиринта» стрелой, из которой одна стрелка посещается один раз? Другими словами, вопрос Дэнни + предположение, что петель нет.
Шион

3
«Вы не можете вводить строки, разделенные запятыми; ввод должен быть именно лабиринтом». Это кажется ненужным ограничением, поскольку «именно лабиринт» уже де-факто разграничен переносами строк. Зачем отдавать приоритет одному разделителю над другим?
Джонатан Ван Матр

1
@ Doorknob Это разумно, поскольку теоретически можно закодировать все сжатое решение в «разделители». Тем не менее, я подозреваю, что ограничение вводит определенный лингвистический уклон против определенных языков. Что если бы правило гласило: «Входные строки могут быть разделены любым одним символом по вашему выбору. Все строки должны быть разделены одним и тем же символом.»? Я думаю, что верхняя граница полезна, потому что она устанавливает домен, в котором должна работать ваша программа .
Джонатан Ван Матр

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чтобы &избежать необходимости дополнительного места, хотя. ОТО, ?~.~)делает довольно хороший смайлик. :-)
Илмари Каронен

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

@PeterTaylor Я не вижу, чтобы он правильно обрабатывал точку через случай, что упоминается в комментариях.
Говард

@ Говард, я понятия не имею, что это за дело. Будем просить разъяснений.
Питер Тейлор

Не могли бы вы опубликовать пример вашего ввода и вывода?
DavidC

@DavidCarraher, посмотрите онлайн демо. ;'STUFF'имитирует подачу STUFFчерез стандартный ввод.
Питер Тейлор

2

Mathematica 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], bottomMe [loc, a], rightOfMe [loc, a], leftOfMe [loc, a]}, 2], a, Prepend [список, loc]}]]

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

Golfed

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

Я не следовал за кодом, но способ, которым вы решили "ввод - теперь лабиринт" , забавен! +1 ... число верующих в "STDIN универсален" поразительно.
Доктор Велизарий

Я рад, что вы оценили решение проблемы ввода.
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;}}}}

Ungolfed:

$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

К, 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 g, вывод будет список, как [(x, y), (x, y), ...]со всеми шагами, чтобы добраться от конца до начала.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.