Relativo vs absoluto

17

Si alguien que mira hacia el norte en el punto A en esta cuadrícula desea instrucciones para seguir el camino verde (ya que solo pueden seguir las líneas de cuadrícula) hasta el punto B, podría decirles:

Ir North, North, West, East, East, South, East, East.

o equivalente

Ir Forward, Forward, Left, Back, Forward, Right, Left, Forward.
(Donde un comando de Derecha , Izquierda o Atrás implícitamente significa girar en esa dirección, luego avanzar).

Camino de A a B

Escriba una función con un argumento que se traduzca entre estas direcciones absolutas y relativas a lo largo del mismo camino , no solo al mismo punto. Suponga que la persona dirigida siempre comienza a mirar hacia el norte.

Si el argumento es una cadena de letras NSEW, devuelve las direcciones relativas equivalentes.
Por ejemplo, f("NNWEESEE")devuelve la cadena FFLBFRLF.

Si el argumento es una cadena de letras FBLR, devuelve las direcciones absolutas equivalentes.
Por ejemplo, f("FFLBFRLF")devuelve la cadena NNWEESEE.

La cadena vacía se rinde. Suponga que no hay otros casos de entrada.

Si su idioma no tiene funciones o cadenas, use lo que le parezca más apropiado.

El código más corto en bytes gana.

Pasatiempos de Calvin
fuente
¿Asumimos que una persona siempre comienza con la cabeza hacia el Norte? De esa manera, en términos relativos para ir hacia el Este, requeriría que Gire a la Derecha, en lugar de simplemente decir Adelante
Optimizador el
@Optimizer Sí, norte. Y sí a tu otro punto. Rigual Eal inicio.
Aficiones de Calvin
1
¡Hurra! ¡Cambiaste tu imagen para confirmar lo que siempre pensé!
Justin
44
¿Estás enganchado a PPCG nuevamente? ;)
Martin Ender
44
@ MartinBüttner O eso, o soy muy bueno para disfrazar mis problemas de tarea. ;)
Calvin's Hobbies

Respuestas:

6

CJam, 57 53 49

