Berechnen Sie die Wicklungszahl

15

Die Wicklungszahl ist die ganze Zahl der Nettoumdrehungen gegen den Uhrzeigersinn, die ein Beobachter gemacht haben muss, um einem bestimmten geschlossenen Pfad zu folgen. Beachten Sie, dass alle Umdrehungen im Uhrzeigersinn negativ für die Wicklungszahl sind. Der Pfad darf sich selbst kreuzen.

Einige Beispiele (schamlos aus Wikipedia entnommen) sind nachfolgend aufgeführt:

Bildbeschreibung hier eingeben

Ihr Ziel ist es, die Windungszahl für einen bestimmten Pfad zu berechnen.

Eingang

Es wird angenommen, dass sich der Beobachter am Ursprung befindet (0,0).

Die Eingabe ist eine endliche Folge von Punkten (paarweise ganze Zahlen) aus einer beliebigen Eingabequelle, die den stückweisen linearen Pfad beschreibt. Falls gewünscht, können Sie dies zu einer 1D-Folge von Ganzzahlen reduzieren und die Eingabe so verschieben, dass alle x-Koordinaten vor allen y-Koordinaten verwendet werden. Sie können die Eingabe auch als komplexe Zahl annehmen a+b i. Der Pfad kann sich selbst schneiden und Segmente mit der Länge Null enthalten. Der erste Punkt ist der Anfang des Pfades und liegt vermutlich irgendwo auf der positiven x-Achse.

Kein Teil des Pfades schneidet den Ursprung. Der Pfad wird immer geschlossen (dh der erste und der verlorene Punkt sind gleich). Ihr Code kann entweder den letzten Punkt implizieren oder erfordern, dass er enthalten ist.

Abhängig von Ihrer Präferenz geben beide Eingaben beispielsweise dasselbe Quadrat an:

impliziter Endpunkt

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

expliziter Endpunkt

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

Ausgabe

Die Ausgabe ist eine einzelne Ganzzahl für die Wicklungsnummer. Dies kann eine beliebige Quelle sein (Rückgabewert, Standardausgabe, Datei usw.).

Beispiele

In allen Beispielen ist der Endpunkt explizit definiert und als x, y-Paare angegeben. Im Übrigen sollten Sie in der Lage sein, diese Beispiele auch direkt in Codes einzugeben, die implizit definierte Endpunkte voraussetzen, und die Ausgaben sollten dieselben sein.

1. Grundtest

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

Ausgabe

1

2. Wiederholter Punkttest

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

Ausgabe

1

3. Test im Uhrzeigersinn

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

Ausgabe

-1

4. Außerhalb des Tests

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

Ausgabe

0

5. Gemischte Wicklung

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

Ausgabe

2

Wertung

Das ist Code Golf; kürzester Code gewinnt. Es gelten Standardlücken. Sie können alle integrierten Funktionen verwenden, sofern diese nicht speziell für die Berechnung der Wicklungsnummer entwickelt wurden.

helloworld922
quelle
2
Kann die Eingabe als komplexe Zahl (oder als Zeichenfolgendarstellung, z. B. "1-i"oder "1-1i"?)
Interpretiert werden
ja, jedes Paar ist erlaubt.
helloworld922

Antworten:

10

ES6, 83 Bytes

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

Nimmt als Eingabe ein Array von Punktpaaren, die als komplexe Zahlen interpretiert werden. Anstatt jeden Punkt in einen Winkel umzuwandeln, werden die Punkte durch den vorherigen Punkt geteilt, den Math.atan2 dann in einen Winkel zwischen -π und π umwandelt, um so automatisch zu bestimmen, in welche Richtung sich der Pfad windet. Die Summe der Winkel ist dann 2π mal die Wicklungszahl.

Da es Math.atan2 nicht um den Umfang seiner Argumente geht, führe ich nicht die vollständige Division durch, z / w = (z * w*) / (w * w*)sondern multipliziere einfach jeden Punkt mit dem komplexen Konjugat des vorherigen Punkts.

Bearbeiten: 4 Bytes dank @ edc65 gespeichert.

Neil
quelle
Schön und schnell. Und ich verstehe deine Mathematik nicht. Ist reduceaber fast immer eine schlechte Wahl.
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/2Verwenden Sie stattdessen die Karte oder reduzieren Sie sie. Sie haben trotzdem meine Stimme
edc65
@ edc65 Danke; Ich habe verwendet, reduceweil mir nicht klar war, dass Math.atan2 (0,0) 0 ist. (Nun, es hängt davon ab, ob eine Ihrer 0en tatsächlich -0 ist.) Die Mathematik basiert auf einer komplexen Division, die normalerweise wie folgt berechnet wird z / w = z * w* / |w|², aber die Größe ist mir egal, also ist es nur die Multiplikation mit dem komplexen Konjugat. Ebenfalls leicht verwirrend akzeptiert Math.atan2 (y, x) Argumente.
Neil
Ich gebe zu, dass ich den Code nicht verstehe, aber wenn Ihre Beschreibung korrekt ist, glaube ich, dass Ihre Antwort falsch ist. In der Tat, wenn Sie Punkte von diesem Pfad
eingeben
@ Wojowu Entschuldigung, ich meinte den Winkel zwischen den Punkten, gemessen vom Ursprung, und nicht die Außenwinkel des Polygons. Für Ihr Bild sollte mein Code in der Tat die Antwort als 1 berechnen.
Neil,
3

MATL , 11 Bytes

X/Z/0)2/YP/

Die Eingabe ist eine Folge komplexer Zahlen einschließlich des Endpunkts.

Probieren Sie es online!

Erläuterung

Die meiste Arbeit erledigt die Z/Funktion ( unwrap), die Winkel im Bogenmaß auspackt, indem absolute Sprünge größer oder gleich pi auf ihr 2 * pi-Komplement geändert werden.

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
quelle
1
MATL und Jelly haben in letzter Zeit die meisten mathematischen Herausforderungen gemeistert. Ich bin beeindruckt, Sie haben Dennis 'Sprache fast übertroffen ...
ETHproductions
@ETHproductions Danke für deine netten Worte! Ja, sie haben in letzter Zeit einige Herausforderungen gemeistert. Andererseits habe ich einige Probleme gesehen, bei denen Jellys Byteanzahl ungefähr halb so hoch ist wie MATL :-D
Luis Mendo
2

Jelly, 11 Bytes

æAI÷ØPæ%1SH

Dies nimmt Eingaben als eine Liste von y-Koordinaten und eine Liste von x-Koordinaten entgegen.

Probieren Sie es hier aus .

Lirtosiast
quelle
1

Python, 111

Längste Antwort bis jetzt. Meine Motivation ist, 1) Python zu lernen und 2) dies möglicherweise auf Pyth zu übertragen.

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

Die Eingabe erfolgt als Liste komplexer Zahlen.

Ideone.

Ich denke, der Ansatz ähnelt der Antwort von ES6.

Wenn 2 komplexe Zahlen multipliziert werden, ist das Argument oder die Phase des Produkts die Summe des Arguments oder der Phase der beiden Zahlen. Wenn also eine komplexe Zahl durch eine andere geteilt wird, ist die Phase des Quotienten die Differenz zwischen den Phasen des Zählers und des Nenners. So können wir für jeden Punkt und den nächsten Punkt den durchfahrenen Winkel berechnen. Summiere diese Winkel und dividiere durch 2π ergibt die erforderliche Wicklungszahl.

Digitales Trauma
quelle