コンパスのポイントを度に変換する


18

私はこのチャレンジを独自に思いつきましたが、それはDoorknobによるこのチャレンジの逆であることが判明しました。彼の仕様が本当に好きなので、私は自分の説明を作り上げるのではなく、その大部分を盗むことにしました。

チャレンジ

コンパス上の32点のいずれかの略語を指定して、対応する度数を印刷します。32ポイントの説明に興味がない場合は、下の表に進んでください。

完全なコンパスは次のとおりです。

画像

Denelson83(所有作品)[ GFDLまたはCC-BY-SA-3.0 ]、ウィキメディアコモンズ経由

各方向は11.25(360/32)度離れています。たとえば、N(北)は0度、NbE(北から東)は11.25度、NNE(北-北東)は22.5度などです。

詳細には、名前は次のように割り当てられます。

  • 0度はN、90度はE、180度はS、270度はWです。これらは基本方向と呼ばれます。
  • 基数方向の中間点は、単に連結された基点方向です。NまたはSは常に最初に、WまたはEは常に2番目になります。これらは順序方向と呼ばれます。序数方向と基数方向が一緒になって主な風を形成します。
  • 主な風の中間点は、それらが連結されている間の方向です。枢機directionsの指示が最初になり、序数の順になります。これらは半風と呼ばれます。
  • 主風と半風の中間地点は、主風から最も近い基本方向の「そば」にある隣接する主風です。これはで示されますb。これらは四分の一風と呼ばれます。

これにより、次のチャートが得られます。

#   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

これは、より詳細なチャートであり、コンパスのポイントのより良い説明です。

あなたの仕事は、3番目の列から32の略語の1つを入力として受け取り、2番目の列に対応する度を出力することです。

入力は常にこれらの32個の文字列のいずれか1つであると想定することができます(オプションとして、しかし常に一貫して単一の末尾の改行を期待できます)。出力も上記のとおりに指定する必要がありますが、末尾のゼロを使用できます。オプションで、単一の末尾の改行を出力できます。

プログラムまたは関数を作成し、STDIN(または最も近い代替)、コマンドライン引数または関数引数を介して入力を取得し、STDOUT(または最も近い代替)、関数の戻り値または関数(out)パラメーターを介して結果を出力できます。

これはコードゴルフなので、最短の回答(バイト単位)が勝ちです。

回答:


2

Pyth、47バイト

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

印刷不能文字によるHexdump:

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

テストハーネス

公式コマンドラインコンパイラのバグのため、このコードは、上記にリンクされているオンラインコンパイラ、または-cオフラインコンパイラのフラグを介してのみ機能します。(質問は質問された後に修正されました。)

このソリューションは@DennisのCJamの回答に非常に似ています。入力をハッシュし、32バイトのルックアップ文字列で結果を検索し、11.25を掛けるプロセスを使用します。

ハッシュ関数Iの使用は、それが有するベース256の整数であるかのように文字列の入力を変換されたC結果のモジュロ取る、C½189であるが、原因の優れた解析にバイトを保存し、で文字列にそのバック変換C再度。

11.25で乗算するには、45を乗算し、4で除算することでバイトを節約します。


9

ルビー、118 106

MartinBüttnerに12バイトの節約をありがとう。

現在、これは関数かプログラムかに関係なく同じ長さです。

ラムダ関数

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

プログラム

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

これはポイントを通るデカルトウォークです。文字NSEWは、に格納されているx座標とy座標から4を加算または減算しd[]ます。後にb(以外のまたは任意のシンボルNSEWに遭遇する)、これは、1に低減されます。

次に、xおよびyデータは複素数として扱われ、角度引数を抽出します。これに16 / PI =を掛け5.1ます。アプローチにはいくつかの幾何学的エラーがありますが、この角度を丸めると正しい数が得られます-15..+16。モジュロを使用してこれを修正します0..31(Rubyでは%常に正を返します)。最後に結果に11.25が乗算されます。


1
丸めとはなんと賢いアイデアでしょう!角度ではなく、角度のアークタンを取得します。これは、最も近い直交方向を基準にして取得されますが、十分に近いことがわかります。
xnor

丸めなしの@xnorでは、NbE 14.05(+2.8)、NNE 26.60(+4.1)、NEbE 51.41(-4.84)が得られるため、値に余裕nがありましたが、慎重に選択する必要がありました。
レベルリバーセント

6

Javascript(ES6)、153バイト

単純なボールでボールを転がしたかっただけです。

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

特に革新的ではありませんが、機能します。おそらく、そこから導き出せるヒントがいくつかあります。心配しないで、別の(できればもっと良い)テクニックを考えます。


1
おそらく、文字列を圧縮できますか?
mbomb007

1
驚いたことに、アルゴリズムによるアプローチを使用するPythonの(提出されていない)ソリューションよりもまだ短いです。
pawel.boczarski

2

CJam、49バイト

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*

上記は16進ダンプxxd -r -c 17 -g 1です。これはで反転できます。

CJamインタープリターでオンラインで試してください。

使い方

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

Javaが勝てないことは知っていますが、とにかく努力したいです。

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

コマンドラインから入力を受け取り、コンソールに出力します。ゴルフされていないバージョン:

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

0〜3をNW(またはWが関係する場合はNに4)を割り当てることで機能します。4つの異なる状況を認識します。

  • parse1は1文字のポイント用で、値を返すだけです。
  • parse2は2文字のポイント用で、2ポイントの値を平均します。
  • parse3はトリプルレターポイント用で、ダブルポイントとシングルポイントの平均を取ります。
  • parse3b4は、「b」が含まれるすべてのオブジェクト用で、「b」の前のポイントの値を計算し、「b」の後のポイントの「方向」に基づいて1/8を加算または減算します。

print()では、値に90を掛けて実際の角度を取得します。


書く必要がありますC c=new C(r[0]);か?たぶんnew C(r[0]);十分ですか?
pawel.boczarski

1

Python 3、149バイト

再帰的なアルゴリズムのアプローチを試みました。四分の一風は私が最初に思ったよりも扱いにくいため、この解決策は比較的長くなりました。

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

ゴルフをしていない:

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

ゴルフバージョンは10を掛ける必要がある小数を返します(代わりにをf("NbW")返します)34.875348.75
智障的人

@viktorahlström、よろしいですか?正しい値が返されます。コードをコピーして貼り付けるときに最後のゼロを逃したかもしれませんか?
エミール

ああ、申し訳ありませんが、明らかにそうでした-私の間違い、ごめんなさい!
智障的人

1

Haskell、206バイト

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

便利なテスト:

*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

ジュリア、151 147 142バイト

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

少し自由:

# 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

コード化されていないコードでは、2つのベクトルの平均をカウントavg = e ^ {jArg(v_1 + v_2)}して、ベクトルを正規化したままにします。ただし、最初のベクトルの伸長による誤差はまだ再帰に追加されていないため、ゴルフ中に正規化ステップは削除され、計算は平均= v_1 + v_2簡単に進みます。完全な円の1/64未満のエラーは、丸めにより除外されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.