Chuyển đổi một điểm của la bàn thành độ


18

Tôi đã đưa ra thử thách này một cách độc lập, nhưng hóa ra nó lại trái ngược với thử thách này của Doorknob . Vì tôi thực sự thích thông số kỹ thuật của anh ấy, tôi quyết định ăn cắp những phần lớn của nó thay vì nấu những lời giải thích của riêng tôi.

Các thách thức

Cho chữ viết tắt của một trong 32 điểm trên la bàn, in độ tương ứng. Vui lòng bỏ qua bảng phía dưới nếu bạn không quan tâm đến lời giải thích về 32 điểm.

Đây là la bàn đầy đủ:

hình ảnh

Bởi Denelson83 (Công việc riêng) [ GFDL hoặc CC-BY-SA-3.0 ], qua Wikimedia Commons

Mỗi hướng là 11,25 (360/32) xa hơn so với trước đó. Ví dụ: N (phía bắc) là 0 độ, NbE (phía bắc theo hướng đông) là 11,25 độ, NNE (phía bắc-đông bắc) là 22,5 độ, v.v.

Cụ thể, các tên được gán như sau:

  • 0 độ là N, 90 độ là E, 180 độ là S và 270 độ là W. Chúng được gọi là hướng hồng y.
  • Các điểm giữa các hướng hồng y chỉ đơn giản là các hướng hồng y nằm giữa chúng. N hoặc S luôn đi đầu và W hoặc E luôn đứng thứ hai. Chúng được gọi là hướng thứ tự. Các hướng thứ tự và hồng y cùng nhau tạo thành gió chính.
  • Các điểm giữa các cơn gió chính là các hướng giữa chúng được nối với nhau. Hướng hồng y đi trước, thứ hai thứ hai. Chúng được gọi là một nửa gió.
  • Các điểm giữa của gió chính và gió nửa là gió chính liền kề "bởi" hướng hồng y gần nhất cách xa gió chính. Điều này được ký hiệu là a b. Chúng được gọi là gió quý.

Kết quả này trong biểu đồ sau:

#   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

Dưới đây là một biểu đồ chi tiết hơn và có thể giải thích tốt hơn về các điểm của la bàn.

Nhiệm vụ của bạn là lấy một trong 32 chữ viết tắt từ cột thứ ba và xuất độ tương ứng trong cột thứ hai.

Bạn có thể cho rằng đầu vào sẽ luôn chính xác là một trong 32 chuỗi đó (và bạn có thể tùy ý nhưng luôn mong đợi một dòng mới duy nhất). Đầu ra cũng phải được cung cấp chính xác như được liệt kê ở trên, mặc dù các số 0 ở cuối được cho phép. Bạn có thể tùy ý xuất một dòng mới duy nhất.

Bạn có thể viết chương trình hoặc hàm, lấy đầu vào qua STDIN (hoặc thay thế gần nhất), đối số dòng lệnh hoặc đối số hàm và xuất kết quả qua tham số STDOUT (hoặc thay thế gần nhất), tham số trả về hàm hoặc tham số hàm (out).

Đây là mã golf, vì vậy câu trả lời ngắn nhất (tính bằng byte) sẽ thắng.

Câu trả lời:


2

Bình thường, 47 byte

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

Hexdump, do các ký tự không thể in:

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

Khai thác thử nghiệm

Do một lỗi trong trình biên dịch dòng lệnh chính thức, mã này chỉ hoạt động thông qua trình biên dịch trực tuyến, được liên kết ở trên hoặc -ccờ của trình biên dịch ngoại tuyến. (Lỗi đã được sửa sau khi câu hỏi được hỏi.)

Giải pháp này rất giống với câu trả lời CJam của @ Dennis, sử dụng quá trình băm đầu vào, tra cứu kết quả trong chuỗi tra cứu 32 byte, sau đó nhân với 11,25.

Việc sử dụng hàm băm I được chuyển đổi đầu vào thành một chuỗi như thể nó là một số nguyên cơ sở 256 với C, lấy modulo kết quả Ccủa ½, đó là 189, nhưng tiết kiệm một byte do phân tích vượt trội, và chuyển đổi trở lại đó để một chuỗi với Cmột lần nữa .

Nhân với 11,25 được thực hiện bằng cách nhân với 45, sau đó chia cho 4, giúp tiết kiệm một byte.


9

Hồng ngọc, 118 106

Cảm ơn Martin Büttner đã lưu 12 byte.

Đây hiện là cùng một độ dài bất kể đó là chức năng hay chương trình.

chức năng 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}

chương trình

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

