Nord par Nord par Nord par Sud Est

30

Étant donné une chaîne de N, S, E et W, affichez un relèvement (angle dans le sens horaire à partir du nord en degrés), corrigez à 5 décimales.

En notation boussole traditionnelle , une chaîne est composée de seulement 2 de ces caractères (comme NNW ou ESE). Ici, vous devez également accepter les chaînes qui contiennent les 4 (comme WNNNSE) . L'utilisation de seulement 2 symboles permet aux humains de comprendre intuitivement la signification. Permettre 4 symboles le rend horrible à lire, mais permet des manières plus courtes de décrire un relèvement avec une précision donnée.

(Comme indiqué dans les commentaires de user2357112 , il s'avère que vous pouvez prouver que pour un roulement donné, la chaîne de 4 symboles aura exactement la même longueur que la chaîne de 2 symboles, j'ai donc basé ce défi sur une fausse hypothèse. Espérons que ce manque d'objectif pratique ne nuise pas à votre plaisir de relever le défi ...)

La méthode exacte est décrite ci-dessous et est équivalente à la notation traditionnelle (elle se développe sur elle plutôt que de la changer).

Contribution

  • L'entrée est une chaîne unique contenant uniquement les caractères NESW.
  • L'entrée peut être une séquence de caractères si vous préférez, à condition que cela n'inclue aucun prétraitement. Par exemple, la prise d'une liste imbriquée [N, [E, [S, [W]]]]pour faciliter l'ordre de traitement n'est pas autorisée.
  • Il n'est pas permis de prendre des personnages différents. Vous ne pouvez pas prendre une chaîne de 1234au lieu de NESW.

Sortie

  • La sortie doit être un nombre décimal ou une représentation sous forme de chaîne de un (pas une ration / fraction).
  • Les zéros de fin n'ont pas besoin d'être affichés. Si le relèvement est 9.00000, la sortie 9compte également comme correcte jusqu'à 5 décimales.
  • La sortie est dans la plage [0, 360). C'est-à-dire, y compris 0 mais à l'exclusion de 360.
  • L'exactitude est vérifiée en arrondissant la sortie à 5 décimales. Si le relèvement est de 0,000005, il arrondit à 0,00001. Les sorties 0.00001 et 0.000005 sont toutes les deux correctes.
  • La sortie en notation scientifique pour certaines entrées est acceptable. Par exemple, 1e-5au lieu de 0.00001.

Conversion

  • Les points du caractère unique N, E, S, et Wcorrespondent à 0, 90, 180 et 270 degrés respectivement.
  • Si vous ajoutez un de ces éléments à une chaîne, le relèvement divise le relèvement du caractère unique et le relèvement de la chaîne d'origine.
  • Le plus proche des deux paliers bissecteurs possibles est choisi, de sorte que NE représente 45 degrés, et non 225 degrés.
  • Ceci est sans ambiguïté sauf lorsque l'angle à bissecter est de 180 degrés. Par conséquent NS, SN, WEet EWcorrespondent à des paliers non défini, et l'entrée ne sera jamais fin dans l' un de ces. Ils peuvent cependant apparaître n'importe où ailleurs dans la chaîne d'entrée, car cela ne crée aucune ambiguïté.
  • Si les deux derniers caractères sont identiques, le caractère final sera redondant car la bissection retournera le même relèvement. Comme cela n'ajoute rien à la notation, votre code n'a pas besoin de gérer cela. Par conséquent NN, EE, SSet WWcorrespondent à des paliers non défini, et l'entrée ne sera jamais fin dans l' un de ces. Ils peuvent cependant apparaître n'importe où ailleurs dans la chaîne d'entrée.

Exemples

N: 0
E: 90
S: 180
SE: halfway between S and E: 135
NSE: halfway between N and SE: 67.5
NNSE: halfway between N and NSE: 33.75
NNNSE: halfway between N and NNSE: 16.875
NNNNSE: halfway between N and NNNSE: 8.4375

Cas de test

Une soumission n'est valide que si elle donne une sortie correcte pour tous les cas de test. Notez que les cas de test repoussent les limites de ce qui peut être traité avec une double précision. Pour les langues par défaut à simple précision, vous devrez probablement dépenser les octets pour spécifier la double précision afin d'obtenir des sorties correctes.

Les sorties des cas de test sont représentées arrondies à 5 décimales et avec une précision arbitraire. Les deux sont des sorties valides.

WNE 337.5 337.5
WEN 337.5 337.5
WEWEWEWEWEWEWEWEWEWEWEN 330.00001 330.000007152557373046875
NESWNESWNESWNESWNESWNESWNESW 90 89.99999932944774627685546875
NNNNNNNNNNNNNNNNNNNNNNNE 0.00001 0.0000107288360595703125
NNNNNNNNNNNNNNNNNNNNNNNW 359.99999 359.9999892711639404296875
SNNNNNNNNNNNNNNNNNNNNNNNE 90.00001 90.00000536441802978515625
SNNNNNNNNNNNNNNNNNNNNNNNW 269.99999 269.99999463558197021484375

Notation

C'est du . Le score est la longueur du code source en octets, et le gain le plus court.


Pédantisme

J'ai fait l'erreur de penser que «North by North West» était une direction de boussole valide. Une erreur heureuse, car elle a conduit à une idée de défi, mais j'ai découvert à partir de la page Wikipedia :

"Le titre du film d'Alfred Hitchcock 1959, North by Northwest, n'est en fait pas un point de direction sur la boussole à 32 vents, mais le le film contient une référence à Northwest Airlines. "

Il s'avère également que la méthode utilisée pour ce défi est cohérente uniquement avec les points cardinaux traditionnels jusqu'au compas 16 points inclus. La boussole à 32 vents décrite sur cette page est subtilement différente et j'ai commodément ignoré son existence pour ce défi.

Enfin, pour tous ceux qui pensent que je devrais utiliser "Sud-Est" au lieu de "Sud-Est",.

trichoplax
la source
WNNNSE<= quelle serait la sortie de cet exemple d'entrée au début de votre message? cela me semble invalide, mais c'est difficile à dire.
Tensibai
@Tensibai Pour l'entrée, WNNNSEla sortie serait 323.4375. Consultez l'exemple de section pour une procédure pas à pas qui s'appliquerait de la même manière à ce cas.
trichoplax
L'entrée est-elle f(N,N,N,S,E)correcte?
Karl Napf
@KarlNapf J'ai développé la section d'entrée pour clarifier. Si je comprends bien, votre exemple d'entrée avec plusieurs arguments semble équivalent à une séquence de caractères, ce serait donc acceptable.
trichoplax
2
"Permettre 4 symboles le rend horrible à lire, mais permet des manières plus courtes de décrire un relèvement avec une précision donnée." - êtes-vous sûr de cela? Il semble que toutes les entrées qui décrivent le même relèvement ont la même longueur, car si vous attribuez à chaque relèvement un rationnel dyadique de 0 à 1, une chaîne de longueur N avec N> 1 correspond toujours à un rationnel dyadique avec le dénominateur 2 ^ (N +1) en termes les plus bas. En outre, autoriser plus de 2 lettres distinctes dans un roulement n'ajoute aucun pouvoir expressif; tout relèvement exprimé avec 3 ou 4 lettres peut être exprimé avec 2.
user2357112 prend en charge Monica

Réponses:

13

JavaScript (ES6), 84 80 78 74 72 octets

Un octet enregistré grâce à @Titus, 1 grâce à @Neil

f=([c,...s],b="NESW".search(c))=>b*90-(s[0]?(b-=f(s)/90)-4*(b*b>4):0)*45

Cela a pris du temps, mais je pense que j'ai enfin perfectionné la formule ...

Extrait de test

Explication

Commençons par le cas le plus simple: une chaîne à un seul caractère. Le résultat est simplement sa position (indexée 0) dans la chaîneNESW , multipliée par 90.

Pour une chaîne de deux caractères, le résultat se situe à mi-chemin entre le résultat du premier caractère et le résultat du second. Cependant, il y a un hic: si la différence absolue entre les deux est supérieure à 180 (par exempleNW ou WN), nous devons 180 à l'angle afin qu'il ne pointe pas dans la direction opposée.

Pour toute chaîne plus longue, le résultat se situe à mi-chemin entre le résultat du premier caractère et le résultat du reste de la chaîne. Cela peut être généralisé de la manière suivante:

  • Si l'entrée est un seul caractère, retourne son index dans la chaîne NESW fois 90.
  • Sinon, retournez l'index du premier caractère dans la chaîne NESWfois 45, plus la moitié du résultat du reste de la chaîne; ajoutez 180 supplémentaires si la différence absolue entre les deux est supérieure à 90.
ETHproductions
la source
Excellent moyen de couper le premier caractère de la chaîne! Vous pouvez enregistrer un octet si vous calculez avec des valeurs divisées par 45.
Titus
@Titus Je peux économiser 2 octets avec cette technique, merci!
ETHproductions
1
searchau lieu de vous indexOffaire économiser un octet.
Neil
@Neil Merci encore! J'ai réussi à en jouer trois de plus en réorganisant complètement l'équation.
ETHproductions
10

C # 6, 226 217 207 185 octets

using System.Linq;double N(string s){double b=f(s.Last());foreach(var c in s.Reverse()){b=(b+f(c)+(b-f(c)>2?4:f(c)-b>2?-4:0))/2;b=(b+4)%4;}return b*90;}int f(char x)=>"NESW".IndexOf(x);

Edit: -10 octets par idée "d'emprunt" de la soumission d'ETHproductions
-22 octets grâce à @Titus

Non golfé

// Call this method
double N(string s){
    // Initialize bearing with last direction
    double b=f(s.Last());
    // Do backward. Doing last direction once more doesn't impact result
    foreach(var c in s.Reverse()){
        // Average current bearing with new bearing, adjusted with wrapping
        b=(b+f(c)+(b-f(c)>2?4:f(c)-b>2?-4:0))/2;
        // Make bearing back to range [0,4)
        b=(b+4)%4;
    }
    // Change from "full circle = 4" unit to degree
    return b*90;
}
// helper method to convert direction to bearing. This returns bearing with full circle = 4.
int f(char x)=>"NESW".IndexOf(x);
Link Ng
la source
Je pense que vous pouvez raccourcir l'ajustement de votre plage à [0,360) en utilisant%
trichoplax
@trichoplax Cela ne coupera-t-il pas les décimales?
Titus
1
Économisez 10 octets avec b=(b+360)%360;au lieu de b+=b>360?-360:b<0?360:0;. Économisez encore 12 octets en divisant tout par 90 et return b*90;.
Titus
1
Voici 10 octets supplémentaires: fusionnez les deux affectations et supprimez les accolades: b=(b+f(c)+(b-f(c)>2?4:f(c)-b>2?-4:0)+8)/2%4;puis distribuez-les +8aux résultats ternairesb=(b+f(c)+(b-f(c)>2?12:f(c)-b>2?4:8))/2%4;
Titus
8

PHP, 95 88 86 100 127 104 101 octets

  • -7 octets avec l'opérateur de coalescence nul
  • -2 octets en ne remplaçant pas N(et plus, car cela permet de mettre la traduction à la tête de boucle: Nest vrai, mais évalue à 0dans le calcul.)
  • +41 octets pour fixer la bissection ( toux )
  • -7 octets directement et -16 indirectement inspirés du code @ ETHproductions
  • -3 octets en remplaçant strtrpar un de mes jonglages

for($i=strlen($s=$argv[1]);$i--;$p=($q+$p=$p??$q)/2+2*(abs($q-$p)>2))$q=ord($s[$i])/.8+3&3;echo$p*90;

C'est officiellement la première fois que j'utilise l'opérateur de coalescence nulle. Courez avec -r.

PHP 7.1

Les décalages de chaîne négatifs dans la prochaine version PHP économiseront 12 octets:
Remplacez strlen($s=$argv[1])par 0et $spar $argv[1].


Octets gratuits pour (presque) tout le monde:

  • Calculer avec 0,1,2,3 au lieu de 0,90,180,270 et multiplier le résultat final par 90 économisera deux octets et permettra probablement de continuer à jouer au golf.
  • Il y a quelques modèles dans les codes ASCII des caractères. Essayez l'un d'entre eux dans votre langue:
    • (a/2%6+2)%5
    • a<87?a/2&3^3:3 ou a/2&3^3*(a<87)
    • a&1?a&2|a/4&1:0
    • a/.8-1&3
Titus
la source
5

Python 3, 133 113 octets

Je viens d'améliorer la réponse de @ L3viathan parce que je viens de créer ce compte et que je ne peux donc pas encore faire de commentaires.

d={"N":0,"E":.5,"S":1,"W":1.5}
def B(s):
 b=d[s[-1]]
 for c in s[::-1]:b=(b+d[c])/2+(abs(b-d[c])>1)
 return b*180
Moonocababa
la source
Bienvenue sur Programming Puzzles & Code Golf, et belle amélioration ...
trichoplax
Je n'ai pas vu votre réponse, mais Titus a eu une idée similaire, et j'en ai eu une autre, je suis à 98 maintenant :)
L3viathan
5

