Convertir un point de la boussole en degrés


18

J'ai trouvé ce défi indépendamment, mais il s'avère être l'inverse de ce défi de Doorknob . Comme j'aime vraiment ses spécifications, j'ai décidé d'en voler de grandes parties au lieu de préparer mes propres explications.

Le défi

Étant donné l'abréviation de l'un des 32 points de la boussole, imprimez les degrés correspondants. N'hésitez pas à passer au tableau ci-dessous si vous n'êtes pas intéressé par une explication des 32 points.

Voici la boussole complète:

image

Par Denelson83 (Travail personnel) [ GFDL ou CC-BY-SA-3.0 ], via Wikimedia Commons

Chaque direction est plus éloignée de 11,25 (360/32) que la précédente. Par exemple, N (nord) est de 0 degré, NbE (nord par est) est de 11,25 degrés, NNE (nord-nord-est) est de 22,5 degrés, etc.

En détail, les noms sont attribués comme suit:

  • 0 degré est N, 90 degrés E, 180 degrés S et 270 degrés W. Ces valeurs sont appelées directions cardinales.
  • Les points à mi-chemin entre les directions cardinales sont simplement les directions cardinales entre lesquelles ils sont concaténés. N ou S vont toujours en premier et W ou E sont toujours en deuxième position. Celles-ci sont appelées directions ordinales. Les directions ordinales et cardinales forment ensemble les vents principaux.
  • Les points à mi-chemin entre les vents principaux sont les directions entre lesquelles ils sont concaténés. Les directions cardinales vont en premier, les secondes ordinales. C'est ce qu'on appelle des demi-vents.
  • Les points à mi-chemin entre les vents principaux et les demi-vents sont le vent principal adjacent "par" la direction cardinale la plus proche du vent principal. Ceci est indiqué par un b. Ce sont les quarts de vents.

Il en résulte le graphique suivant:

#   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

Voici un tableau plus détaillé et éventuellement une meilleure explication des points cardinaux.

Votre tâche consiste à prendre en entrée l'une des 32 abréviations de la troisième colonne et à afficher les degrés correspondants dans la deuxième colonne.

Vous pouvez supposer que l'entrée sera toujours exactement l'une de ces 32 chaînes (et vous pouvez éventuellement mais systématiquement vous attendre à une seule nouvelle ligne de fin). La sortie doit également être donnée exactement comme indiqué ci-dessus, bien que les zéros de fin soient autorisés. Vous pouvez éventuellement générer une seule nouvelle ligne de fin.

Vous pouvez écrire un programme ou une fonction, en prenant une entrée via STDIN (ou l'alternative la plus proche), un argument de ligne de commande ou un argument de fonction et en sortant le résultat via STDOUT (ou l'alternative la plus proche), la valeur de retour de la fonction ou le paramètre de la fonction (out).

Il s'agit du code golf, donc la réponse la plus courte (en octets) l'emporte.

Réponses:


2

Pyth, 47 octets

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

Hexdump, en raison de caractères non imprimables:

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

Harnais de test

En raison d'un bogue dans le compilateur de ligne de commande officiel, ce code ne fonctionne que via le compilateur en ligne, lié ci-dessus, ou l' -cindicateur du compilateur hors ligne. (Le bug a été corrigé après la question.)

Cette solution est très similaire à la réponse CJam de @ Dennis, utilisant le processus de hachage de l'entrée, la recherche du résultat dans une chaîne de recherche de 32 octets, puis la multiplication par 11,25.

La fonction de hachage que j'utilise convertit l'entrée en une chaîne comme s'il s'agissait d'un entier de base 256 avec C, en prenant le résultat modulo Cde ½, qui est 189, mais enregistre un octet en raison d'une analyse supérieure et la reconvertit en chaîne avec à Cnouveau .

La multiplication par 11,25 est accomplie en multipliant par 45, puis en divisant par 4, ce qui économise un octet.


9

Rubis, 118 106

Merci à Martin Büttner pour 12 octets enregistrés.

Il s'agit actuellement de la même longueur, qu'il s'agisse d'une fonction ou d'un programme.

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

programme

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

