Calculer le nombre d'enroulement

15

Le nombre d'enroulement est le nombre entier de révolutions nettes dans le sens antihoraire qu'un observateur doit avoir effectuées pour suivre un chemin fermé donné. Notez que toute rotation dans le sens des aiguilles d'une montre compte négative pour le nombre de bobinage. Le chemin est autorisé à s'entrecroiser.

Quelques exemples (pris sans vergogne de Wikipedia) sont donnés ci-dessous:

entrez la description de l'image ici

Votre objectif est de calculer le nombre d'enroulement pour un chemin donné.

Contribution

L'observateur est supposé être à l'origine (0,0).

L'entrée est une séquence finie de points (paire de nombres entiers) provenant de n'importe quelle source d'entrée souhaitée qui décrit le chemin linéaire par morceaux. Vous pouvez aplatir cela en une séquence 1D de nombres entiers si vous le souhaitez, et vous pouvez également étaler l'entrée pour prendre toutes les coordonnées x avant toutes les coordonnées y / vice-versa. Vous pouvez également prendre l'entrée comme un nombre complexe a+b i. Le chemin peut se recouper et peut contenir des segments de longueur nulle. Le premier point est le début du chemin et est supposé se situer quelque part sur l'axe x positif.

Aucune partie du chemin ne coupera l'origine. Le chemin sera toujours fermé (c'est-à-dire que le premier et le point perdu sont les mêmes). Votre code peut impliquer le dernier point ou exiger qu'il soit inclus.

Par exemple, selon votre préférence, les deux entrées spécifient le même carré:

point final implicite

1,0
1,1
-1,1
-1,-1
1,-1

point final explicite

1,0
1,1
-1,1
-1,-1
1,-1
1,0

Production

La sortie est un entier unique pour le nombre d'enroulement. Il peut s'agir de n'importe quelle source (valeur de retour, sortie standard, fichier, etc.).

Exemples

Tous les exemples ont le point final explicitement défini et sont donnés sous forme de paires x, y. Soit dit en passant, vous devriez également pouvoir directement alimenter ces exemples dans n'importe quel code en supposant des points d'extrémité définis implicitement et les sorties devraient être les mêmes.

1. Test de base

1,0
1,1
-1,1
-1,-1
1,-1
1,0

Production

1

2. Test ponctuel répété

1,0
1,0
1,1
1,1
-1,1
-1,1
-1,-1
-1,-1
1,-1
1,-1
1,0

Production

1

3. Test dans le sens horaire

1,0
1,-1
-1,-1
-1,1
1,1
1,0

Production

-1

4. Test extérieur

1,0
1,1
2,1
1,0

Production

0

5. Enroulement mixte

1,0
1,1
-1,1
-1,-1
1,-1
1,0
1,-1
-1,-1
-1,1
1,1
1,0
1,1
-1,1
-1,-1
1,-1
1,0
1,1
-1,1
-1,-1
1,-1
1,0

Production

2

Notation

C'est le golf de code; le code le plus court gagne. Des échappatoires standard s'appliquent. Vous pouvez utiliser toutes les fonctions intégrées tant qu'elles n'ont pas été spécifiquement conçues pour calculer le nombre d'enroulement.

helloworld922
la source
2
Les entrées peuvent-elles être prises comme des nombres complexes (ou une représentation sous forme de chaîne de ceux-ci, comme "1-i"ou "1-1i"?)
Level River St
oui, tout type de paire est autorisé.
helloworld922

Réponses:

10

ES6, 83 octets

a=>a.map(([x,y])=>r+=Math.atan2(y*b-x*c,y*c+x*b,b=x,c=y),b=c=r=0)&&r/Math.PI/2

Prend en entrée un tableau de paires de points qui sont interprétés comme des nombres complexes. Plutôt que de convertir chaque point en un angle, les points sont divisés par le point précédent, que Math.atan2 convertit ensuite en un angle entre -π et π, déterminant ainsi automatiquement la direction dans laquelle le chemin s'enroule. La somme des angles est alors 2π fois le nombre d'enroulement.

