Dając wskazówki

15

Wyzwanie

Dałeś mapę znajomemu, który wygląda trochę tak:

      |
      /
     |
     /
    |
    \
     |
     \
      D

Prosta mapa, która zaczyna się na górze, a kończy na dole. Niestety twój przyjaciel tego nie rozumie. Czy potrafisz odkodować mapę, aby mógł ją odczytać?

Wejście

Wejście jest ciągiem znaków składających się z |, /, \, D, ^, Y, (spacja) oraz nowej linii.

  • | każe pozostać w tej samej kolumnie.
  • \ każe przejść do kolumny po prawej i na dół 1.
  • / każe przejść do kolumny po lewej i na dół 1.
  • D oznacza miejsce docelowe.
    • ^ (jeśli jest obecny) mówi o podziale na ścieżce.
    • Y(jeśli jest obecny) mówi o ponownym połączeniu ścieżek. Traktuj to jak |.

Dane wejściowe zostaną ustawione tak, aby tworzyły rodzaj ścieżki:

   |
   |
   \
    |
    ^
   / \
  /   |
 D    |

Zawsze będzie spacja między dwiema ścieżkami, a wszystkie ścieżki albo dołączą ponownie, albo dojdą do ostatniego wiersza wejścia. Będzie tylko jeden podział na mapę. Długość mapy wejściowej nie jest ograniczona. Nigdy nie będzie więcej niż dwie ścieżki.

Wynik

Dane wyjściowe powinny być ciągiem wskazówek.

  • L ” powinien powiedzieć znajomemu, aby przesunął L eft i zrobił 1 krok do przodu.
  • R ” należy poinformować swojego znajomego, aby przenieść R rawo i wziąć 1 krok do przodu.
  • F ” powinien powiedzieć znajomemu, aby zrobił krok do przodu.

W przypadku przykładowej mapy wyników dane wyjściowe byłyby następujące:

F F L F R R R

Pamiętaj, że twój przyjaciel zaczyna na górze mapy i jest skierowany w dół mapy. Podaj wskazówki z jego perspektywy. W przypadku wystąpienia „^” program musi być w stanie wybrać ścieżkę prowadzącą do miejsca docelowego (D). Jeśli dwie ścieżki ponownie się połączą, twój program musi wybrać najprostszą ścieżkę (tę, która ma najwięcej |s) do przejścia . Wskazówki muszą być oddzielone przestrzenie i musi kończyć się na D .

Przykłady

Wejście

      |
      |
      \
       \
        ^
       / |
      |  |
      \  |
       \ \
        \ \
         \ /
          Y
          D

Wynik

F F L L L F F F L L R F

Ponieważ skrajna lewa ścieżka zawiera tylko 1 |, używamy skrajnej prawej ścieżki, która ma 3.


Wejście

\
 |
 /
|
\
 |
 /
D

Wynik

L F R F L F R

Wejście

    /
   \
    /
   \
    ^
   \ \
    D \

Wynik

R L R L R L

Inne szczegóły

  • To jest golf golfowy, więc wygrywa osoba z najkrótszym kodem do następnej środy, 19 sierpnia.
  • Konstruktywne opinie są mile widziane i bardzo mile widziane.
  • Częściowo zainspirowany Mapą do ukrytego skarbu
  • Zmień tytuł na bardziej kreatywny.
  • Jeśli znajdziesz błędy, które popełniłem, popraw je.
  • I oczywiście, baw się dobrze.

Dziękuję Ci!

Może trochę późno, ale UndefinedFunction jest zwycięzcą kodującym w JavaScript! Dziękuje wszystkim którzy dołączyli. Żadne inne wpisy nie będą akceptowane.

The_Basset_Hound
źródło
Nadal wydaje się nie na miejscu. Pierwszy przykład kończy się L L, co moim zdaniem powinno być L L L. Przykład z Ynadal ma 1na końcu i wydaje się, że zawiera także inne błędy. Czytam mapę tak, F F R R R F F F R R L Fjakby poprawnie rozumiałem zasady.
Martin Ender,
@ MartinBüttner, masz zakończyć na D, potrzebujesz tylko 2 Ls. 3 Ls
minęłoby
2
Czy ścieżka może kiedykolwiek dotrzeć do ślepego zaułka, zanim dojdzie do ostatniej linii? Czy też wszystkie ścieżki dojdą do ostatniego wiersza wejścia?
jrich
@BassetHound nie powinien być jeden Ldla ^dwojga i dwa Ldla dwojga /? I dlaczego dodałeś jeszcze dwa Fna końcu Yprzykładu?
Martin Ender,
@ETHproductions Tak.
The_Basset_Hound