Il s'agit d'une promenade cartésienne à travers les points. Les caractères NSEWajoutent ou soustraient 4 des coordonnées x et y stockées dans d[]. Après avoir rencontré un b(ou tout autre symbole que NSEW), il est réduit à 1.

Les données x et y sont ensuite traitées comme un nombre complexe pour extraire l'argument angulaire. Ceci est multiplié par 16 / PI = 5.1. Bien qu'il y ait quelques erreurs géométriques dans l'approche, l'arrondi de cet angle est suffisant pour donner le nombre correct -15..+16. Modulo est utilisé pour corriger cela 0..31(en Ruby %renvoie toujours positif.) Enfin, le résultat est multiplié par 11,25.


1
Quelle bonne idée d'arrondir! Vous obtenez l'arctan de l'angle au lieu de l'angle, pris par rapport à la direction orthogonale la plus proche, mais cela s'avère assez proche.
xnor

@xnor sans l'arrondi, je reçois NbE 14.05 (+2.8), NNE 26.60 (+4.1), NEbE 51.41 (-4.84), donc j'avais une certaine latitude avec les valeurs de nmais j'ai dû les choisir avec soin.
Level River St

6

Javascript (ES6), 153 octets

Je voulais juste lancer le bal avec un simple.

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

Pas particulièrement innovant, mais cela fonctionne, et il y a peut-être quelques conseils qui pourraient en découler. Ne vous inquiétez pas, je penserai à une autre technique (si tout va bien meilleure).


1
Peut-être pouvez-vous compresser la chaîne?
mbomb007

1
Étonnamment, elle est toujours plus courte que ma solution (non soumise) en Python, qui utilise une approche algorithmique.
pawel.boczarski

2

CJam, 49 octets

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*

Ce qui précède est un hexdump, qui peut être inversé avec xxd -r -c 17 -g 1.

Essayez-le en ligne dans l' interpréteur CJam .

Comment ça fonctionne

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 (caractères)

Je sais que Java ne peut pas gagner mais j'aime quand même faire l'effort.

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

Il prend les entrées de la ligne de commande et les sorties vers la console. Version non golfée:

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

Il fonctionne en attribuant 0-3 à NW (ou 4 pour N si W est impliqué). Il reconnaît 4 situations différentes:

  • parse1 est pour les points d'une seule lettre, il renvoie simplement la valeur.
  • parse2 est pour les points à deux lettres, il fait la moyenne des valeurs des 2 points.
  • parse3 est pour les points à trois lettres, il prend la moyenne de la moyenne des points doubles et simples.
  • parse3b4 est pour tous ceux qui contiennent un «b», il calcule la valeur du point avant le «b» et ajoute ou soustrait 1/8 en fonction de la «direction» du point après le «b».

Dans print (), la valeur est multipliée par 90 pour obtenir l'angle réel.


Faut-il écrire C c=new C(r[0]);? Peut new C(r[0]);- être est-ce suffisant?
pawel.boczarski

1

Python 3, 149 octets

J'ai essayé une approche algorithmique récursive. Les quarts de vent étaient plus difficiles à gérer que je ne le pensais au début, donc cette solution s'est développée relativement longtemps.

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

Non golfé:

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

La version golfée renvoie une décimale qui doit être multipliée par 10 ( f("NbW")renvoie 34.875au lieu de 348.75)
智障 的 人

@ viktorahlström, êtes-vous sûr? Il renvoie la valeur correcte pour moi. Peut-être avez-vous manqué le dernier zéro lors de la copie et du collage du code?
Emil

Oh, désolé, apparemment c'était ça - mon erreur, désolé!
智障 的 人

1

Haskell, 206 octets

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

Test pratique:

*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 octets

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

Un peu non golfé:

# 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

Dans le code non golfé, je compte la moyenne de deux vecteurs comme avg = e ^ {jArg (v_1 + v_2)}pour que le vecteur soit toujours normalisé. Cependant, les erreurs dues à l'allongement du premier vecteur ne s'accumulent pas encore avec si peu d'additions dans notre récursivité, donc pendant le golf, l'étape de normalisation a été supprimée et le calcul se fait moyenne = v_1 + v_2simplement. Les erreurs inférieures à 1/64 du cercle complet sont filtrées par arrondi.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.