05AB1E ,48 42 37 32 octets

6 octets enregistrés grâce à Emigna. 5 octets enregistrés grâce à l'idée de Titus de travailler sur la plage [0,4 [et de multiplier par 90 à la fin. 5 octets enregistrés grâce à la maîtrise d'Adnan de l'ancienne métamorphose xor / modulo.

Ainsi, chaque angle est réduit de la plage [0,360 [à la plage [0,4 [tout au long de l'exécution. Le résultat est ensuite multiplié par 90 et affiché.

Ç30^5%R¬U¦vXy+;DX-Ä0›2*+4%U}X90*

It can be divided into two sequentially called subprograms.
First program: convert input string into an array of the corresponding angles in range [0,4[
Ç      Take the ascii value of all input characters
 30^5% Dark ascii manipulation that yields [0,1,2,3] for [N,E,S,W]

Now we have an array of integers in range [0,4[.

Second program: actually compute the final angle
R                          Reverse the array
 ¬                         Take the first value (the last of the non-reversed array)
  U                        Pop it from the stack and set X to the same value
   ¦                       Strip the first element
    v                      For each remaining element
     Xy+;                  Compute the average value between the leftmost value and X
         DX-Ä0›            Push 1 if angular distance cast to integer is > 0 (i.e. if it is >= 1), 0 otherwise. It's equivalent to checking >= 90 degrees
               2*+         Multiply by 2 (=2 if angular distance is >= 1 and 0 otherwise) and add it to the formerly computed average value. It's equivalent to multiplying by 180
                  4%       Perform mod 4. It's equivalent to performing mod 360
                    U      Store the result back to X
                     }     End for, mandatory if input has only one character
                      X90* Push X*90 and implicitly display it

Essayez-le en ligne!

Axes potentiels du golf:

  • Je ne sais pas si ce mod 4 est requis (cela économiserait 2 octets). Tous les cas de test fonctionnent sans lui, mais il existe peut-être un cas délicat. Une preuve mathématique pour le valider ou l'annuler serait de premier ordre.
  • Il n'y a aucun élément implicite à part l'affichage du résultat (guillemets fermants, crochets fermants).
Osable
la source
1
Ne semble pas donner le résultat demandé sur les cas de test NNNNNNNNNNNNNNNNNNNNNNNEet SNNNNNNNNNNNNNNNNNNNNNNNE.
Emigna
2
Bizarre. Maintenant je le fais aussi. Je dois avoir mal collé ou quelque chose, désolé. Vous pouvez raccourcir le code jusqu'à v"NESW"yk90*})R¬U¦vXy+;DX-Ä89›180*+360%U}X.
Emigna
1
Grande explication! Il pourrait être utile d'inclure une note qui 89›signifie en fait que la partie entière est supérieure à 89, ce qui équivaut à dire que le nombre complet est supérieur ou égal à 90 (ce qui fonctionne toujours bien car exactement 90 ne devrait jamais se produire). Actuellement, le commentaire dans le code expliqué donne l'impression qu'il vérifie plus de 89, alors que votre code passe les cas de test, il est donc clairement correct de vérifier plus de 90.
trichoplax
1
J'ai édité l'explication ainsi, mais j'ai écrit "cast to integer" car je ne sais pas comment l'opérateur doit se comporter envers les valeurs négatives à virgule flottante. Il n'y a pas de problème ici car cela fonctionne sur la valeur absolue, mais je préfère ne pas faire d'hypothèses trop fortes sur l'opérateur.
Osable
1
Vous pouvez remplacer v"NESW"yk})par Ç30^5%:)
Adnan
5

Python 3, 146 145 117 107 97 94 93 92 octets

f(s):u='NESW'.find(s[0])*90;return(u+f(s[1:]))/2+180*(abs(u-‌​f(s[1:]))>180)if s[1:]else u

Appelez favec la chaîne.

L3viathan
la source
Vous ne pouvez pas avoir les deux ...0elsequ'ils lancent SyntaxErrors.
Jonathan Allan
@JonathanAllan Quelle version de Python utilisez-vous? Je suis sur 3.5.2 et cela fonctionne.
L3viathan
Je l'ai exécuté sur 3.3.3 - pouvez-vous supprimer l'espace entre else et -aussi? (peut en 3.3.3)
Jonathan Allan
@JonathanAllan Oui je peux! Merci, cela me fait gagner un autre octet.
L3viathan
2
@Titus d.findpeut, j'ai eu l'idée exacte il y a une minute; voir la réponse mise à jour.
L3viathan
5

C, 184 octets

double h(char c){return ((c=='E')+(c=='S')*2+(c=='W')*3);}double d(char*s){double f=h(*s);if(s[1]){double t=f;f=(f+d(s+1)/90)/2;if(((t-f)>1)||((f-t)>1))f+=2;if(f>=4)f-=4;}return f*90;}

Non golfé

// a helper function
double direction_(char ch)
{
    if (ch=='N')
        return 0.;
    else if (ch=='E')
        return 90.;
    else if (ch=='S')
        return 180.;
    else
        return 270.;
}

// this is the main function to call
double direction(char* str)
{
    double fAngle = direction_(str[0]);
    if (str[1])
    {
        double tmp = fAngle + direction(str+1);
        if (tmp>=360.)
            tmp-=360.;
        tmp/=2;

        if (((tmp-fAngle)>90.) || ((tmp-fAngle)<-90.))
        { //  check if we need to take the "other side"; if the resulting angle is more than 90 degrees away, we took the wrong on
            if (tmp>=180.)
                tmp-=180.;
            else
                tmp+=180.;
        }
        fAngle = tmp;
    }
    return fAngle;
}
Eyal Lev
la source
semble que l'utilisation de float ne vous donne pas la précision nécessaire.
Eyal Lev
4
Bienvenue chez PPCG! : D
mbomb007
Les noms des fonctions ne seront-ils pas en conflit les uns avec les autres (puisque les noms sont les deux d)?
clismique
@qwerp, signature différente (l'un prend caractère *, l'autre ne prend que caractère)
Eyal Lev
2
Les noms de fonction ne sont pas modifiés en C, comme ils le sont en C ++, vous devez donc renommer l'un d'eux si vous voulez qu'il soit C.
Klas Lindbäck
3

R, 172 146 octets

z=rev((0:3*90)[match(scan(,""),c("N","E","S","W"))]);p=z[1];l=length(z);for(i in 2:l)p=(p+z[i])/2+(abs(p-z[i])>180)*180;if(l<2)p=z;sprintf("%f",p)

Non golfé

z=rev((0:3*90)[match(scan,""),c("N","E","S","W"))]); #1
p=z[1];                                              #2
l=length(z)                                          #3
for(i in 2:l)p=(p+z[i])/2+(abs(p-z[i])>180)*180;     #4
if(l<2)p=z                                           #5
sprintf("%f",p)                                      #6

Expliqué

  1. Lire l'entrée de stdin
    • Faire correspondre l'entrée par index à c("N","E","S","W")
    • À partir des indices appariés: correspond au vecteur de degrés 0:3*90(au lieu de c(0,90,180,270))
    • Inverser et stocker sous z
  2. Initialiser p au degré équivalent au dernier caractère en entrée
  3. Enregistrer la longueur de l'entrée sous l
  4. Itérativement, calculez le plus proche des deux relèvements possibles.
  5. Si une seule entrée est donnée, réglez p surz
  6. Format et impression

Essayez les cas de test sur R-fiddle (notez que c'est une fonction car vous scanne travaillez pas sur R-fiddle)

Billywob
la source
À condition que la sortie soit correcte à 5 décimales, vous n'avez pas besoin d'effectuer l'arrondi. Du défi: Outputs 0.00001 and 0.000005 are both correct.vous devriez donc être en mesure d'économiser quelques octets en ne l'arrondissant pas
trichoplax
@trichoplax je comprends. L'entrée peut-elle également être un vecteur de caractères de chaîne comme. c("N","N","E")au lieu de "NNE"? Cela équivaut à une liste Python non imbriquée ["N","N","E"].
Billywob
Oui. Je voulais que "séquence" soit un terme général pour inclure des choses comme des tableaux, des vecteurs, des listes, des tuples.
trichoplax
1
Je pense que vous pouvez économiser 4 octets si vous divisez tout par 90 et printf (p * 90).
Titus
3

Haskell, 109 105 103 octets

h=180
a#b|abs(a-b)<h=n|n>h=n-h|1>0=n+h where n=(a+b)/2 -- calculates the new "mean" on the cirlce
f 'N'=0                                          -- translates characters to angles
f 'E'=90
f 'S'=h
f _=270
foldr1(#).map f                                  -- traverses the whole string

Merci pour -2 octets @xnor!

flawr
la source
La liste exhaustive fsemble longue, mais j'ai du mal à trouver quelque chose de plus court. Le plus proche que j'ai eu était f c=90*until(\i->"NESW"!!i==c)(+1)0(35). Je pense que vous pouvez remplacer 'W'par _.
xnor
Oui, je m'attendais aussi à ce qu'il y ait quelque chose de plus court, mais je n'ai rien trouvé. Merci pour le _!
flawr
3

Dyalog APL , 55 45 38 octets

Solution

Requiert ⎕IO←0, qui est par défaut sur de nombreux systèmes. Demande de la direction.

360|÷○÷180×12○(+÷(|+))/¯12○○2÷⍨'NES'⍳⍞

Explication

Contourne le problème en convertissant chaque lettre en un nombre complexe 1∠ θa + b · i , puis en effectuant une réduction de la somme de droite à gauche (point fort d'APL) tout en normalisant à chaque étape. Le θ final est ensuite converti en degrés et normalisé pour être à l'intérieur de [0, 360):

'NES'⍳⍞les indices de chaque lettre d'entrée dans "NES"; N → 0, E → 1, S → 2, toute autre chose → 3

○2÷⍨convertir en angles en radians; θ = π · x2

¯12○convertir en nombres complexes sur le cercle unitaire; e i · θ

(... )/réduisez la liste avec ... (ie insérez la fonction entre les éléments de ...)

+÷(|+)... la somme normalisée; x n - 1 + x n| x n - 1 + x n |

12○convertir en angle; θ

÷○÷180×convertir en degrés; 1π · 1180 · x

360| reste de division divisé par 360

TryAPL en ligne!

Anecdote

Si l'entrée et la sortie étaient des unités complexes orthogonales, la solution entière serait juste:

(+÷(|+))/

Le reste du code analyse les entrées et met en forme les sorties.

Adam
la source
Je remarque que les sorties de test ne correspondent pas à celles du défi à 5 décimales, ce qui rend cela invalide. Dyalog APL a-t-il la possibilité d'utiliser la double précision?
trichoplax
@trichoplax Oui, ⎕FR←1287utilise des flottants de 128 bits, mais TryAPL ne le permet pas.
Adám
Je pense que tout flottant supérieur ou égal à 64 bits devrait fonctionner (je n'ai cependant testé qu'en Python). Cela signifie-t-il que vous pouvez rendre le code valide mais qu'il ne fonctionnera alors que pour les personnes qui ont installé la langue? Peut-être pourriez-vous montrer le code complet valide pour le score, et inclure la version en ligne qui n'a pas tout à fait la précision requise afin que les gens puissent voir que l'algorithme est correct.
trichoplax
@trichoplax En fait, TryAPL utilise la double précision, mais vos cas de test accumulent des erreurs au-delà de 53 bits.
Adám
S'il peut être démontré que la différence est due à des différences d'interprétation de la norme IEEE 754, qui sont toujours conformes à la norme, alors j'ajusterai les cas de test pour m'assurer que les deux interprétations donnent le même résultat à 5 décimales. J'ai choisi les cas de test de telle sorte qu'ils donnent le même résultat à 5 décimales en Python pour les décimales flottantes (double précision) et de précision arbitraire. Je vais y jeter un œil.
trichoplax
2

Lisp commun, 347 327 octets

Merci à @Titus d'avoir décollé quelques-uns

Cela peut probablement être plus joué au golf, mais au moins cela fonctionne (je pense):

(defun d(c)(if(eql c #\N)0(if(eql c #\E)1(if(eql c #\S)2(if(eql c #\W)3)))))(defun m(a b)(if(> a b)(rotatef a b))(if(<(+(- 4 b)a)(- b a))(+(/(+(- 4 b)a)2)b)(+(/(- b a)2)a)))(defun f(s)(let((c))(setf c(d(char s(1-(length s)))))(do((a)(p(-(length s)2)(1- p)))((< p 0))(setf a(char s p))(setf c(m(d a)c)))(format t"~5$"(* c 90))))

Usage:

* (f "WNE")
337.50000
NIL

Fonction dprend un caractère N, E, Wou Set retourne le degré approprié. La fonction mobtient le degré combiné approprié de deux directions données. La fonction fparcourt la chaîne fournie, calcule le degré approprié et l'imprime en virgule flottante.

artificielle
la source
Mon LISP est rouillé, mais est-ce que tout diviser par 90 peut économiser 6 octets?
Titus
@Titus Je pense que oui. J'ai réalisé d'autres améliorations donc j'ajouterai ceci quand je serai devant mon ordinateur
artificiel
2

Befunge, 183 181 175 octets

>~#+:#25#%6*#/`#2_$>5%4*:00p"Z}"4*:***20g#v_+2/00g10g-:8`\0\-8`+!v
v5:+*:*:"d"/+55+5$_^#!:\p01/**:*4"}Z":p020<%**:*"(2Z"+**5*:*"0}"!<
>5>+#<%#56#58#:*#/+\#5:#5_$$$,,,".">:#,_@

Essayez-le en ligne!

Explication

Cela suit un algorithme similaire à la plupart des autres réponses, seulement il utilise des calculs à virgule fixe émulés avec des nombres entiers puisque Befunge ne prend pas en charge les virgules flottantes.

Merci à @Titus pour la routine ASCII-to-int.

 ~ : 5 6* ` _$        while ((c = getchar()) > 30)  // ends with any ctrl char or EOF
> + 2 %6 / 2            push(c / 2 % 6 + 2)         // partial conversion to int

                      do {
  5%                    dir = pop() % 5             // completes the conversion to int   
  4*:00p                dir *= 4; lowres_dir = dir  // used by the 180-flip calculation
  "Z}"4*:***            dir *= 22500000             // this is 90000000 / 4 
  20g_                  if (!first_pass) {
    +2/                   dir = (dir+last_dir)/2    // last_dir is second item on stack
    00g10g-               diff = lowres_dir - last_lowres_dir
    :8`\0\-8`+!!          flip = diff>8 || -diff>8
    "}0"*:*5**+           dir += flip * 180000000   // add 180 degrees if we need to flip
    "Z2("*:**%            dir %= 360000000          // keep within the 360 degree range
                        }
  020p                  first_pass = false
  :"Z}"4*:**/10p        last_lowres_dir = dir / 22500000
  \                     last_dir = dir              // saved as second item on stack
  :!_                 } while (!stack.empty())

$                     pop()                         // this leaves the final dir on top
5+55+/                dir = (dir + 5)/10            // round down to 5 decimal places
"d":*:*+              dir += 100000000              // add a terminating digit
                      while (true) {                // convert into chars on stack
:55 + % 6 8 * +\ : _    push(dir%10+'0'); if (!dir) break
   > < 5 5 : /+ 5 5     dir /= 10
                      }

$$$                   pop() x 3                     // drop the chars we don't need
,,,                   putchar(pop()) x 3            // output first three chars
"."                   push('.')                     // add a decimal point
>:#,_@                while(c=pop()) putchar(c)     // output the remaining chars
James Holderness
la source
Cela signifie-t-il simplement que vous devez émuler un type de point fixe plus grand (plus de décimales)? Les cas de test sont conçus pour exiger une double précision, qui ne dépasse pas 17 chiffres significatifs (un maximum de 16 décimales), et 14 décimales pourraient éventuellement suffire.
trichoplax