Konwertuj punkt kompasu na stopnie

18

Podjąłem to wyzwanie niezależnie, ale okazało się, że jest odwrotnością tego wyzwania Doorknob . Ponieważ bardzo podoba mi się jego specyfikacja, postanowiłem ukraść jej duże części zamiast gotować własne wyjaśnienia.

Wyzwanie

Biorąc pod uwagę skrót jednego z 32 punktów na kompasie, wydrukuj odpowiednie stopnie. Jeśli nie jesteś zainteresowany wyjaśnieniem 32 punktów, możesz przejść do poniższej tabeli.

Oto pełny kompas:

wizerunek

Autor: Denelson83 (praca własna) [ GFDL lub CC-BY-SA-3.0 ], za pośrednictwem Wikimedia Commons

Każdy kierunek jest o 11,25 (360/32) stopni dalej niż poprzedni. Na przykład N (północ) wynosi 0 stopni, NbE (północ na wschód) wynosi 11,25 stopni, NNE (północno-północny wschód) wynosi 22,5 stopnia itp.

Szczegółowo nazwy są przypisywane w następujący sposób:

  • 0 stopni to N, 90 stopni to E, 180 stopni to S, a 270 stopni to W. Są to tak zwane kierunki kardynalne.
  • Punkty w połowie drogi między głównymi kierunkami są po prostu głównymi kierunkami, które znajdują się między połączonymi. N lub S zawsze są pierwsze, a W lub E zawsze są drugie. Są to tak zwane kierunki porządkowe. Kierunki porządkowy i kardynalny razem tworzą główne wiatry.
  • Punkty w połowie drogi między głównymi wiatrami to kierunki, które łączą je ze sobą. Kierunki kardynalne idą pierwsze, porządkowe drugie. Są to tak zwane pół wiatry.
  • Punkty w połowie drogi między wiatrem głównym a połowicznym to sąsiedni wiatr główny „o” najbliższym kierunku kardynalnym od wiatru głównego. Jest to oznaczone symbolem b. Są to tak zwane wiatry ćwiartkowe.

Powoduje to następujący wykres:

#   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

Oto bardziej szczegółowa tabela i być może lepsze wyjaśnienie punktów kompasu.

Twoim zadaniem jest pobranie jednego z 32 skrótów z trzeciej kolumny i wypisanie odpowiednich stopni w drugiej kolumnie.

Możesz założyć, że wejście zawsze będzie dokładnie jednym z tych 32 ciągów (i możesz opcjonalnie, ale konsekwentnie oczekiwać pojedynczego nowego wiersza). Dane wyjściowe należy również podawać dokładnie tak, jak podano powyżej, chociaż dozwolone są zera końcowe Opcjonalnie możesz wypisać jeden końcowy znak nowej linii.

Możesz napisać program lub funkcję, pobierając dane wejściowe przez STDIN (lub najbliższą alternatywę), argument wiersza poleceń lub argument funkcji i wypisując wynik przez STDOUT (lub najbliższą alternatywę), wartość zwracaną funkcji lub parametr funkcji (wyjściowej).

To jest kod golfowy, więc wygrywa najkrótsza odpowiedź (w bajtach).

Martin Ender
źródło

Odpowiedzi:

2

Pyth, 47 bajtów

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

Hexdump, ze względu na niedrukowalne znaki:

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

Uprząż testowa

Z powodu błędu w oficjalnym kompilatorze z wiersza poleceń ten kod działa tylko za pośrednictwem kompilatora online, pod powyższym linkiem lub -cflagi kompilatora offline. (Błąd został naprawiony po zadaniu pytania).

To rozwiązanie jest bardzo podobne do odpowiedzi CJam @ Dennisa, przy użyciu procesu mieszania danych wejściowych, wyszukiwania wyniku w 32-bajtowym ciągu wyszukiwania, a następnie mnożenia przez 11,25.

Zastosowanie funkcji mieszania I konwersji wprowadzania do kolumny, jak gdyby był to podstawa 256 liczba całkowita C, przy modulo wynik Cz ½, która wynosi 189, lecz pozwala na oszczędność bajt dzięki doskonałej analizy składniowej i przetwarzania tego powrotem do kolumny z Cponownie .

Mnożenie przez 11,25 odbywa się przez pomnożenie przez 45, a następnie podzielenie przez 4, co oszczędza bajt.

isaacg
źródło
9

Ruby, 118 106

Dzięki Martin Büttner za 12 bajtów zapisanych.

Jest to obecnie ta sama długość, niezależnie od tego, czy jest to funkcja, czy program.

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

program

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

