Converter um ponto da bússola em graus

18

Eu vim com esse desafio de forma independente, mas acaba sendo o inverso a esse desafio da Maçaneta da porta . Como eu realmente gosto das especificações dele, decidi roubá-las em vez de inventar minhas próprias explicações.

O desafio

Dada a abreviação de um dos 32 pontos na bússola, imprima os graus correspondentes. Sinta-se à vontade para pular a tabela abaixo se não estiver interessado em obter uma explicação dos 32 pontos.

Aqui está a bússola completa:

imagem

Por Denelson83 (Trabalho próprio) [ GFDL ou CC-BY-SA-3.0 ], via Wikimedia Commons

Cada direção tem 11,25 (360/32) graus a mais que a anterior. Por exemplo, N (norte) é 0 graus, NbE (norte a leste) é 11,25 graus, NNE (norte-nordeste) é 22,5 graus, etc.

Em detalhes, os nomes são atribuídos da seguinte forma:

  • 0 graus é N, 90 graus é E, 180 graus é S e 270 graus é W. Essas são chamadas direções cardinais.
  • Os pontos intermediários entre as direções cardeais são simplesmente as direções cardinais entre as concatenadas. N ou S sempre vão primeiro e W ou E sempre são os segundos. Essas são chamadas direções ordinais. As direções ordinal e cardinal juntas formam os ventos principais.
  • Os pontos intermediários entre os ventos principais são as direções entre as quais são concatenadas. As direções cardeais vão primeiro, segundo ordinal. Estes são chamados de meio vento.
  • Os pontos intermediários entre o vento principal e o meio vento são o vento principal adjacente "por" a direção cardinal mais próxima do vento principal. Isso é indicado com a b. Estes são chamados quartos de vento.

Isso resulta no seguinte gráfico:

#   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

Aqui está um gráfico mais detalhado e, possivelmente, uma melhor explicação dos pontos da bússola.

Sua tarefa é tomar como entrada uma das 32 abreviações da terceira coluna e gerar os graus correspondentes na segunda coluna.

Você pode presumir que a entrada sempre será exatamente uma dessas 32 strings (e, opcionalmente, mas de maneira consistente, poderá esperar uma única nova linha à direita). A saída também deve ser fornecida exatamente como listado acima, embora os zeros à direita sejam permitidos. Opcionalmente, você pode gerar uma única nova linha à direita.

Você pode escrever um programa ou função, recebendo entrada via STDIN (ou alternativa mais próxima), argumento da linha de comando ou argumento da função e emitindo o resultado via STDOUT (ou alternativa mais próxima), valor de retorno da função ou parâmetro da função (saída).

Isso é código de golfe, então a resposta mais curta (em bytes) vence.

Martin Ender
fonte

Respostas:

2

Pitão, 47 bytes

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

Hexdump, devido a caracteres não imprimíveis:

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

Equipamento de teste

Devido a um erro no compilador de linha de comando oficial, esse código funciona apenas através do compilador online, vinculado acima, ou do -csinalizador do compilador offline. (O bug foi corrigido depois que a pergunta foi feita.)

Essa solução é muito semelhante à resposta CJam de @ Dennis, usando o processo de hash da entrada, procurando o resultado em uma cadeia de pesquisa de 32 bytes e multiplicando por 11,25.

A função hash que eu uso está convertendo a entrada em uma string como se fosse um inteiro 256 básico com C , pegando o módulo Cde resultado de ½, que é 189, mas salva um byte devido à análise superior e convertendo-a novamente em uma string com Cnovamente .

A multiplicação por 11,25 é conseguida multiplicando por 45 e depois dividindo por 4, o que economiza um byte.

isaacg
fonte
9

Rubi, 118 106

Obrigado a Martin Büttner por 12 bytes salvos.

Atualmente, este é o mesmo comprimento, independentemente de ser uma função ou um programa.

função 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}

programa

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

Esta é uma caminhada cartesiana pelos pontos. Os caracteres NSEWadicionam ou subtraem 4 das coordenadas x e y armazenadas em d[]. Após um b(ou qualquer símbolo diferente deNSEW ) for encontrado, ele será reduzido para 1.