Odpowiedzi:

5

JavaScript (ES6), 261 248 252 248 212 bajtów

Ponieważ musi być obsługiwany tylko jeden podział:

s=>(s=s.replace(/ /g,o="",d=0).split(`
`)).map((v,j)=>{if(v=="^")for(v="/\\";(w=s[++j])&&(x=w[1]);d=x=="D"?1:w[0]=="D"?0:x>"{"?d+1:w[0]>"{"?d-1:d);o+=(p=v[d>0?1:0]||v[0])<"0"?"R ":p<"E"?"":p=="\\"?"L ":"F "})?o:o


Jednak 240 bajtów i możemy poradzić sobie z wieloma podziałami:

s=>(s=s.replace(/ /g,o="").split(`
`)).map((v,j)=>{if(!v[1])t=d=0
else if(!t){for(t=1;(w=s[++j])&&(x=w[1]);d=x=="D"?1:w[0]=="D"?0:x>"{"?d+1:w[0]>"{"?d-1:d);o+=d>0?"L ":"R "}o+=(p=v[d>0?1:0])<"0"?"R ":p<"E"||p=="^"?"":p=="\\"?"L ":"F "})?o:o


Oba programy definiują anonimowe funkcje.

Aby użyć, nadaj funkcji nazwę, dodając f=przed kodem.

Następnie można je wywołać za pomocą

alert(f(
`   |
   |
   \\
    |
    ^
   / \\
  /   |
 D    |`
))


Wyjaśnienie

(nieaktualne, ale wciąż ta sama koncepcja. Dla rozwiązania wielokrotnego podziału)

s=>
    //Remove all spaces from the input
    (s=s.replace(/ /g,o="",
                 //Define function c, to convert symbols to directions
                 c=p=>p<"0"?"R ":p<"E"||p=="^"?"":p=="\\"?"L ":"F "
    //Split input into an array by newlines
    ).split(`
`))
    //for each string v in the input array, at index j:
    .map((v,j)=>{
        //if v is only one character long:
        if(!v[1]){
            t=1     //assign t to 1 (true) - we need to test if multiple paths
            d=0     //assign d to 0 - reset the counter for determining shortest path
        }
        //if v is two characters long, and we have not tested which path is shorter yet:
        else if(t){
            for(    t=0;    //assign t to 0 - we will have tested which path is longer

                    //for each string left in the input, while the input still has two characters:
                    (w=s[++j]) && w[1];
                    //assign d to determine which direction to go. This will be conveyed by if d>0
                    d=
                        w[1]=="D"?1:    //if the dest. is only on one side, choose that side.
                        w[0]=="D"?0:
                        w[1]=="|"?d+1:  //otherwise add/subtract from d (like a tug of war) to determine which side has more "|"
                        w[0]=="|"?d-1:
                        d
               );
            o+=d>0?"L ":"R "    //append to the output which direction was taken
        }

        o+=c(v[d>0?1:0])    //append to the output the characters from the correct path in any case, determined by d calculated above 
                            //(or defaulting to 0, if path is not split, in which case the only character is appended)

    }) ? o : o  //coerce the result, which will evaluate to an array of the input, to the output (o) and implicitly return


Notatki

  • Wszystkie ukośniki odwrotne ( \) na wejściu są oznaczone jako „esc” \\, aby javascript mógł je rozpoznać.

  • Oba wyjścia zawierają końcowe spacje.

jrich
źródło
Cholera, myślałem, że wszystko naprawiłem.
The_Basset_Hound
9

PHP, 634 631 607 396 382 381 347 338 330 337 324 bajtów

Mój pierwszy golf, więc bądź delikatny. Wszelkie wskazówki są mile widziane.