To kartezjański spacer po punktach. Znaki NSEWdodają lub odejmują 4 od współrzędnych xiy zapisanych w d[]. Po napotkaniu b(lub dowolnego innego symbolu niż NSEW) jest on redukowany do 1.

Dane xiy są następnie traktowane jako liczba zespolona w celu wyodrębnienia argumentu kątowego. Mnoży się to przez 16 / PI = 5.1. Chociaż w podejściu występują pewne błędy geometryczne, zaokrąglenie tego kąta jest wystarczające do podania prawidłowej liczby -15..+16. Modulo służy do poprawienia tego 0..31(w Ruby %zawsze zwraca wartość dodatnią.) Ostatecznie wynik jest mnożony przez 11,25.

Level River St
źródło
1
Cóż za sprytny pomysł z zaokrąglaniem! Otrzymujesz arctan kąta zamiast kąta, wzięty w stosunku do najbliższego prostopadłego kierunku, ale okazuje się, że jest wystarczająco blisko.
xnor
@ xnor bez zaokrąglania dostaję NbE 14,05 (+2,8), NNE 26,60 (+4,1), NEbE 51,41 (-4,84), więc miałem trochę swobody w zakresie wartości, nale musiałem je ostrożnie wybierać.
Level River St
6

JavaScript (ES6), 153 bajty

Chciałem tylko, żeby piłka toczyła się z prostą.

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

Nie jest to szczególnie innowacyjne, ale działa, a być może istnieją pewne wskazówki, które można z niego wyciągnąć. Nie martw się, wymyślę inną (miejmy nadzieję lepszą) technikę.

ETHprodukcje
źródło
1
Być może możesz skompresować ciąg?
mbomb007,
1
O dziwo, wciąż jest krótszy niż moje (nie przesłane) rozwiązanie w Pythonie, które wykorzystuje podejście algorytmiczne.
pawel.boczarski
2

CJam, 49 bajtów

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*

Powyżej jest zrzut heksowy, który można odwrócić za pomocą xxd -r -c 17 -g 1.

Wypróbuj online w interpretatorze CJam .

Jak to działa

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
źródło
1

Java, 653 (znaki)

Wiem, że Java nie może wygrać, ale i tak staram się.

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

Pobiera dane z wiersza poleceń i dane wyjściowe do konsoli. Wersja bez golfa:

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

Działa poprzez przypisanie 0-3 do NW (lub 4 dla N, jeśli zaangażowany jest W). Rozpoznaje 4 różne sytuacje:

  • parse1 odnosi się do pojedynczych liter, po prostu zwraca wartość.
  • parse2 jest dla podwójnych liter, uśrednia wartości 2 punktów.
  • parse3 jest dla potrójnych liter, przyjmuje średnią z podwójnych i pojedynczych punktów.
  • parse3b4 jest dla wszystkich z literą „b”, oblicza wartość punktu przed „b” i dodaje lub odejmuje 1/8 na podstawie „kierunku” punktu po „b”.

W print () wartość jest mnożona przez 90, aby uzyskać rzeczywisty kąt.

Harry Blargle
źródło
Czy trzeba pisać C c=new C(r[0]);? Może new C(r[0]);wystarczy?
pawel.boczarski
1

Python 3, 149 bajtów

Wypróbowałem rekurencyjne podejście algorytmiczne. Ćwiartkowe wiatry były trudniejsze do opanowania, niż początkowo myślałem, więc to rozwiązanie stało się stosunkowo długie.

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

Nie golfowany:

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
źródło
Wersja w golfa zwraca liczbę dziesiętną, którą należy pomnożyć przez 10 ( f("NbW")zwraca 34.875zamiast 348.75)
21 的 人
@ viktorahlström, jesteś pewien? Zwraca mi poprawną wartość. Może pominąłeś ostatnie zero podczas kopiowania i wklejania kodu?
Emil,
Och, przepraszam, najwyraźniej tak było - mój błąd, przepraszam!
智障 的 人
1

Haskell, 206 bajtów

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

Wygodny 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]
Leif Willerts
źródło
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
źródło
0

Julia, 151 147 142 bajtów

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

Nieco golfista:

# 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

W kodzie bez golfa liczę średnią dwóch wektorów avg = e ^ {jArg (v_1 + v_2)}, aby wektor nadal był znormalizowany. Jednak błędy wynikające z wydłużenia pierwszego wektora nie kumulują się przy tak małych dodatkach w naszej rekurencji, więc podczas gry w golfa krok normalizacji został usunięty, a obliczenia idą śr. = v_1 + v_2po prostu. Błędy mniejsze niż 1/64 pełnego koła są odfiltrowywane przez zaokrąglanie.

pawel.boczarski
źródło