Os dados xey são então tratados como um número complexo para extrair o argumento angular. Isso é multiplicado por 16 / PI = 5.1. Embora haja alguns erros geométricos na abordagem, arredondar esse ângulo é suficiente para fornecer o número correto -15..+16. O módulo é usado para corrigir isso 0..31(no Ruby %sempre retorna positivo). Finalmente, o resultado é multiplicado por 11,25.

Level River St
fonte
1
Que idéia inteligente de arredondamento! Você obtém o arcano do ângulo em vez do ângulo, tirado em relação à direção ortogonal mais próxima, mas isso fica próximo o suficiente.
Xnor
@xnor sem o arredondamento, recebo NbE 14.05 (+2.8), NNE 26.60 (+4.1), NEbE 51.41 (-4.84), então tive uma margem de manobra com os valores de, nmas tive que escolhê-los com cuidado.
Level River St
6

Javascript (ES6), 153 bytes

Só queria fazer a bola rolar com uma simples.

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

Não é particularmente inovador, mas funciona, e talvez haja algumas dicas que possam ser derivadas disso. Não se preocupe, pensarei em outra técnica (espero que melhor).

ETHproductions
fonte
1
Talvez você possa comprimir a string?
mbomb007
1
Surpreendentemente, ainda é mais curto que minha solução (não enviada) em Python, que usa abordagem algorítmica.
pawel.boczarski
2

CJam, 49 bytes

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*

O acima é um hexdump, que pode ser revertido com xxd -r -c 17 -g 1.

Experimente on-line no intérprete CJam .

Como funciona

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.
Dennis
fonte
1

Java, 653 (caracteres)

Eu sei que o Java não pode vencer, mas eu gosto de fazer o esforço de qualquer maneira.

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

Ele recebe entrada da linha de comando e produz para o console. Versão não destruída:

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

Ele funciona atribuindo 0-3 a NW (ou 4 para N se W estiver envolvido). Reconhece 4 situações diferentes:

  • parse1 é para pontos de letra única, apenas retorna o valor.
  • parse2 é para pontos com duas letras, calcula a média dos valores dos 2 pontos.
  • parse3 é para pontos triplos de letras, leva a média da média dos pontos duplos e simples.
  • parse3b4 é para todos os que possuem um 'b', calcula o valor do ponto antes do 'b' e adiciona ou subtrai 1/8 com base na 'direção' do ponto após o 'b'.

Em print (), o valor é multiplicado por 90 para obter o ângulo real.

Harry Blargle
fonte
É necessário escrever C c=new C(r[0]);? Talvez new C(r[0]);seja suficiente?
pawel.boczarski
1

Python 3, 149 bytes

Eu tentei uma abordagem algorítmica recursiva. Os ventos fracos eram mais difíceis de lidar do que eu pensava a princípio, então essa solução cresceu relativamente longa.

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
Emil
fonte
A versão golfed retorna um decimal que precisa ser multiplicado por 10 ( f("NbW")retorna em 34.875vez de 348.75) #
21815
@ viktorahlström, você tem certeza? Retorna o valor correto para mim. Talvez você tenha perdido o último zero ao copiar e colar o código?
Emil
Oh, desculpe, aparentemente foi isso - meu erro, desculpe!
智障 的 人
1

Haskell, 206 bytes

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

Teste conveniente:

*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]
Leif Willerts
fonte
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
fonte
0

Julia, 151 147 142 bytes

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

Um pouco destroçado:

# 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

No código não-contado, conto a média de dois vetores média = e ^ {jArg (v_1 + v_2)}para que o vetor ainda seja normalizado. No entanto, os erros devido ao alongamento do primeiro vetor ainda não estão se acumulando com tão poucas adições em nossa recursão; portanto, durante o golfe, a etapa de normalização foi removida e o cálculo é média = v_1 + v_2simples. Erros menores que 1/64 do círculo completo são filtrados por arredondamento.

pawel.boczarski
fonte