{"NESW""FRBL"_3$&!!:Q$:R^^f#0\{{+0\}Q*_@-R=\}%);}

Versión previa

{"NESW""FRBL"_3$0=#W>:Q{\}*:R;f#0\{{+0\}Q*_@-R=\}%);}

Ejemplo:

{"NESW""FRBL"_3$0=#W>:Q{\}*:R;f#0\{{+0\}Q*_@-R=\}%);}:T;
"NNWEESEE"T
N
"FFLBFRLF"T

Salida:

FFLBFRLF
NNWEESEE

Cómo funciona

{
  "NESW""FRBL"             " Push the two strings. ";
  _3$0=#W>                 " Check if the first character is in FRBL. ";
  :Q                       " Assign the result to Q. ";
  {\}*                     " Swap the two strings if true. ";
  :R;                      " Assign the top string to R and discard it. ";
  f#                       " Find each character of the input in the string. ";
  0\                       " Push a 0 under the top of the stack. ";
  {                        " For each item (index of character): ";
    {                      " If Q: ";
      +0\                  " A B -> 0 (A+B) ";
    }Q*
    _@-                    " C D -> D (D-C) ";
    R=                     " E -> E-th character in R ";
    \                      " Swap the top two items. ";
  }%
  );                       " Discard the last item in the list. ";
}
jimmy23013
fuente
6

C ++, 99 97

Lo siguiente está formateado como una expresión lambda. Toma un char*argumento y lo sobrescribe.

[](char*s){for(int d=0,n=0,c=*s*9%37&4;*s;d+=n)c?n=*s%11/3-d:n+=*s%73%10,*s++="NESWFRBL"[c|n&3];}

Para aquellos que no están familiarizados con esta función (como yo hace 1 hora), úsela de la siguiente manera:

#include <iostream>

int main()
{
    char s[] = "NNWEESEE";
    auto x = [](char*s){for(int d=0,n=0,c=*s*9%37&4;*s;d+=n)c?n=*s%11/3-d:n+=*s%73%10,*s++="NESWFRBL"[c|n&3];};

    x(s); // transform from absolute to relative
    std::cout << s << '\n';

    x(s); // transform from relative to absolute
    std::cout << s << '\n';
}

Algunas explicaciones:

  • Cuando se usa código como flag ? (x = y) : (x += z), el segundo par de paréntesis se requiere en C. ¡Así que usé C ++!
  • C ++ requiere especificar un tipo de retorno para una función. A menos que use una expresión lambda, ¡eso es! Una ventaja adicional es que no necesito desperdiciar 1 carácter en el nombre de la función.
  • El código *s*9%37&4prueba el primer byte; el resultado es 4 si es uno de NESW; 0 de lo contrario
  • El código *s%11/3convierte los bytes NESWa 0, 1, 2, 3.
  • El código *s%73%10convierte los bytes FRBLa 0, 9, 6, 3 (que es 0, 1, 2, 3 módulo 4)
  • Al convertir direcciones relativas a absolutas, no necesito la dvariable. Intenté reorganizar el código para eliminarlo por completo, pero parece imposible ...
anatolyg
fuente
1
Me gusta mucho la forma en que conviertes las letras en números. :)
Emil
6

JavaScript (E6) 84 86 88 92104

Editar: usando & en lugar de%, diferente prioridad del operador (menos paréntesis) y funciona mejor con números negativos
Edit2: | en lugar de +, op precedence nuevamente, -2. Gracias DocMax
Edit3: la comprensión de la matriz es 2 caracteres más corta que map (), para cadenas

F=p=>[o+=c[d=n,n=c.search(i),n<4?4|n-d&3:n=n+d&3]for(i of n=o='',c='NESWFRBL',p)]&&o

Prueba en la consola FireFox / FireBug

console.log(F('NNWEESEE'),F('FFLBFRLF'))

Salida

FFLBFRLF NNWEESEE
edc65
fuente
@Optimizer no más. Y con la esperanza de reducir aún más.
edc65
¿Qué significa && oal final?
bebe
2
@bebe la función de mapa devuelve una matriz, dentro de ella, como efecto secundario, relleno la cadena o que es lo que necesito devolver. array && valueevaluar valuecomo cualquier matriz evaluartruthy
edc65
1
¡Finalmente! He estado mirando éste desde que tocó 88. A menos que me falta algo, puede reemplazar 4+(n-d&3)con 4|n-d&3y guardar 2 caracteres.
DocMax
4

APL, 72

{^/⍵∊A←'NESW':'FRBL'[1+4|-2-/4,3+A⍳⍵]⋄A[1+4|+\'RBLF'⍳⍵]}

Si las configuraciones del intérprete se pueden cambiar sin penalización, la puntuación es 66 , cambiando ⎕IOa 0:

{^/⍵∊A←'NESW':'FRBL'[4|-2-/0,A⍳⍵]⋄A[4|+\'FRBL'⍳⍵]}
TwiNight
fuente
3

Pitón, 171 139

No es tan corto como las otras soluciones, pero supongo que debería ser relativamente bueno para lo que se puede hacer con Python:

def f(i):a,b='NWSE','FLBR';I=map(a.find,'N'+i);return''.join((b[I[k+1]-I[k]],a[sum(map(b.find,i)[:k+1])%4])[-1in I]for k in range(len(i)))

Versión ampliada para una legibilidad ligeramente mejor:

def f(i):
    a, b = 'NWSE', 'FLBR'
    I = map(a.find,'N'+i)     # translate to numbers assuming abs. directions
    J = map(b.index,i)        # translate to numbers assuming rel. directions
    if not -1 in I:
        o = [b[I[k+1]-I[k]] for k in range(len(i))]    # rel. dir. is differences of abs. dir.
    else:
        o = [a[sum(J[:k+1])%4] for k in range(len(i))] # abs. dir. is sum of all rel. dir. so far
    return ''.join(o)
Emil
fuente
1

Go, 201

type q string;func F(s q)q{d,z:=byte(0),make([]byte,len(s));for i,c:=range[]byte(s){if(c^4)*167%3<2{c=c*156%5;z[i],d="LBRF"[(d-c)%4],c-1;}else{c=(c^43)*3%7-1;d=(d+c)%4;z[i]="NESW"[d];};};return q(z);}

Versión legible:

func F(s string) string {
    d, z, R, A := 0, make([]byte, len(s)), "LBRFLBR", "NESW"
    for i, c := range []byte(s) {
        switch c {
        case 'N': c = R[d+3]; d = 0
        case 'E': c = R[d+2]; d = 1
        case 'S': c = R[d+1]; d = 2
        case 'W': c = R[d]; d = 3
        case 'F': c = A[d]
        case 'R': d = (d + 1) % 4; c = A[d]
        case 'B': d = (d + 2) % 4; c = A[d]
        case 'L': d = (d + 3) % 4; c = A[d]
        }
        z[i] = c
    }
    return string(z)
}

David
fuente
1

GNU sed, 356 bytes

El desafío requiere una transformación simple en una secuencia de personajes. sed, el editor de flujo es la elección obvia de idioma ;-)

