Dar direcciones

15

Desafío

Le has dado un mapa a un amigo que se parece un poco a esto:

      |
      /
     |
     /
    |
    \
     |
     \
      D

Un mapa simple que comienza en la parte superior y termina en la parte inferior. Lamentablemente, tu amigo no lo entiende. ¿Puedes decodificar el mapa para que pueda leerlo?

Entrada

La entrada es una cadena de caracteres que consisten en |, /, \, D, ^, Y, (espacio) , y saltos de línea.

  • | le dice que se quede en la misma columna.
  • \ le dice que se mueva a la columna a la derecha y hacia abajo 1.
  • / le dice que se mueva a la columna a la izquierda y hacia abajo 1.
  • D marca el destino
    • ^ (si está presente) habla de una división en el camino.
    • Y(si está presente) habla de una unión de caminos. Trátelo como a |.

La entrada se organizará de modo que haga una especie de camino:

   |
   |
   \
    |
    ^
   / \
  /   |
 D    |

Siempre habrá un espacio entre dos rutas, y todas las rutas volverán a unirse o llegarán a la última línea de la entrada. Solo habrá una división por mapa. No hay límite para la longitud del mapa de entrada. Nunca habrá más de dos caminos.

Salida

La salida debe ser una cadena de direcciones.

  • " L " debería decirle a tu amigo que mueva a la izquierda y dé un paso adelante.
  • " R " debería decirle a tu amigo que se mueva a la derecha y dé un paso adelante.
  • " F " debería decirle a tu amigo que avance 1 paso.

Para el mapa de ejemplo de entrada, la salida sería la siguiente:

F F L F R R R

Tenga en cuenta que su amigo comienza en la parte superior del mapa y mira hacia abajo. Da las instrucciones desde su perspectiva. Para una instancia de "^", su programa debe poder elegir la ruta que conduce al destino (D). Si las dos rutas se recombinan, su programa debe elegir la ruta más recta (la que tenga más |s) a seguir. Direcciones deben estar separados por espacios, y deben terminar en D .

Ejemplos

Entrada

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

Salida

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

Como la ruta más a la izquierda contiene solo 1 |, utilizamos la ruta más a la derecha que tiene 3.


Entrada

\
 |
 /
|
\
 |
 /
D

Salida

L F R F L F R

Entrada

    /
   \
    /
   \
    ^
   \ \
    D \

Salida

R L R L R L

Otros detalles

  • Este es el código de golf, por lo que la persona con el código más corto para el próximo miércoles 19 de agosto gana.
  • Retroalimentación constructiva bienvenida y muy apreciada.
  • Parcialmente inspirado en Un mapa del tesoro escondido
  • Siéntase libre de cambiar el título a algo más creativo.
  • Si encuentra errores que cometí, corríjalos.
  • Y por supuesto, diviértete.

¡Gracias!

Tal vez un poco tarde, ¡pero UndefinedFunction es la codificación ganadora en JavaScript! Gracias a todos los que entraron. No se aceptarán otras entradas.

The_Basset_Hound
fuente
Todavía parece apagado. El primer ejemplo termina en L L, que creo que debería ser L L L. El ejemplo con Ytodavía tiene un 1al final y también parece tener otros errores. Leo el mapa como F F R R R F F F R R L Fsi entendiera las reglas correctamente.
Martin Ender
@ MartinBüttner se supone que debes terminar en D, solo necesitarías 2 Ls. 3 Ls pasarían D.
The_Basset_Hound
2
¿Puede un camino llegar a un callejón sin salida antes de llegar a la última línea? ¿O todos los caminos llegarán a la última línea de la entrada?
jrich
@BassetHound ¿no debería haber uno Lpara el ^y dos Lpara los dos /? ¿Y por qué agregaste dos más Fal final del Yejemplo?
Martin Ender
@ETHproductions Sí.
The_Basset_Hound

Respuestas:

5

Javascript (ES6), 261 248 252 248 212 bytes

Como solo se debe admitir una división:

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


Sin embargo, 240 bytes y podemos lidiar con múltiples divisiones:

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


Ambos programas definen funciones anónimas.

Para usar, asigne un nombre a las funciones agregando f=antes del código.

Luego, pueden ser llamados con

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


Explicación

(desactualizado, pero sigue siendo el mismo concepto. Para la solución de división múltiple)

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


Notas

  • Todas las barras invertidas ( \) en la entrada se escapan como \\, de modo que JavaScript pueda reconocerlas.

  • Ambas salidas contienen un espacio final.

jrich
fuente
Maldita sea, pensé que tenía todo arreglado.
The_Basset_Hound
9

PHP, 634 631 607 396 382 381 347 338 330 337 324 bytes

Mi primer golf, sé gentil. Cualquier consejo es muy apreciado.

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

Explicación breve:
Tengo un recuento que es 0 si la entrada tiene solo una ruta. Cuando la ruta se divide, el recuento es 1 para la ruta izquierda y 2 para la ruta derecha. Después de definir ambas rutas (o solo una), verifico qué ruta tiene más "F".

Versión sin golf:

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


Registro:
Guardado 36 Bytes gracias a Kamehameha.
Ahorró muchos bytes cambiando la lógica un poco.
Guardado 42 Bytes gracias a axiac.
Reemplazado cada declaración con operadores ternarios.

jrenk
fuente
3
Bienvenido al sitio!
isaacg
2
Puede probar en $a=$b='';lugar de: $a='';$b='';ahorra alrededor de 3 bytes.
Kamehameha
1
Además, la concatenación como $a=$a.'L ';se puede reducir a $a.='L '. Parece que lo has hecho en un par de lugares. Eso ahorrará alrededor de 6 bytes :)
Kamehameha
1
No conozco muy bien PHP, pero creo que puedes dejar el espacio después de "as" en tu foreach ( foreach($e as$i)); He probado eso y parece funcionar bien.
ProgramFOX
1
Un par de consejos más para guardar unos pocos bytes, como @ProgramFox mencionó sobre, asen el foreach, los espacios entre echoy el nombre de la variable se pueden eliminar para que tenga echo$b. Además, un par de tests de igualdad puede ser más corto también, $c==0podría ser !$cy si ese es el caso, se puede inicializar $ca ''con $ae $b!
Dom Hastings
3

PHP, 281 bytes

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

Es el resultado de dos iteraciones de golf. La versión sin golf es:

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

Es bastante golfista y surgió como una mejora del siguiente programa de golf (312 bytes):

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

Es la versión de golf del original:

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

Ejecución de ejemplo:

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

También maneja múltiples horquillas correctamente (es necesario unirse antes de la próxima bifurcación para tener como máximo dos ramas en cualquier momento). Pregunté por varios tenedores en un comentario, pero el código ya estaba listo cuando llegó la respuesta ("no es necesario").

El código completo con el conjunto de pruebas y más comentarios se pueden encontrar en github .

axiac
fuente
Wow buen trabajo! ¡Todavía necesito aprender bastantes cosas!
jrenk