Перевести точку компаса в градусы

18

Я придумал этот вызов самостоятельно, но он оказался обратным этому вызову от Doorknob . Поскольку мне действительно нравятся его характеристики, я решил украсть его большую часть вместо того, чтобы готовить свои собственные объяснения.

Соревнование

Учитывая сокращение одной из 32 точек на компасе, выведите соответствующие градусы. Не стесняйтесь переходить к таблице ниже, если вы не заинтересованы в объяснении 32 пунктов.

Вот полный компас:

образ

По Denelson83 (собственная работа) [ GFDL или CC-BY-SA-3.0 ], через Wikimedia Commons

Каждое направление на 11,25 (360/32) градуса дальше предыдущего. Например, N (север) составляет 0 градусов, NbE (север на восток) составляет 11,25 градуса, NNE (север-северо-восток) составляет 22,5 градуса и т. Д.

Подробно имена присваиваются следующим образом:

  • 0 градусов - это N, 90 градусов - это E, 180 градусов - это S, а 270 градусов - это W. Это так называемые основные направления.
  • Точки на полпути между кардинальными направлениями - это просто кардинальные направления между ними. N или S всегда идут первыми, а W или E всегда вторыми. Они называются порядковыми направлениями. Порядковый и кардинальный направления вместе образуют главные ветры.
  • Точки на полпути между основными ветрами - это направления, между которыми они соединены. Кардинальные направления идут первыми, порядковые вторыми. Они называются полу ветрами.
  • Точки на полпути между основным и половинным ветрами являются смежным основным ветром «по» ближайшему кардинальному направлению от основного ветра. Это обозначено как 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

Вот более подробный график и, возможно, лучшее объяснение точек компаса.

Ваша задача - взять в качестве входных данных одну из 32 аббревиатур из третьего столбца и вывести соответствующие градусы во второй столбец.

Вы можете предположить, что input всегда будет точно одной из этих 32 строк (и вы можете опционально, но последовательно ожидать единственного завершающего перевода строки). Вывод также должен быть дан точно так, как указано выше, хотя допускаются конечные нули. При желании вы можете вывести один завершающий символ новой строки.

Вы можете написать программу или функцию, принимая ввод через 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флаг автономного компилятора. (Ошибка была исправлена ​​после того, как вопрос был задан.)

Это решение очень похоже на ответ CJam @ Dennis, использующий процесс хеширования ввода, поиска результата в 32-байтовой строке поиска и последующего умножения на 11,25.

Использование хэш - функции я преобразовывает входные данные в строку , как если бы это была база 256 целое число с C, принимая результат по модулю Cиз ½, который является 189, но сохраняет байт из - за превосходного синтаксического анализа, и преобразования его обратно в строку с Cвновь ,

Умножение на 11,25 достигается путем умножения на 45, а затем деления на 4, что позволяет сэкономить байт.

isaacg
источник
9

Руби, 118 106

Спасибо Мартину Бюттнеру за 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добавляют или вычитают 4 из координат x и y, хранящихся в d[]. После того как b(или любой другой символ, кроме NSEW) встречается, это уменьшается до 1.

Данные x и y затем обрабатываются как комплексное число для извлечения углового аргумента. Это умножается на 16 / PI = 5.1. Хотя в подходе есть некоторые геометрические ошибки, округления этого угла достаточно, чтобы получить правильное число -15..+16. Для исправления этого используется модуль 0..31(в Ruby %всегда возвращается положительное значение). Наконец, результат умножается на 11.25.

Уровень реки St
источник
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

Не особенно инновационный, но он работает, и, возможно, есть некоторые советы, которые можно извлечь из него. Не волнуйтесь, я подумаю о другой (надеюсь, лучше) технике.

ETHproductions
источник
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*

Выше это hexdump, который можно изменить с помощью 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

Ява, 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 (или 4 для N, если используется W). Он распознает 4 разные ситуации:

  • parse1 для однобуквенных точек, он просто возвращает значение.
  • parse2 для двухбуквенных точек, он усредняет значения 2 точек.
  • parse3 для тройных буквенных знаков, он принимает среднее значение двойных и единичных точек.
  • parse3b4 предназначен для всех тех, у кого есть «b», он вычисляет значение точки перед «b» и добавляет или вычитает 1/8 на основе «направления» точки после «b».

В 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

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
Эмиль
источник
Гольф-версия возвращает десятичное число, которое нужно умножить на 10 ( f("NbW")возвращается 34.875вместо 348.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()
blabb
источник
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

В некоголенном коде я подсчитываю среднее значение двух векторов avg = e ^ {jArg (v_1 + v_2)}, чтобы вектор оставался нормализованным. Однако ошибки из-за удлинения первого вектора еще не накапливаются с таким небольшим количеством добавлений в нашей рекурсии, поэтому во время игры в гольф шаг нормализации был удален, и вычисление идет avg = v_1 + v_2просто. Ошибки менее 1/64 полного круга отфильтровываются путем округления.

pawel.boczarski
источник