Converti un punto della bussola in gradi


18

Ho affrontato questa sfida in modo indipendente, ma si è rivelato il contrario di questa sfida di Doorknob . Dato che mi piacciono molto le sue specifiche, ho deciso di rubarne gran parte invece di preparare le mie spiegazioni.

La sfida

Data l'abbreviazione di uno dei 32 punti sulla bussola, stampare i gradi corrispondenti. Sentiti libero di saltare alla tabella seguente se non sei interessato a una spiegazione dei 32 punti.

Ecco la bussola completa:

Immagine

Di Denelson83 (opera propria) [ GFDL o CC-BY-SA-3.0 ], tramite Wikimedia Commons

Ogni direzione è 11,25 (360/32) gradi più avanti della precedente. Ad esempio, N (nord) è 0 gradi, NbE (nord-est) è 11,25 gradi, NNE (nord-nord-est) è 22,5 gradi, ecc.

Nel dettaglio, i nomi sono assegnati come segue:

  • 0 gradi è N, 90 gradi è E, 180 gradi è S e 270 gradi è W. Queste sono chiamate direzioni cardinali.
  • I punti a metà strada tra le direzioni cardinali sono semplicemente le direzioni cardinali tra cui sono concatenati. N o S vanno sempre per primi e W o E sono sempre i secondi. Queste sono chiamate direzioni ordinali. Le direzioni ordinali e cardinali formano insieme i venti principali.
  • I punti a metà strada tra i venti principali sono le direzioni tra cui sono concatenati. Le direzioni cardinali vanno prima, secondo ordinale. Questi sono chiamati mezzi venti.
  • I punti a metà strada tra il vento principale e il mezzo vento sono il vento principale adiacente "per" la direzione cardinale più vicina al vento principale. Questo è indicato con a b. Questi sono chiamati quarti di vento.

Ciò si traduce nella seguente tabella:

#   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

Ecco una tabella più dettagliata e forse una migliore spiegazione dei punti cardinali.

Il tuo compito è quello di prendere come input una delle 32 abbreviazioni dalla terza colonna e generare i gradi corrispondenti nella seconda colonna.

Si può presumere che l'input sarà sempre esattamente una di quelle 32 stringhe (e, facoltativamente, ci si può aspettare una nuova riga finale). Anche l'output deve essere fornito esattamente come elencato sopra, anche se sono consentiti zero finali. Se lo si desidera, è possibile generare una nuova riga finale finale.

È possibile scrivere un programma o una funzione, prendendo l'input tramite STDIN (o l'alternativa più vicina), l'argomento della riga di comando o l'argomento della funzione e producendo il risultato tramite STDOUT (o l'alternativa più vicina), il valore di ritorno della funzione o il parametro della funzione (out).

Questo è il golf del codice, quindi vince la risposta più breve (in byte).

Risposte:


2

Pyth, 47 byte

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

Hexdump, a causa di caratteri non stampabili:

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

Collaudare l'imbragatura

A causa di un bug nel compilatore ufficiale della riga di comando, questo codice funziona solo tramite il compilatore online, collegato sopra o il -cflag del compilatore offline. (Il bug è stato corretto dopo la domanda.)

Questa soluzione è molto simile alla risposta CJam di @Dennis, usando il processo di hashing dell'input, cercando il risultato in una stringa di ricerca a 32 byte e quindi moltiplicando per 11,25.

L'uso funzione hash che è la conversione l'ingresso di una stringa come se fosse un numero intero di base 256 con C, prendendo il modulo risultato Cdi ½, che è 189, ma salva un byte a causa di parsing superiore, e lo ha convertito in una stringa con Cnuovamente .

La moltiplicazione per 11,25 si ottiene moltiplicando per 45, quindi dividendo per 4, risparmiando un byte.


9

Ruby, 118 106

Grazie a Martin Büttner per 12 byte salvati.

Questa è attualmente della stessa lunghezza indipendentemente dal fatto che si tratti di una funzione o di un programma.

funzione 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}

programma

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

