Convertir un punto de la brújula a grados

18

Se me ocurrió este desafío de forma independiente, pero resulta ser lo contrario a este desafío de Doorknob . Como realmente me gusta su especificación, decidí robar gran parte de ella en lugar de preparar mis propias explicaciones.

El reto

Dada la abreviatura de uno de los 32 puntos en la brújula, imprima los grados correspondientes. Siéntase libre de saltar a la tabla a continuación si no está interesado en una explicación de los 32 puntos.

Aquí está la brújula completa:

imagen

Por Denelson83 (Trabajo propio) [ GFDL o CC-BY-SA-3.0 ], a través de Wikimedia Commons

Cada dirección es 11.25 (360/32) grados más lejos que la anterior. Por ejemplo, N (norte) es 0 grados, NbE (norte por este) es 11.25 grados, NNE (norte-noreste) es 22.5 grados, etc.

En detalle, los nombres se asignan de la siguiente manera:

  • 0 grados es N, 90 grados es E, 180 grados es S y 270 grados es W. Estas se llaman direcciones cardinales.
  • Los puntos intermedios entre las direcciones cardinales son simplemente las direcciones cardinales que están entre concatenados. N o S siempre van primero, y W o E siempre son segundos. Estas se llaman direcciones ordinales. Las direcciones ordinales y cardinales juntas forman los vientos principales.
  • Los puntos intermedios entre los vientos principales son las direcciones que están entre concatenados. Las direcciones cardinales van primero, ordinal segundo. Estos se llaman vientos a medias.
  • Los puntos intermedios entre los vientos principales y medios son el viento principal adyacente "por" la dirección cardinal más cercana lejos del viento principal. Esto se denota con a b. Estos se llaman cuartos de viento.

Esto da como resultado el siguiente cuadro:

#   Degrees  Abbrv.  Name
1   0        N       North
2   11.25    NbE     North by east
3   22.5     NNE     North-northeast
4   33.75    NEbN    Northeast by north
5   45       NE      Northeast
6   56.25    NEbE    Northeast by east
7   67.5     ENE     East-northeast
8   78.75    EbN     East by north
9   90       E       East
10  101.25   EbS     East by south
11  112.5    ESE     East-southeast
12  123.75   SEbE    Southeast by east
13  135      SE      Southeast
14  146.25   SEbS    Southeast by south
15  157.5    SSE     South-southeast
16  168.75   SbE     South by east
17  180      S       South
18  191.25   SbW     South by west
19  202.5    SSW     South-southwest
20  213.75   SWbS    Southwest by south
21  225      SW      Southwest
22  236.25   SWbW    Southwest by west
23  247.5    WSW     West-southwest
24  258.75   WbS     West by south
25  270      W       West
26  281.25   WbN     West by north
27  292.5    WNW     West-northwest
28  303.75   NWbW    Northwest by west
29  315      NW      Northwest
30  326.25   NWbN    Northwest by north
31  337.5    NNW     North-northwest
32  348.75   NbW     North by west

Aquí hay una tabla más detallada y posiblemente una mejor explicación de los puntos de la brújula.

Su tarea es tomar como entrada una de las 32 abreviaturas de la tercera columna y generar los grados correspondientes en la segunda columna.

Puede suponer que la entrada siempre será exactamente una de esas 32 cadenas (y puede esperar opcional pero consistentemente una nueva línea final). La salida también se debe dar exactamente como se enumeró anteriormente, aunque se permiten ceros finales. Opcionalmente, puede generar una nueva línea final.

Puede escribir un programa o función, tomando la entrada a través de STDIN (o la alternativa más cercana), argumento de línea de comando o argumento de función y generando el resultado a través de STDOUT (o la alternativa más cercana), el valor de retorno de la función o el parámetro de función (out).

Este es el código de golf, por lo que gana la respuesta más corta (en bytes).

Martin Ender
fuente

Respuestas:

2

Pyth, 47 bytes