Puisque Math.atan2 ne se soucie pas de l'échelle de ses arguments, je n'effectue pas réellement la division complète z / w = (z * w*) / (w * w*)au lieu de cela, je multiplie simplement chaque point par le conjugué complexe du point précédent.

Edit: 4 octets enregistrés grâce à @ edc65.

Neil
la source
Agréable et rapide. Et je ne comprends pas tes maths. Mais reducec'est presque toujours un mauvais choix.
edc65
a=>a.map(([x,y])=>r+=Math.atan2(y*b-x*c,y*c+x*b,b=x,c=y),b=c=r=0)&&r/Math.PI/2utilisez plutôt la carte ou réduisez. Vous avez quand même mon vote
edc65
@ edc65 Merci; J'ai utilisé reduceparce que je ne savais pas que Math.atan2 (0,0) est égal à 0. (Eh bien, cela dépend si l'un de vos 0 est réellement -0.) Les mathématiques sont basées sur une division complexe, qui est normalement calculée comme z / w = z * w* / |w|², mais je ne me soucie pas de l'ampleur, donc c'est juste une multiplication par le conjugué complexe. Math.atan2 accepte également de manière légèrement confuse les arguments (y, x).
Neil
J'avoue ne pas comprendre le code, mais si votre description est exacte, je pense que votre réponse est fausse. En effet, si vous avez entré des points à partir de ce chemin (je donne une image pour plus de clarté), le nombre d'enroulement est 1, tandis que votre problème en afficherait 2.
Wojowu
@Wojowu Désolé, je voulais dire l'angle entre les points mesuré depuis l'origine, plutôt que les angles externes du polygone, donc pour votre image, mon code devrait en effet calculer la réponse comme 1.
Neil
3

MATL , 11 octets

X/Z/0)2/YP/

L'entrée est une séquence de nombres complexes comprenant le point final.

Essayez-le en ligne!

Explication

La plupart du travail est effectué par la Z/fonction ( unwrap), qui déroule les angles en radians en modifiant les sauts absolus supérieurs ou égaux à pi à leur complément 2 * pi.

X/       % compute angle of each complex number
Z/       % unwrap angles
0)       % pick last value. Total change of angle will be a multiple of 2*pi because 
         % the path is closed. Total change of angle coincides with last unwrapped
         % angle because the first angle is always 0
2/       % divide by 2
YP/      % divide by pi
Luis Mendo
la source
1
MATL et Jelly ont à peu près lié la plupart des défis mathématiques récemment. Je suis impressionné, vous avez presque dépassé le méta-golf de la langue de Dennis ...
ETHproductions
@ETHproductions Merci pour vos belles paroles! Oui, ils ont été liés dans certains défis récents. D'un autre côté, j'ai vu pas mal de problèmes où le nombre d'octets de Jelly est environ la moitié de MATL :-D
Luis Mendo
2

Gelée, 11 octets

æAI÷ØPæ%1SH

Cela prend l'entrée comme une liste de coordonnées y et une liste de coordonnées x.

Essayez-le ici .

lirtosiast
la source
1

Python, 111

Réponse la plus longue jusqu'à présent. Mes motivations sont 1) d'apprendre python et 2) éventuellement de porter cela en pyth.

from cmath import *
q=input()
print reduce(lambda x,y:x+y,map(lambda (x,y):phase(x/y)/pi/2,zip(q[1:]+q[:1],q)))

L'entrée est donnée sous la forme d'une liste de nombres complexes.

Ideone.

Je pense que l'approche est similaire à la réponse ES6.

Lorsque 2 nombres complexes sont multipliés, l'argument ou la phase du produit est la somme de l'argument ou de la phase des deux nombres. Ainsi, lorsqu'un nombre complexe est divisé par un autre, la phase du quotient est la différence entre les phases du numérateur et du dénominateur. Ainsi, nous pouvons calculer l'angle traversé pour chaque point et le point suivant. Additionner ces angles et diviser par 2π donne le nombre d'enroulement requis.

Traumatisme numérique
la source