Oblicz numer uzwojenia

15

Liczba uzwojenia jest liczbą całkowitą obrotów netto przeciwnie do ruchu wskazówek zegara, które obserwator musiał wykonać, aby podążać daną zamkniętą ścieżką. Zwróć uwagę, że wszelkie obroty zgodne z ruchem wskazówek zegara liczą się ujemnie w kierunku liczby uzwojenia. Ścieżka może się przecinać.

Niektóre przykłady (bezwstydnie zaczerpnięte z Wikipedii) podano poniżej:

wprowadź opis zdjęcia tutaj

Twoim celem jest obliczenie liczby uzwojenia dla danej ścieżki.

Wejście

Zakłada się, że obserwator jest u źródła (0,0).

Dane wejściowe są skończoną sekwencją punktów (par liczb całkowitych) z dowolnego pożądanego źródła wejściowego, która opisuje kawałkową ścieżkę liniową. W razie potrzeby możesz spłaszczyć tę sekwencję liczb całkowitych 1D, a także zamienić dane wejściowe, aby przyjąć wszystkie współrzędne x przed wszystkimi współrzędnymi y / odwrotnie. Możesz również wziąć dane wejściowe jako liczbę zespolonąa+b i . Ścieżka może się przecinać i zawierać segmenty o zerowej długości. Pierwszy punkt to początek ścieżki i zakłada się, że leży gdzieś na dodatniej osi x.

Żadna część ścieżki nie przecina początku. Ścieżka zawsze będzie zamknięta (tzn. Pierwszy i utracony punkt są takie same). Twój kod może sugerować ostatni punkt lub wymagać jego uwzględnienia.

Na przykład w zależności od preferencji oba dane wejściowe określają ten sam kwadrat:

domniemany punkt końcowy

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

wyraźny punkt końcowy

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

Wynik

Dane wyjściowe to jedna liczba całkowita dla liczby uzwojenia. Może to być dowolne źródło (zwracana wartość, standardowe wyjście, plik itp.).

Przykłady

Wszystkie przykłady mają wyraźnie zdefiniowany punkt końcowy i są podane jako pary x, y. Nawiasem mówiąc, powinieneś być w stanie bezpośrednio wprowadzić te przykłady do dowolnych kodów, zakładając niejawnie zdefiniowane punkty końcowe, a wyniki powinny być takie same.

1. Test podstawowy

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

Wynik

1

2. Test powtarzanego punktu

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

Wynik

1

3. Test zgodny z ruchem wskazówek zegara

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

Wynik

-1

4. Test zewnętrzny

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

Wynik

0

5. Uzwojenie mieszane

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

Wynik

2

Punktacja

To jest kod golfowy; najkrótszy kod wygrywa. Obowiązują standardowe luki. Możesz używać dowolnych wbudowanych funkcji, o ile nie zostały one specjalnie zaprojektowane do obliczania liczby uzwojenia.

helloworld922
źródło
2
Czy dane wejściowe można traktować jako liczby zespolone (lub ich ciąg znaków, taki jak "1-i"lub "1-1i"?)
Level River St
tak, każdy rodzaj pary jest dozwolony.
helloworld922

Odpowiedzi:

10

ES6, 83 bajty

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

Bierze jako dane wejściowe tablicę par punktów, które są interpretowane jako liczby zespolone. Zamiast konwertować każdy punkt na kąt, punkty są dzielone przez poprzedni punkt, który Math.atan2 następnie konwertuje na kąt między -π i π, tym samym automatycznie określając, w którą stronę ścieżka jest kręta. Suma kątów jest wtedy 2π razy liczba uzwojenia.

Ponieważ Math.atan2 nie dba o skalę swoich argumentów, tak naprawdę nie wykonuję pełnego podziału z / w = (z * w*) / (w * w*), po prostu mnożę każdy punkt przez złożoną koniugat poprzedniego punktu.

Edycja: Zapisano 4 bajty dzięki @ edc65.

Neil
źródło
Ładnie i szybko. I nie rozumiem twojej matematyki. Ale reduceprawie zawsze jest złym wyborem.
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/2zamiast tego użyj mapy lub zmniejsz. W każdym razie masz mój głos
edc65
@ edc65 Dzięki; Użyłem, reduceponieważ nie zdawałem sobie sprawy, że Math.atan2 (0,0) wynosi 0. (Cóż, zależy to od tego, czy jedno z twoich 0 to w rzeczywistości -0). Matematyka jest oparta na złożonym podziale, który jest zwykle obliczany jako z / w = z * w* / |w|², ale nie dbam o wielkość, więc to tylko pomnożenie przez złożony koniugat. Również nieco myląco Math.atan2 akceptuje argumenty (y, x).
Neil
Przyznaję, że nie rozumiem kodu, ale jeśli twój opis jest dokładny, to uważam, że twoja odpowiedź jest błędna. Rzeczywiście, jeśli wprowadziłeś punkty z tej ścieżki (daję obraz dla większej przejrzystości), liczba uzwojeń wynosi 1, podczas gdy twój problem dałby wynik 2.
Wojowu
@Wojowu Przepraszam, miałem na myśli kąt między punktami mierzony od początku, a nie zewnętrzne kąty wielokąta, więc dla twojego zdjęcia mój kod powinien rzeczywiście obliczyć odpowiedź jako 1.
Neil
3

MATL , 11 bajtów

X/Z/0)2/YP/

Dane wejściowe to ciąg liczb zespolonych, w tym punkt końcowy.

Wypróbuj online!

Wyjaśnienie

Większość pracy jest wykonywana przez Z/funkcję ( unwrap), która rozpakowuje kąty w radianach, zmieniając absolutne skoki większe lub równe pi do ich uzupełnienia 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
źródło
1
MATL i Jelly mają ostatnio bardzo dużo problemów matematycznych. Jestem pod wrażeniem, że prawie nie grałeś w golfa w języku Dennisa ...
ETHproductions
@ETHproductions Dziękujemy za miłe słowa! Tak, zostali związani z kilkoma ostatnimi wyzwaniami. Z drugiej strony widziałem całkiem sporo problemów, w których liczba bajtów Jelly jest o połowę mniejsza niż MATL :-D
Luis Mendo
2

Galaretka, 11 bajtów

æAI÷ØPæ%1SH

Pobiera to dane wejściowe jako listę współrzędnych y i listę współrzędnych x.

Wypróbuj tutaj .

lirtosiast
źródło
1

Python, 111

Najdłuższa jak dotąd odpowiedź. Moje motywacje to 1) nauczenie się Pythona i 2) prawdopodobnie przeniesienie tego do Pyth'a.

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

Dane wejściowe podano jako listę liczb zespolonych.

Ideone.

Myślę, że podejście jest podobne do odpowiedzi ES6.

Po pomnożeniu 2 liczb zespolonych argument lub faza iloczynu jest sumą argumentu lub fazy dwóch liczb. Zatem, gdy liczba zespolona jest dzielona przez inną, wówczas faza ilorazu jest różnicą między fazami licznika i mianownika. W ten sposób możemy obliczyć kąt przejścia dla każdego punktu i następnego punktu. Suma tych kątów i podziel przez 2π daje wymaganą liczbę uzwojeń.

Cyfrowa trauma
źródło