Konvertieren Sie einen Punkt des Kompasses in Grad


18

Ich habe diese Herausforderung unabhängig erarbeitet, aber es stellt sich heraus, dass Doorknob die Umkehrung dieser Herausforderung darstellt . Da ich seine Spezifikation wirklich mag, habe ich beschlossen, große Teile davon zu stehlen, anstatt meine eigenen Erklärungen zu erfinden.

Die Herausforderung

Bei der Abkürzung eines der 32 Punkte auf dem Kompass die entsprechenden Grade ausdrucken. Wenn Sie keine Erklärung für die 32 Punkte wünschen, können Sie gerne zur folgenden Tabelle springen.

Hier ist der vollständige Kompass:

Bild

Von Denelson83 (Eigene Arbeit) [ GFDL oder CC-BY-SA-3.0 ] über Wikimedia Commons

Jede Richtung ist 11,25 (360/32) Grad weiter als die vorherige. Beispielsweise beträgt N (Nord) 0 Grad, NbE (Nord-Ost) 11,25 Grad, NNE (Nord-Nordost) 22,5 Grad usw.

Im Detail werden die Namen wie folgt vergeben:

  • 0 Grad ist N, 90 Grad ist E, 180 Grad ist S und 270 Grad ist W. Diese werden als Himmelsrichtungen bezeichnet.
  • Die halben Punkte zwischen den Himmelsrichtungen sind einfach die Himmelsrichtungen, zwischen denen sie verkettet sind. N oder S stehen immer an erster Stelle, und W oder E stehen immer an zweiter Stelle. Diese werden Ordnungsrichtungen genannt. Die Ordnungs- und Kardinalrichtungen bilden zusammen die Hauptwinde.
  • Die halben Punkte zwischen den Hauptwinden sind die Richtungen, in die sie miteinander verbunden sind. Kardinalrichtungen gehen zuerst, Ordinalsekunde. Diese werden Halbwinde genannt.
  • Die Zwischenpunkte zwischen Haupt- und Halbwind sind der benachbarte Hauptwind "nach" der dem Hauptwind am nächsten liegenden Himmelsrichtung. Dies ist mit a bezeichnet b. Diese werden Viertelwinde genannt.

Daraus ergibt sich folgende Grafik:

#   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

Hier ist eine detailliertere Tabelle und möglicherweise eine bessere Erklärung der Himmelsrichtungen.

Ihre Aufgabe ist es, eine der 32 Abkürzungen aus der dritten Spalte als Eingabe zu übernehmen und die entsprechenden Grade in der zweiten Spalte auszugeben.

Sie können davon ausgehen, dass die Eingabe immer genau eine dieser 32 Zeichenfolgen ist (und Sie können optional, aber konsistent, eine einzelne nachgestellte Newline erwarten). Die Ausgabe sollte ebenfalls genau wie oben angegeben erfolgen, obwohl nachgestellte Nullen zulässig sind. Optional können Sie eine einzelne nachgestellte Newline ausgeben.

Sie können ein Programm oder eine Funktion schreiben, indem Sie eine Eingabe über STDIN (oder die nächstgelegene Alternative), ein Befehlszeilenargument oder ein Funktionsargument vornehmen und das Ergebnis über STDOUT (oder die nächstgelegene Alternative), einen Funktionsrückgabewert oder einen Funktionsparameter (out) ausgeben.

Dies ist Codegolf, daher gewinnt die kürzeste Antwort (in Bytes).

Antworten:


2

Pyth, 47 Bytes

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

Hexdump aufgrund nicht druckbarer Zeichen:

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

Kabelbaum testen

Aufgrund eines Fehlers im offiziellen Befehlszeilen-Compiler funktioniert dieser Code nur über den oben verlinkten Online-Compiler oder das -cFlag des Offline-Compilers. (Der Fehler wurde behoben, nachdem die Frage gestellt wurde.)

Diese Lösung ist der Antwort von @ Dennis in CJam sehr ähnlich. Dabei wird die Eingabe durchsucht, das Ergebnis in einer 32-Byte-Suchzeichenfolge nachgeschlagen und dann mit 11,25 multipliziert.

Die Hash-Funktion, die ich verwende, konvertiert die Eingabe in eine Zeichenfolge, als wäre sie eine ganze Zahl zur Basis von 256 C, wobei das Ergebnismodul Cvon ½189 verwendet wird, aber ein Byte aufgrund der überlegenen Syntaxanalyse gespeichert wird, und das Ergebnis mit Cerneut in eine Zeichenfolge konvertiert wird .

Die Multiplikation mit 11,25 erfolgt durch Multiplikation mit 45 und anschließende Division durch 4, wodurch ein Byte eingespart wird.


9

Ruby, 118 106

Danke an Martin Büttner für die 12 Bytes gespart.

Dies ist derzeit die gleiche Länge, unabhängig davon, ob es sich um eine Funktion oder ein Programm handelt.

