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


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 абревіатур з третього стовпця і вивести відповідні ступені у другому стовпчику.

Ви можете припустити, що введення завжди буде точно одним з цих 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 @ Денніса, використовуючи процес хешування вводу, пошук результату в рядку пошуку 32 байти, а потім множення на 11,25.

Використання хеш - функції я перетворює вхідні дані в рядок , як якщо б це була база 256 ціле число з C, приймаючи результат по модулю Cз ½, який є 189, але зберігає байт з - за чудової синтаксичного аналізу, і перетворення його назад в рядок з Cзнову .

Множення на 11,25 здійснюється множенням на 45, потім діленням на 4, що зберігає байт.


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(у Рубі %завжди повертається позитивним.) Нарешті результат множиться на 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*

Вищенаведене - це шістнадцятковий засіб, з яким можна повернути назад 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 (або 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

Безголівки:

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

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 повного кола відфільтровуються шляхом округлення.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.