c*45x"NuMD¢¼Ew
XSj.{§/gWbZ¹°"C%CzC\½4

Hexdump, debido a caracteres no imprimibles:

0000000: 632a 3435 7822 4e86 754d 0344 a2bc 4504  c*45x"N.uM.D..E.
0000010: 770a 9518 1c58 536a 2e7b a77f 2f67 5762  w....XSj.{../gWb
0000020: 5ab9 15b0 8798 2243 2543 7a43 5cbd 34    Z....."C%CzC\.4

Arnés de prueba

Debido a un error en el compilador oficial de línea de comandos, este código solo funciona a través del compilador en línea, vinculado anteriormente, o el -cindicador del compilador fuera de línea. (El error se solucionó después de que se hizo la pregunta).

Esta solución es muy similar a la respuesta CJam de @ Dennis, que utiliza el proceso de cifrar la entrada, busca el resultado en una cadena de búsqueda de 32 bytes y luego multiplica por 11.25.

El uso función hash I es la conversión de la entrada a una cadena como si fuera un número entero de base 256 con C, teniendo el módulo resultado Cde ½, que es 189, pero ahorra una byte debido a análisis superior, y la conversión que de nuevo a una cadena con Cotra vez .

La multiplicación por 11.25 se logra multiplicando por 45, luego dividiendo por 4, lo que ahorra un byte.

isaacg
fuente
9

Ruby, 118 106

Gracias a Martin Büttner por 12 bytes guardados.

Actualmente tiene la misma longitud independientemente de si se trata de una función o un programa.

función lambda

->s{n=4
d=0,0
s.chars{|e|c="SWNE".index e
c ?d[c%2]+=c/2*2*n-n :n=1}
(Complex(*d).arg*5.1).round%32*11.25}

programa

n=4
d=0,0
gets.chars{|e|c="SWNE".index e
c ?d[c%2]+=c/2*2*n-n :n=1}
p (Complex(*d).arg*5.1).round%32*11.25

Este es un paseo cartesiano por los puntos. Los caracteres NSEWsuman o restan 4 de las coordenadas x e y almacenadas en d[]. Después de encontrar un b(o cualquier otro símbolo que no sea NSEW), se reduce a 1.

Los datos x e y luego se tratan como un número complejo para extraer el argumento angular. Esto se multiplica por 16 / PI = 5.1. Aunque hay algunos errores geométricos en el enfoque, redondear este ángulo es suficiente para dar el número correcto -15..+16. El módulo se usa para corregir esto 0..31(en Ruby %siempre devuelve positivo). Finalmente, el resultado se multiplica por 11.25.

Level River St
fuente
1
¡Qué idea tan inteligente con el redondeo! Obtiene el arctan del ángulo en lugar del ángulo, tomado en relación con la dirección ortogonal más cercana, pero eso resulta lo suficientemente cerca.
xnor
@xnor sin el redondeo obtengo NbE 14.05 (+2.8), NNE 26.60 (+4.1), NEbE 51.41 (-4.84), así que tuve un margen de maniobra con los valores de npero tuve que elegirlos con cuidado.
Level River St
6

Javascript (ES6), 153 bytes

Solo quería que la pelota rodara con una simple.

x=>'N NbE NNE NEbN NE NEbE ENE EbN E EbS ESE SEbE SE SEbS SSE SbE S SbW SSW SWbS SW SWbW WSW WbS W WbN WNW NWbW NW NWbN NNW NbW'.split` `.indexOf(x)*45/4

No es particularmente innovador, pero funciona, y tal vez hay algunos consejos que podrían derivarse de él. No se preocupe, pensaré en otra técnica (con suerte mejor).

ETHproducciones
fuente
1
¿Quizás puedas comprimir la cuerda?
mbomb007
1
Sorprendentemente, todavía es más corto que mi solución (no presentada) en Python, que utiliza un enfoque algorítmico.
pawel.boczarski
2

CJam, 49 bytes

0000000: 72 34 62 32 35 33 25 63 22 4e bf 6f f1 80 e8 dc 38  r4b253%c"N.o....8
0000011: 45 3d f0 2e 94 3c d3 12 53 24 e5 5f a6 63 28 60 57  E=...<..S$._.c(`W
0000022: 5b 14 20 92 17 81 d1 22 23 31 31 2e 32 35 2a        [. ...."#11.25*

Lo anterior es un hexdump, que se puede revertir con xxd -r -c 17 -g 1.

Pruébelo en línea en el intérprete de CJam .

Cómo funciona

r      e# Read a token from STDIN.
4b     e# Convert the string (array of code points) from base 4 to integer.
253%   e# Take the result modulo 253.
c      e# Cast to character.
"…"    e# Push a 32 byte lookup table.
#      e# Find the index of the character.
11.25* e# Multiply the index by 11.25.
Dennis
fuente
1

Java, 653 (caracteres)

Sé que Java no puede ganar, pero me gusta hacer el esfuerzo de todos modos.

class C{float c=1/8f;int n=0;float a;public C(String s){if(s.contains("W"))n=4;switch(s.length()){case 1:p(d(s));case 2:p(e(s));case 3:if(s.contains("b"))f(s,1);g(s);}f(s,2);}int v(char x){switch(x){case 'N':return n;case 'E':return 1;case 'S':return 2;}return 3;}int d(String s){return v(s.charAt(0));}float e(String s){return (v(s.charAt(0))+v(s.charAt(1)))/2f;}void f(String s,int i){if(i<2)a=v(s.charAt(0));else a=e(s.substring(0,i));if(v(s.charAt(1+i))<a)c=-c;p(a+c);}void g(String s){p((d(s.substring(0,1))+e(s.substring(1)))/2f);}void p(float x){System.out.printf("%.2f",x*90);System.exit(0);}public static void main(String[]r){C c=new C(r[0]);}}

Toma entrada de la línea de comandos y salidas a la consola. Versión sin golf:

class Compass
{
    float c = 1/8f;
    int n = 0;
    float a;

    public Compass( String s )
    {
        if( s.contains( "W" ) )
        {
            n = 4;
        }
        switch( s.length() )
        {
            case 1:
                print( parse1( s ) );
            case 2:
                print( parse2( s ) );
            case 3:
                if( s.contains( "b" ) )
                {
                    parse3b4( s , 1 );
                }
                parse3( s );
        }
        parse3b4( s , 2 );
    }

    int getValue( char x )
    {       
        switch( x )
        {           
            case 'N':
                return n;
            case 'E':
                return 1;
            case 'S':
                return 2;           
        }
        return 3;
    }

    int parse1( String s )
    {
        return getValue( s.charAt( 0 ) );
    }

    float parse2( String s )
    {
        return ( getValue( s.charAt( 0 ) ) + getValue( s.charAt( 1 ) ) ) / 2f;
    }

    void parse3b4( String s , int i )
    {
        if( i < 2 ) a = getValue( s.charAt( 0 ) );
        else a = parse2( s.substring( 0 , i ) );
        if( getValue( s.charAt( 1 + i ) ) < a )
        {
            c = -c;
        }
        print( a + c );
    }

    void parse3( String s )
    {
        print( ( parse1( s.substring( 0 , 1 ) ) + parse2( s.substring( 1 ) ) ) / 2f );
    }

    void print( float x )
    {       
        System.out.printf( "%.2f" , x * 90 );
        System.exit( 0 );
    }

    public static void main( String[] args )
    {
        Compass compass = new Compass( args[ 0 ] );
    }
}

Funciona asignando 0-3 a NW (o 4 para N si W está involucrado). Reconoce 4 situaciones diferentes:

  • parse1 es para puntos de una letra, solo devuelve el valor.
  • parse2 es para puntos de doble letra, promedia los valores de los 2 puntos.
  • parse3 es para puntos de letras triples, toma el promedio del promedio de los puntos dobles y simples.
  • parse3b4 es para todos los que tienen una 'b' en ellos, calcula el valor del punto antes de la 'b' y suma o resta 1/8 en función de la 'dirección' del punto después de la 'b'.

En print () el valor se multiplica por 90 para obtener el ángulo real.

Harry Blargle
fuente
¿Es necesario escribir C c=new C(r[0]);? Tal vez new C(r[0]);es suficiente?
pawel.boczarski
1

Python 3, 149 bytes

Intenté un enfoque algorítmico recursivo. Los vientos de cuarto fueron más difíciles de manejar de lo que pensé al principio, por lo que esta solución se hizo relativamente larga.

def f(s):
 if'W'in s:s=s.replace(*'Nn')
 a=(len(s)-2)/8;return'b'in s and(1-a)*f(s[:-2])+a*f(s[-1])or a>=0and(f(s[0])+f(s[1:]))/2or'NESWn'.find(s)*90

Sin golf:

def f(s):
    if 'W'in s:
        s = s.replace('N','n')
    a=(len(s)-2)/8
    if 'b' in s:
        a = 1/8 if len(s)==3 else 1/4
        return (1-a)*f(s[:-2])+a*f(s[-1])
    else:
        if len(s)==1:
            return 'NESWn'.find(s)*90
        else:
            return (f(s[0])+f(s[1:]))/2
Emil
fuente
La versión Golfed devuelve un decimal que debe multiplicarse por 10 ( f("NbW")devuelve en 34.875lugar de 348.75)
智障 的 人
@ viktorahlström, ¿estás seguro? Devuelve el valor correcto para mí. ¿Tal vez te perdiste el último cero al copiar y pegar el código?
Emil
Oh, lo siento, aparentemente fue eso. ¡Mi error, lo siento!
智障 的 人
1

Haskell, 206 bytes

c l=11.25*(fromIntegral$b$l)
b l|(p y l)<0=a l+16|0<1=mod(a l)32
a l=round$(16/pi*)$atan$d$l
d l=p x l/p y l
p z[]=0.0
p z('b':[r])=z r/4
p z(a:r)=z a+p z r
x 'E'=4
x 'W'=(-4)
x c=0
y 'N'=4
y 'S'=(-4)
y c=0

Prueba conveniente:

*Main> map c ["N","NbE","NNE","NEbN","NE","NEbE","ENE","EbN","E","EbS","ESE","SEbE","SE","SEbS","SSE","SbE","S","SbW","SSW","SWbS","SW","SWbW","WSW","WbS","W","WbN","WNW","NWbW","NW","NWbN","NNW","NbW"]
[0.0,11.25,22.5,33.75,45.0,56.25,67.5,78.75,90.0,101.25,112.5,123.75,135.0,146.25,157.5,168.75,180.0,191.25,202.5,213.75,225.0,236.25,247.5,258.75,270.0,281.25,292.5,303.75,315.0,326.25,337.5,348.75]
Leif Willerts
fuente
0

PowerShell - 350

Comapss_gui_in_powershell

Add-Type -AssemblyName *sys*forms*
$f=new-object windows.forms.form
$c=new-object windows.forms.combobox
$c.DataSource=(-split"N NbE NNE NEbN NE NEbE ENE EbN E EbS ESE SEbE SE SEbS SSE SbE S SbW SSW SWbS SW SWbW WSW WbS W WbN WNW NWbW NW NWbN NNW NbW")
$c.Parent=$f
$c.Add_SelectedValueChanged({$f.text=$c.SelectedIndex*11.25})
$f.ShowDialog()
blabb
fuente
0

Julia, 151 147 142 bytes

t=strchr
p=s->if ""==s 0;else i=t(s,'b')
(32/2^i)^sign(i)*p(i>0?s[1:i-1]:s[2:])+im^t("ESWN",s[i+1])end
f=s->90int(16mod(angle(p(s)),2pi)/pi)/8

Un poco ignorante:

# return approx. direction in term of complex number of absolute value 1,
# whose argument is the direction:
# N -> 0, E -> 0+1j, S -> -1, W -> 0-1j
function p(s)
    if ""==s 0;
    else
        i=strchr(s,'b');
        if i!=0
            # if 'b' is 2nd in the word, following direction weight is 1/8,
            # if 'b' is 3rd in the word, following direction weight is 1/4.
            weight=2^(5-i)
            # the first term to count avg is all before 'b'
            first_term=s[1:i-1]
        else
            # weights are equal for the counted and the new (eg. 'NNW <= avg(N, NW)')
            weight=1
            # the first term to count avg is all after the first character
            first_term=s[2:]
        end
        # the return value - average of two vectors
        # s[i+1] evaluates to FIRST character if 'b' didn't occur
        # or to the LAST CHARACTER (after 'b') if it did.
        e^(im*angle(weight*p(first_term)+im^t("ESWN",s[i+1])));
    end
end

# ... And the proper function for returning angle
# there are errors (sic!) in the counted direction, but dividing by 11.25,
# rounding and remultiplying by 11.25 filters them out
f=s->int32(mod(angle(p(s)),2pi)/pi*16)*11.25

En el código no golfizado, cuento el promedio de dos vectores avg = e ^ {jArg (v_1 + v_2)}para tener el vector todavía normalizado. Sin embargo, los errores debidos al alargamiento del primer vector aún no se acumulan con tan pocas adiciones en nuestra recursividad, por lo que mientras se jugaba se eliminó el paso de normalización y el cómputo es avg = v_1 + v_2simple. Los errores de menos de 1/64 del círculo completo se filtran redondeando.

pawel.boczarski
fuente