Lambda-Funktion

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

Programm

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

Dies ist eine kartesische Wanderung durch die Punkte. Die Zeichen NSEWaddieren oder subtrahieren 4 von den in gespeicherten x- und y-Koordinaten d[]. Nachdem ein b(oder ein anderes als ein NSEW) Symbol gefunden wurde , wird dieses auf 1 reduziert.

Die x- und y-Daten werden dann als komplexe Zahl behandelt, um das Winkelargument zu extrahieren. Dies wird mit 16 / PI = multipliziert 5.1. Obwohl der Ansatz einige geometrische Fehler enthält, reicht die Rundung dieses Winkels aus, um die richtige Zahl zu erhalten -15..+16. Modulo wird verwendet, um dies zu korrigieren 0..31(in Ruby wird %immer ein positiver Wert zurückgegeben). Schließlich wird das Ergebnis mit 11,25 multipliziert.


1
Was für eine clevere Idee beim Runden! Sie erhalten den Arktan des Winkels anstelle des Winkels, bezogen auf die nächstgelegene orthogonale Richtung, aber das ist nah genug.
15.

@xnor ohne die Rundung bekomme ich NbE 14.05 (+2.8), NNE 26.60 (+4.1), NEbE 51.41 (-4.84), also hatte ich etwas Spielraum mit den Werten von n, musste sie aber sorgfältig auswählen.
Level River St

6

Javascript (ES6), 153 Byte

Ich wollte den Ball nur mit einem einfachen ins Rollen bringen.

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

Nicht besonders innovativ, aber es funktioniert, und vielleicht gibt es einige Tipps, die daraus abgeleitet werden könnten. Keine Sorge, ich werde mir eine andere (hoffentlich bessere) Technik überlegen.


1
Vielleicht können Sie die Zeichenfolge komprimieren?
mbomb007

1
Erstaunlicherweise ist es immer noch kürzer als meine (nicht eingereichte) Lösung in Python, die einen algorithmischen Ansatz verwendet.
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*

Das obige ist ein Hexdump, der mit umgekehrt werden kann xxd -r -c 17 -g 1.

Probieren Sie es online im CJam-Interpreter aus .

Wie es funktioniert

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

Ich weiß, dass Java nicht gewinnen kann, aber ich möchte mich trotzdem anstrengen.

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

Es nimmt Eingaben von der Kommandozeile entgegen und gibt sie an die Konsole aus. Ungolfed-Version:

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

Es funktioniert durch Zuweisen von 0-3 zu NW (oder 4 für N, wenn W beteiligt ist). Es werden 4 verschiedene Situationen erkannt:

  • parse1 ist für einzelne Buchstabenpunkte und gibt nur den Wert zurück.
  • parse2 ist für Doppelbuchstabenpunkte und mittelt die Werte der 2 Punkte.
  • parse3 ist für Punkte mit drei Buchstaben, es wird der Durchschnitt aus dem Durchschnitt der doppelten und der einzelnen Punkte gebildet.
  • parse3b4 berechnet für alle mit einem 'b' den Wert des Punktes vor dem 'b' und addiert oder subtrahiert 1/8 basierend auf der 'Richtung' des Punktes nach dem 'b'.

In print () wird der Wert mit 90 multipliziert, um den tatsächlichen Winkel zu erhalten.


Ist es notwendig zu schreiben C c=new C(r[0]);? Vielleicht new C(r[0]);reicht das aus?
pawel.boczarski

1

Python 3, 149 Bytes

Ich habe einen rekursiven algorithmischen Ansatz ausprobiert. Die Viertelwinde waren schwerer zu bewältigen als ich zunächst dachte, so dass diese Lösung relativ lang wuchs.

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

Golfed Version liefert eine Dezimalzahl , dass der Bedarf von 10 (multipliziert werden f("NbW")kehrt 34.875statt 348.75)
智障的人

@ viktorahlström, bist du sicher? Es gibt den richtigen Wert für mich zurück. Vielleicht haben Sie beim Kopieren und Einfügen des Codes die letzte Null verpasst?
Emil

Oh, sorry, anscheinend war es das - mein Fehler, sorry!
Dienstag,

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

Bequemer Test:

*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 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

Ein bisschen ungolfed:

# 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

Im ungolfed Code zähle ich den Durchschnitt von zwei Vektoren avg = e ^ {jArg (v_1 + v_2)}, um den Vektor noch normalisieren zu lassen. Die Fehler aufgrund der Verlängerung des ersten Vektors häufen sich jedoch noch nicht mit so geringen Zusätzen in unserer Rekursion an, so dass während des Golfspiels der Normalisierungsschritt entfernt wurde und die Berechnung avg = v_1 + v_2einfach verläuft. Fehler, die kleiner als 1/64 des Vollkreises sind, werden durch Runden herausgefiltert.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.