Konversi Titik Kompas ke Derajat


18

Saya datang dengan tantangan ini secara mandiri, tetapi ternyata kebalikan dari tantangan ini oleh Doorknob . Karena saya sangat menyukai speknya, saya memutuskan untuk mencuri sebagian besar alih-alih memasak penjelasan saya sendiri.

Tantangan

Diberi singkatan dari salah satu dari 32 poin pada kompas, cetak derajat yang sesuai. Jangan ragu untuk langsung beralih ke tabel di bawah ini jika Anda tidak tertarik dengan penjelasan 32 poin.

Ini kompas lengkap:

gambar

Oleh Denelson83 (Pekerjaan sendiri) [ GFDL atau CC-BY-SA-3.0 ], melalui Wikimedia Commons

Setiap arah adalah 11,25 (360/32) derajat lebih jauh dari sebelumnya. Sebagai contoh, N (utara) adalah 0 derajat, NbE (utara oleh timur) adalah 11,25 derajat, NNE (utara-timur laut) adalah 22,5 derajat, dll.

Secara rinci, nama-nama tersebut ditetapkan sebagai berikut:

  • 0 derajat adalah N, 90 derajat adalah E, 180 derajat adalah S, dan 270 derajat adalah W. Ini disebut arah mata angin.
  • Titik setengah antara arah mata angin hanyalah arah mata angin mereka di antara disatukan. N atau S selalu menjadi yang pertama, dan W atau E selalu menjadi yang kedua. Ini disebut arahan ordinal. Arah ordinal dan kardinal bersama-sama membentuk angin utama.
  • Titik tengah di antara angin utama adalah arah di antara keduanya. Arahan kardinal pergi dulu, ordinal kedua. Ini disebut setengah angin.
  • Titik tengah antara angin utama dan setengah adalah angin utama yang berdekatan "dengan" arah mata angin terdekat dari angin utama. Ini dilambangkan dengan a b. Ini disebut seperempat angin.

Ini menghasilkan bagan berikut:

#   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

Berikut adalah bagan yang lebih terperinci dan mungkin penjelasan yang lebih baik tentang titik-titik kompas.

Tugas Anda adalah mengambil salah satu dari 32 singkatan dari kolom ketiga dan menampilkan derajat yang sesuai di kolom kedua.

Anda dapat mengasumsikan bahwa input akan selalu menjadi salah satu dari 32 string (dan Anda dapat secara opsional tetapi secara konsisten mengharapkan satu baris baru). Output juga harus diberikan persis seperti yang tercantum di atas, meskipun trailing nol diperbolehkan. Anda secara opsional dapat menampilkan satu baris baru.

Anda dapat menulis sebuah program atau fungsi, mengambil input melalui STDIN (atau alternatif terdekat), argumen baris perintah atau argumen fungsi dan mengeluarkan hasilnya melalui STDOUT (atau alternatif terdekat), nilai pengembalian fungsi atau parameter function (out).

Ini kode golf, jadi jawaban tersingkat (dalam byte) menang.

Jawaban:


2

Pyth, 47 byte

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

Hexdump, karena karakter yang tidak patut dicetak:

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

Uji harness

Karena ada bug di kompiler baris perintah resmi, kode ini hanya berfungsi melalui kompiler online, ditautkan di atas, atau -cbendera kompiler offline. (Bug diperbaiki setelah pertanyaan diajukan.)

Solusi ini sangat mirip dengan jawaban CJam @ Dennis, menggunakan proses hashing input, mencari hasilnya dalam string lookup 32 byte, dan kemudian mengalikannya dengan 11.25.

Fungsi hash saya gunakan adalah mengkonversi input ke string seakan itu adalah dasar 256 bilangan bulat dengan C, mengambil hasil modulo Cdari ½, yang 189, tapi menghemat byte karena parsing unggul, dan mengkonversi kembali bahwa untuk string dengan Clagi .

Mengalikan dengan 11,25 dilakukan dengan mengalikan dengan 45, kemudian membaginya dengan 4, yang menghemat satu byte.


9

Ruby, 118 106

Terima kasih kepada Martin Büttner untuk 12 byte yang disimpan.

Saat ini panjangnya sama terlepas dari apakah itu fungsi atau program.

fungsi 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

Ini adalah jalan kartesian melalui poin. Karakter NSEWmenambah atau mengurangi 4 dari koordinat x dan y yang disimpan di d[]. Setelah b(atau simbol apa pun selain NSEW) ditemukan, ini dikurangi menjadi 1.