Đây là một cartesian đi qua các điểm. Các ký tự NSEWcộng hoặc trừ 4 từ tọa độ x và y được lưu trữ trong d[]. Sau khi gặp b(hoặc bất kỳ ký hiệu nào khác NSEW), điều này giảm xuống còn 1.

Dữ liệu x và y sau đó được coi là một số phức để trích xuất đối số góc. Điều này được nhân với 16 / PI = 5.1. Mặc dù có một số lỗi hình học trong cách tiếp cận, làm tròn góc này là đủ để đưa ra con số chính xác -15..+16. Modulo được sử dụng để sửa lỗi này thành 0..31(trong Ruby %luôn trả về giá trị dương.) Cuối cùng, kết quả được nhân với 11,25.


1
Thật là một ý tưởng thông minh với làm tròn! Bạn nhận được arctan của góc thay vì góc, được lấy tương đối với hướng trực giao gần nhất, nhưng nó lại đủ gần.
xnor

@xnor mà không làm tròn tôi nhận được NbE 14.05 (+2.8), NNE 26.60 (+4.1), NEbE 51.41 (-4.84) ​​vì vậy tôi đã mất một số thời gian với các giá trị của nnhưng tôi đã phải chọn chúng một cách cẩn thận.
Cấp sông St

6

Javascript (ES6), 153 byte

Chỉ muốn có được quả bóng lăn với một đơn giản.

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

Không đặc biệt sáng tạo, nhưng nó hoạt động, và có lẽ có một số lời khuyên có thể bắt nguồn từ nó. Đừng lo lắng, tôi sẽ nghĩ về một kỹ thuật khác (hy vọng tốt hơn).


1
Có lẽ bạn có thể nén chuỗi?
mbomb007

1
Thật đáng ngạc nhiên, nó vẫn ngắn hơn giải pháp (chưa được gửi) của tôi trong Python, sử dụng phương pháp tiếp cận thuật toán.
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*

Trên đây là một hexdump, có thể được đảo ngược với xxd -r -c 17 -g 1.

Hãy thử trực tuyến trong trình thông dịch CJam .

Làm thế nào nó hoạt động

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 (ký tự)

Tôi biết Java không thể thắng nhưng dù sao tôi cũng muốn nỗ lực.

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

Nó nhận đầu vào từ dòng lệnh và đầu ra cho bàn điều khiển. Phiên bản bị đánh cắp:

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

Nó hoạt động bằng cách gán 0-3 cho NW (hoặc 4 cho N nếu W có liên quan). Nó nhận ra 4 tình huống khác nhau:

  • parse1 là cho các điểm chữ cái duy nhất, nó chỉ trả về giá trị.
  • parse2 dành cho các điểm chữ kép, nó tính trung bình các giá trị của 2 điểm.
  • parse3 là cho ba điểm chữ cái, nó lấy trung bình của trung bình của gấp đôi và các điểm duy nhất.
  • parse3b4 dành cho tất cả những người có 'b' trong đó, nó tính giá trị của điểm trước 'b' và cộng hoặc trừ 1/8 dựa trên 'hướng' của điểm sau 'b'.

Trong print () giá trị được nhân với 90 để có được góc thực.


Có cần thiết phải viết C c=new C(r[0]);không? Có lẽ new C(r[0]);là đủ?
pawel.boczarski

1

Python 3, 149 byte

Tôi đã thử một cách tiếp cận thuật toán đệ quy. Gió quý khó xử lý hơn tôi nghĩ lúc đầu, vì vậy giải pháp này phát triển tương đối dài.

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

Ung dung:

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

Phiên bản chơi gôn trả về số thập phân cần được nhân với 10 ( f("NbW")trả về 34.875thay vì 348.75)
智障 的

@ viktorahlström, bạn có chắc không? Nó trả về giá trị chính xác cho tôi. Có lẽ bạn đã bỏ lỡ số 0 cuối cùng khi sao chép và dán mã?
Emil

Ồ, xin lỗi, rõ ràng đó là - lỗi của tôi, xin lỗi!
智障 的

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

Kiểm tra thuận tiện:

*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

Một chút vô duyên:

# 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

Trong mã không mã hóa, tôi đếm trung bình của hai vectơ như avg = e ^ {jArg (v_1 + v_2)}để vectơ vẫn được chuẩn hóa. Tuy nhiên, các lỗi do độ giãn dài của vectơ đầu tiên vẫn chưa được tích lũy với rất ít bổ sung trong đệ quy của chúng tôi, vì vậy trong khi chơi golf, bước chuẩn hóa đã được loại bỏ và việc tính toán diễn ra avg = v_1 + v_2đơn giản. Các lỗi nhỏ hơn 1/64 của vòng tròn đầy đủ được lọc ra bằng cách làm tròn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.