Questa è una passeggiata cartesiana attraverso i punti. I caratteri NSEWaggiungono o sottraggono 4 dalle coordinate x e y memorizzate in d[]. Dopo bche NSEWviene rilevato un (o qualsiasi altro simbolo diverso da ), questo viene ridotto a 1.

I dati xey vengono quindi trattati come un numero complesso per estrarre l'argomento angolare. Questo è moltiplicato per 16 / PI = 5.1. Sebbene ci siano alcuni errori geometrici nell'approccio, arrotondare questo angolo è sufficiente per fornire il numero corretto -15..+16. Modulo viene utilizzato per correggere questo in 0..31(in Ruby %restituisce sempre positivo.) Infine il risultato viene moltiplicato per 11,25.


1
Che idea intelligente con l'arrotondamento! Ottieni l'arcano dell'angolo invece dell'angolo, preso in relazione alla direzione ortogonale più vicina, ma risulta abbastanza vicino.
xnor

@xnor senza arrotondamento ottengo NbE 14,05 (+2,8), NNE 26,60 (+4,1), NEbE 51,41 (-4,84), quindi ho avuto un margine di manovra con i valori di nma ho dovuto sceglierli attentamente.
Level River St

6

Javascript (ES6), 153 byte

Volevo solo far rotolare la palla con una semplice.

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

Non particolarmente innovativo, ma funziona e forse ci sono alcuni suggerimenti che potrebbero derivarne. Non preoccuparti, penserò a un'altra tecnica (si spera migliore).


1
Forse puoi comprimere la stringa?
mbomb007,

1
Sorprendentemente, è ancora più breve della mia soluzione (non inviata) in Python, che utilizza un approccio algoritmico.
pawel.boczarski,

2

CJam, 49 byte

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*

Quanto sopra è un hexdump, che può essere invertito con xxd -r -c 17 -g 1.

Provalo online nell'interprete CJam .

Come funziona

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.

1

Java, 653 (caratteri)

So che Java non può vincere, ma mi piace comunque fare lo sforzo.

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]);}}

Prende input dalla riga di comando e li invia alla console. Versione non golfata:

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 ] );
    }
}

Funziona assegnando 0-3 a NW (o 4 per N se W è coinvolto). Riconosce 4 diverse situazioni:

  • parse1 è per punti a lettera singola, restituisce solo il valore.
  • parse2 è per i punti a doppia lettera, fa la media dei valori dei 2 punti.
  • parse3 è per i punti a tripla lettera, prende la media della media del doppio e dei singoli punti.
  • parse3b4 è per tutti quelli con una "b", calcola il valore del punto prima della "b" e aggiunge o sottrae 1/8 in base alla "direzione" del punto dopo la "b".

In print () il valore viene moltiplicato per 90 per ottenere l'angolo effettivo.


È necessario scrivere C c=new C(r[0]);? Forse new C(r[0]);è sufficiente?
pawel.boczarski,

1

Python 3, 149 byte

Ho provato un approccio algoritmico ricorsivo. I quarti di vento erano più difficili da gestire di quanto pensassi all'inizio, quindi questa soluzione è diventata relativamente lunga.

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

Ungolfed:

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

La versione golfata restituisce un decimale che deve essere moltiplicato per 10 ( f("NbW")restituisce 34.875invece di 348.75)
智障 的 人

@ viktorahlström, sei sicuro? Restituisce il valore corretto per me. Forse hai perso l'ultimo zero durante la copia e incolla del codice?
Emil,

Oh, scusa, a quanto pare è stato questo - il mio errore, scusa!
的 的 人

1

Haskell, 206 byte

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

Test 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]

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()

0

Julia, 151 147 142 byte

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 po 'non golfato:

# 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

Nel codice ungolf, conto la media di due vettori come avg = e ^ {jArg (v_1 + v_2)}per avere il vettore ancora normalizzato. Tuttavia, gli errori dovuti all'allungamento del primo vettore non si stanno ancora accumulando con così poche aggiunte nella nostra ricorsione, quindi mentre si gioca a golf la fase di normalizzazione è stata rimossa e il calcolo procede avg = v_1 + v_2semplicemente. Gli errori inferiori a 1/64 del cerchio completo vengono filtrati per arrotondamento.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.