<?php
foreach(str_split(strtr(fgets(STDIN),[' '=>'']))as $i){if($i!=D){$z=$i=='^';$x=$i==Y;$s=!$z&&!$x?($i=='/'?R:($i=='|'?F:($i=='\\'?L:$s))):$s;$a.=$z?R:($x?F:(($c==1||!$c)?$s:''));$b.=$z?L:($x?F:(($c==2||!$c)?$s:''));$c=$z?1:($x?0:($c==1?2:($c==2?1:$c)));}else{echo(substr_count($a,F)<substr_count($b,F)&&$c==0||$c==2)?$b:$a;}}

Krótkie wyjaśnienie:
Mam licznik, który wynosi 0, jeśli wejście ma tylko jedną ścieżkę. Po podzieleniu ścieżki liczba wynosi 1 dla lewej ścieżki i 2 dla prawej ścieżki. Po zdefiniowaniu obu ścieżek (lub tylko jednej) sprawdzam, która ścieżka ma więcej „F”.

Wersja bez golfa:

<?php
$input = fgets(STDIN);
$inputArray = str_split($input);
foreach ($inputArray as $currentChar) {
    if ($currentChar != 'D') {
        if ($i == '^') {
            $firstPath .= 'R';
            $secondPath .= 'L';
            $count = 1;
        } elseif ($i == 'Y') {
            $secondPath .= 'F';
            $firstPath .= 'F';
            $count = 0;
        } else {
            if ($i == ' ') {
                continue;
            }
            if ($i == '/') {
                $direction = 'R';
            } else {
                if ($i == '|') {
                    $direction = 'F';
                } else {
                    if ($i == '\\') {
                        $direction = 'L';
                    } else {
                        $direction = '';
                    }
                }
            }
            if ($count == 1) {
                $firstPath .= $direction;
                $count = 2;
            } elseif ($count == 2) {
                $secondPath .= $direction;
                $count = 1;
            }
            if (!$count) {
                $firstPath .= $direction;
                $secondPath .= $direction;
            }
        }
    } else {
        echo (substr_count($firstPath, 'F') < substr_count($secondPath, 'F')) || $count == 2 ? $secondPath : $firstPath;
    }
};


Log:
Zapisano 36 bajtów dzięki Kamehameha.
Zaoszczędzono wiele bajtów, zmieniając nieco logikę.
Zaoszczędzono 42 bajty dzięki axiac.
Zastąpiono każdą instrukcję if operatorami trójskładnikowymi.

Jrenk
źródło
3
Witamy na stronie!
isaacg
2
Możesz spróbować $a=$b='';zamiast - $a='';$b='';Zapisuje około 3 bajtów.
Kamehameha,
1
$a=$a.'L ';Można również zredukować do rodzaju konkatenacji $a.='L '. Wygląda na to, że zrobiłeś to w kilku miejscach. To pozwoli zaoszczędzić około 6 bajtów :)
Kamehameha,
1
Nie znam zbyt dobrze PHP, ale wierzę, że możesz porzucić „po” w foreach ( foreach($e as$i)); Przetestowałem to i wydaje się, że działa dobrze.
ProgramFOX,
1
Kilka dodatkowych wskazówek, jak zaoszczędzić kilka bajtów, jak @ProgramFox wspomniał o asw foreach, odstępach między echoi nazwy zmiennej można usunąć, aby to zrobić echo$b. Także kilka testów równości może być krótszy też $c==0może być !$ci czy to przypadek, można zainicjować $cdo ''z $aa $b!
Dom Hastings,
3

PHP, 281 bajtów

$b=0;$p=['|'=>'$a[$b].="F ";$f[$b]++;','/'=>'$a[$b].="R ";','\\'=>'$a[$b].="L ";','^'=>'$d.=$a[0];$n=2;$a=["R ","L "];$f=[];$b=1;','Y'=>'$d.=$a[$f[0]<$f[$n=1]]."F ";$a=[];','D'=>'$d.=$a[$b];exit(rtrim($d));'];foreach(str_split($argv[$n=1])as$c){if($x=$p[$c]){eval($x);$b=++$b%$n;}}

Jest to wynik dwóch iteracji golfowych. Wersja bez golfa to:

$a=$f=[];       // these assignments are not required (they were suppresed in v2)
$n=1;           // this assignment can be squeezed into $argv[$n=1]
$b=0;           // if this assignment is suppressed $b becomes '' and breaks the logic
$code = [
    '|' => '$a[$b].="F ";$f[$b]++;',
    '/' => '$a[$b].="R ";',
    '\\'=> '$a[$b].="L ";',
    '^' => '$d.=$a[0];$n=2;$a=["R ","L "];$f=[];$b=1;',
    'Y' => '$d.=$a[$f[0]<$f[$n=1]]."F ";$a=[];',
    'D' => '$d.=$a[$b];echo(rtrim($d));',
];
foreach (str_split($argv[1]) as $char) {
    // ignore input characters not in the keys of $code
    if ($x = $code[$char]) {
        eval($x);
        $b = ++ $b % $n;   // cycles between 0 and 1 ($n == 2) or stays 0 ($n == 1)
    }
}

Sama gra w golfa i pojawiła się jako ulepszenie następującego programu gry w golfa (312 bajtów):

$b=0;foreach(str_split($argv[$n=1])as$c){if($c=='|'){$a[$b].='F ';$f[$b]++;}elseif($c=='/'){$a[$b].='R ';}elseif($c=='\\'){$a[$b].='L ';}elseif($c=='^'){$d.=$a[0];$n=2;$a=['R ','L '];$f=[];$b=1;}elseif($c==Y){$d.=$a[$f[0]<$f[$n=1]].'F ';$a=[];}elseif($c==D){$d.=$a[$b];exit(rtrim($d));}else continue;$b=++$b%$n;}

Jest to wersja oryginalna gry w golfa:

$map = $argv[1];

$dir = '';              // the already computed directions
$nb = 1;                // the number of branches
$branches = [ '' ];     // the branches (2 while between '^' and 'Y', 1 otherwise)
$nbF = [ 0, 0 ];        // the number of 'F's on the branches (used to select the branch)
$curr = 0;              // the current branch
foreach (str_split($map) as $char) {
    if ($char == '|') {             // go 'F'orward
        $branches[$curr] .= 'F ';       // put it to the current branch
        $nbF[$curr] ++;                 // count it for the current branch
    } elseif ($char == '/') {       // go 'R'ight
        $branches[$curr] .= 'R ';
    } elseif ($char == '\\') {      // go 'L'eft
        $branches[$curr] .= 'L ';
    } elseif ($char == '^') {       // fork; choose the path ('L' or 'R') that contains the most 'F'orward segments
        $dir .= $branches[0];           // flush the current path (it was stored as the first branch)
        $nb = 2;                        // start two branches
        $branches = [ 'R ', 'L ' ];     // put the correct directions on each branch
        $nbF = [ 0, 0 ];                // no 'F's on any branch yet
        $curr = 1;                      // need this to let it be 0 on the next loop
    } elseif ($char == 'Y') {       // join
        $dir .= $branches[$nbF[0] < $nbF[1]];   // flush; choose the branch having the most 'F's
        $dir .= 'F ';                           // treat it like a "|"
        $branches = [ '' ];                     // back to a single, empty branch
        $nb = 1;
    } elseif ($char == 'D') {       // finish
        $dir .= $branches[$curr];       // flush
        break;                          // and exit; could use 'return' but it's one byte longer; use exit() in the final program and save 5 bytes
    } else {
        continue;
    }
    $curr = ++ $curr % $nb;
}
echo rtrim($dir);

Przykładowe wykonanie:

$ php -d error_reporting=0 directions.php '
      |
      |
      \
       \
        ^
       / |
      |  |
      \  |
       \ \
        \ \
         \ /
          Y
          D
'; echo
F F L L L F F F L L R F
$

Obsługuje również poprawnie wiele widelców (musisz dołączyć przed następnym widelcem, aby mieć maksymalnie dwie gałęzie w dowolnym momencie). Zapytałem o kilka rozwidleń w komentarzu, ale kod był już gotowy, gdy nadeszła odpowiedź („niepotrzebna”).

Pełny kod z pakietem testowym i więcej komentarzy można znaleźć na github .

aksjomat
źródło
Wow, dobra robota! Nadal muszę się nauczyć kilku rzeczy!
jrenk,