Data x dan y kemudian diperlakukan sebagai bilangan kompleks untuk mengekstraksi argumen sudut. Ini dikalikan dengan 16 / PI = 5.1. Meskipun ada beberapa kesalahan geometris dalam pendekatan, membulatkan sudut ini cukup untuk memberikan angka yang benar -15..+16. Modulo digunakan untuk memperbaiki ini menjadi 0..31(dalam Ruby %selalu mengembalikan positif.) Akhirnya hasilnya dikalikan dengan 11.25.


1
Ide yang cerdas dengan pembulatan! Anda mendapatkan arctan dari sudut bukan dari sudut, diambil relatif terhadap arah ortogonal terdekat, tetapi ternyata cukup dekat.
xnor

@ xnor tanpa pembulatan, saya mendapatkan NbE 14.05 (+2.8), NNE 26.60 (+4.1), NEbE 51.41 (-4.84) ​​jadi saya memiliki beberapa kelonggaran dengan nilai-nilai ntetapi saya harus memilihnya dengan hati-hati.
Level River St

6

Javascript (ES6), 153 byte

Hanya ingin bola bergulir dengan yang sederhana.

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

Tidak terlalu inovatif, tetapi berhasil, dan mungkin ada beberapa tips yang bisa diambil darinya. Jangan khawatir, saya akan memikirkan teknik lain (semoga lebih baik).


1
Mungkin Anda bisa mengompres string?
mbomb007

1
Hebatnya, ini masih lebih pendek daripada solusi saya (tidak dikirimkan) dengan Python, yang menggunakan pendekatan algoritmik.
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*

Di atas adalah hexdump, yang dapat dibalik dengan xxd -r -c 17 -g 1.

Cobalah online di juru bahasa CJam .

Bagaimana itu bekerja

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

Saya tahu Java tidak bisa menang tetapi saya tetap berusaha.

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

Dibutuhkan input dari commandline dan output ke konsol. Versi tidak disatukan:

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

Ia bekerja dengan menetapkan 0-3 ke NW (atau 4 untuk N jika W terlibat). Ia mengenali 4 situasi berbeda:

  • parse1 adalah untuk poin huruf tunggal, itu hanya mengembalikan nilai.
  • parse2 adalah untuk poin huruf ganda, itu rata-rata nilai dari 2 poin.
  • parse3 adalah untuk poin surat rangkap tiga, dibutuhkan rata-rata rata-rata poin ganda dan tunggal.
  • parse3b4 adalah untuk semua yang memiliki 'b' di dalamnya, ia menghitung nilai titik sebelum 'b' dan menambah atau mengurangi 1/8 berdasarkan 'arah' dari titik setelah 'b'.

Dalam cetakan () nilainya dikalikan dengan 90 untuk mendapatkan sudut yang sebenarnya.


Apakah perlu menulis C c=new C(r[0]);? Mungkin new C(r[0]);sudah cukup?
pawel.boczarski

1

Python 3, 149 byte

Saya mencoba pendekatan algoritmik rekursif. Perempat angin lebih sulit untuk ditangani daripada yang saya pikirkan pada awalnya, jadi solusi ini tumbuh relatif lama.

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

Tidak Disatukan:

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

Versi golf mengembalikan desimal yang perlu dikalikan dengan 10 ( f("NbW")pengembalian 34.875bukan 348.75)
智障 的 人

@ viktorahlström, Anda yakin? Ini mengembalikan nilai yang benar untuk saya. Mungkin Anda melewatkan nol terakhir saat menyalin dan menempelkan kode?
Emil

Oh, maaf, ternyata itu - kesalahan saya, maaf!
智障 的 人

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

Tes yang mudah:

*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

Sedikit tidak 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

Dalam kode yang tidak dikenali, saya menghitung rata-rata dua vektor rata-rata = e ^ {jArg (v_1 + v_2)}agar vektor masih dinormalisasi. Namun, kesalahan karena perpanjangan vektor pertama belum terakumulasi dengan penambahan yang sangat sedikit dalam rekursi kami, jadi saat bermain golf langkah normalisasi telah dihapus dan perhitungan berjalan dengan rata-rata = v_1 + v_2sederhana. Kesalahan kurang dari 1/64 lingkaran penuh disaring dengan pembulatan.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.