/[FRBL]/bx                                     # Jump to label x if relative
:y                                             # label y (start of abs->rel loop)
/[FRBL]$/q                                     # quit if string ends in rel char
s/(^|[FRBL])N/\1F/;ty                          # Substitute next abs char with
s/(^|[FRBL])E/\1R/;tr                          #     rel char, then jump to
s/(^|[FRBL])S/\1B/;tb                          #     relevant rotation label if
s/(^|[FRBL])W/\1L/;tl                          #     a match was found
by                                             # loop back to y
:r;y/NESW/WNES/;by                             # Rotation labels: transform then
:b;y/NESW/SWNE/;by                             #     loop back to y
:l;y/NESW/ESWN/;by
:x                                             # label x (start of rel->abs loop)
/^[NESW]/q                                     # quit if string starts w/ abs char
/F([NESW]|$)/s/F([NESW]|$)/N\1/                # Matches for each direction:
/R([NESW]|$)/y/NESW/ESWN/;s/R([NESW]|$)/E\1/   #     rotate, then substitute
/B([NESW]|$)/y/NESW/SWNE/;s/B([NESW]|$)/S\1/
/L([NESW]|$)/y/NESW/WNES/;s/L([NESW]|$)/W\1/
bx                                             # loop back to x

(Comentarios y espacios despojados para el cálculo del puntaje de golf)

Salida:

$ sed -rf absrel.sed <<< NNWEESEE
FFLBFRLF
$ sed -rf absrel.sed <<< FFLBFRLF
NNWEESEE
$ 

Explicación:

La idea aquí es que cuando cambiamos el marco de referencia, siempre hay un mapeo directo entre {N, E, S, W}y {F, R, B, L}.

En el caso de absoluto a relativo, trabajamos hacia adelante a través de la cadena. Para cada carácter hacemos un mapa {N, E, S, W}para {F, R, B, L}, a continuación, girar los restantes [NESW]caracteres de acuerdo con el carácter que acaba de mapeado, a continuación, pasar a la siguiente carácter.

Para el caso de relativo a absoluto, hacemos lo contrario. Trabajamos hacia atrás a través de la cadena, girando todos los [NESW]caracteres siguientes de acuerdo con el carácter que está inmediatamente delante. Luego asignamos ese carácter {N, E, S, W}a {F, R, B, L}, hasta llegar al comienzo de la cadena.

Trauma digital
fuente
0

Haskell, 224

import Data.Function
i=flip(\x->length.takeWhile(/=x))
r=['F','R','B','L']
a=['N','E','S','W']
f s@(x:_)|elem x a=map((r!!).(`mod`4).(4-))$zipWith((-)`on`(i a))('N':s)(s)|True=tail$map((a!!).(`mod`4)).scanl(+)(0)$map(i r) s

Esto asigna números de rotación a las direcciones relativas, y números de orientación a las direcciones absolutas, luego encuentra las rotaciones entre orientaciones sucesivas o las orientaciones después de rotaciones sucesivas. La ifunción encuentra el índice dentro de las dos leyendas.

Archaephyrryx
fuente