Prawdziwa rotacja Czebyszewa


15

Jest to wyzwanie inspirowane rotacją Czebyszewa . Proponuję przyjrzeć się tam odpowiedziom, aby uzyskać inspirację do tego wyzwania.

W punkcie na płaszczyźnie znajduje się unikalny kwadrat (prostokąt o równych bokach), który jest wyśrodkowany na początku i przecina ten punkt ( interaktywne demo ):

wprowadź opis zdjęcia tutaj

Biorąc pod uwagę punkt p i odległość d , zwróć punkt uzyskany przez przesunięcie odległości d od p , przeciwnie do ruchu wskazówek zegara (i zgodnie z ruchem wskazówek zegara dla ujemnego d ), wzdłuż obwodu kwadratu wyśrodkowanego na początku, który przecina p . Twoja odpowiedź musi zawierać co najmniej 4 cyfry dziesiętne.

Przypadki testowe:

(0, 0), 100 -> (0, 0)
(1, 1), 81.42 -> (-0.4200, 1.0000)
(42.234, 234.12), 2303.34 -> (-234.1200, 80.0940)
(-23, -39.234), -234.3 -> (39.2340, -21.8960)

Następujące przypadki testowe pochodzą z oryginalnego wyzwania Martina Endera i wszystkie mają wartość d = 1 :

(0, 0)       -> (0, 0)
(1, 0)       -> (1, 1)
(1, 1)       -> (0, 1)
(0, 1)       -> (-1, 1)
(-1, 1)      -> (-1, 0)
(-1, 0)      -> (-1, -1)
(-1, -1)     -> (0, -1)
(0, -1)      -> (1, -1)
(1, -1)      -> (1, 0)
(95, -12)    -> (95, -11)
(127, 127)   -> (126, 127)
(-2, 101)    -> (-3, 101)
(-65, 65)    -> (-65, 64)
(-127, 42)   -> (-127, 41)
(-9, -9)     -> (-8, -9)
(126, -127)  -> (127, -127)
(105, -105)  -> (105, -104)

Czy prawie wszystkie z nich nie mogą być tylko nieznacznie zmienione w porównaniu z innym wyzwaniem? To wydaje się niepotrzebnym dodatkiem.
— ATaco

1
@ATaco Nie, to trochę bardziej skomplikowane.
— orlp

Czy odległość należy obliczać wzdłuż obwodu, zaczynając od p?
— Gábor Fekete

@ GáborFekete Co jeszcze?
— orlp

Tak, rozumiem, przypadki testowe implikują to, ale nie zostało to wyraźnie określone. Na początku myślałem, że zacznie się od dodatniego przecięcia na osi x.
— Gábor Fekete

Odpowiedzi:


4

Python 2, 363 335 296 266 262 258 256 233 bajtów

Woo, 130 bajtów utraconych! Dzięki Neil za uratowanie 4 bajtów, Nathan Merrill za uratowanie 2 bajtów i xnor za uratowanie śmiesznych 23 bajtów!

Ogólna idea jest następująca: możemy zmniejszyć przebytą odległość, przyjmując jej moduł względem obwodu kwadratu. Obwód jest definiowany jako 8-krotność największej z dwóch współrzędnych, ponieważ punkt musi na nim spoczywać. Następnie, po przyjęciu modułu, gwarantujemy, że nie zachodzą na siebie. Gwarantuje to również, że zawsze musimy poruszać się w kierunku przeciwnym do ruchu wskazówek zegara, ponieważ moduł daje pozytywny wynik.

Stamtąd używam po prostu tego, co wiemy z podanych współrzędnych xiy, aby dowiedzieć się, gdzie jesteśmy: góra, dół, lewo, prawo lub w rogu i określić kierunek, który może być jednym z 0, 1, 2, 3:

0 --> we are on the 'top', moving 'left'
1 --> we are on the 'left', moving 'down'
2 --> we are on the 'bottom', moving 'right'
3 --> we are on the 'right', moving 'up'

Po tym jest to tak proste, jak zapętlanie, gdy jeszcze mamy odległość do przebycia, i na podstawie kierunku, który odejmujemy lub dodajemy do odpowiedniej współrzędnej, i mówimy pętli, w którym kierunku idziemy dalej.

p,d=input()
x,y=p
s=max(x,y,-x,-y)
d=d%(s*8or 1)
r=[(y<s)*[2,[3,x>-s][x<s]][y>-s],[2*(y<0),3*(y<=0)][x>0]][y*y==x*x]
while s>0<d:f=1-2*(r<2);m=abs(f*s-p[r%2]);j=d>m;p[r%2]=[p[r%2]+f*d,f*s][j];r=-~r%4;d=(d-m)*j
print"%.4f "*2%tuple(p)

Chociaż dość długo, z pewnością działa. Oto kilka przykładowych operacji wejścia / wyjścia:

[0, 0], 100 --> 0.0000 0.0000
[1, 1], 81.42 --> -0.4200 1.0000
[42.234, 234.12], 2303.34 --> -234.1200 80.0940
[-23, -39.234], -234.3 --> 39.2340 -21.8960

Wypróbuj online lub uruchom testy .


Czy s=max(x,y,-x,-y)działa
— Neil,

@Neil Tak, dziękuję!
— Kade

(s>0)*(d>0)jest s>0<d. Dane wyjściowe mogą być "%.4f "*2%tuple(p). if s:d=d%(8*s)może być d%(s*8or 1). (r+1)może być ~-r. 1*(x>-s)może po prostu być (x>-s). abs(y)==abs(x)może byćy*y==x*x
— xnor

@xnor Wow, dzięki! Zmieniłem tylko te cienkie, które (x>-s)nie wymagały nawiasów ani ~-rdekretu, więc użyłem -~r.
— Kade

3

JavaScript (ES6), 147 bajtów

f=(x,y,d,s=Math.max(x,y,-x,-y),c=(d/8%s+s)%s*8,v=0,w=x+y>0?1:-1,b=(v?x:y)*w+c-s)=>c?b>0?f(v?s*w:x,v?y:s*w,d,s,b,!v,v?w:-w):[x+c*w*v,y+c*w*!v]:[x,y]

Objaśnienie: Działa, próbując dodać wektor kierunku, trzymając się w granicach kwadratu. Każde przekroczenie jest rekurencyjnie cofane z kierunkiem obróconym w kierunku przeciwnym do ruchu wskazówek zegara o 90 °. Kierunek jest faktycznie kodowany za pomocą flagi pionowej vi jednostki, wtak że wektory (1, 0), (0, 1), (-1, 0) i (0, -1) są kodowane z v0, 1, 0 , 1 i wodpowiednio 1, 1, -1, -1. Wektor kierunku może początkowo nie wskazywać odpowiedniego kierunku, ale nigdy nie jest skierowany do tyłu, więc ostatecznie obróci się w użytecznym kierunku.

f=(x,y,d,                   Input parameters
 s=Math.max(x,y,-x,-y),     Calculate half the side of the square
 c=(d/8%s+s)%s*8,           Reduce the distance modulo the perimeter
 v=0,                       Initial vertical flag
 w=x+y>0?1:-1,              Initial direction
 b=(v?x:y)*w+c-s)=>         Will we overshoot the corner?
  c?b>0?f(v?s*w:x,v?y:s*w,  Advance to the next corner
          d,s,b,!v,v?w:-w): Rotate the direction
        [x+c*w*v,y+c*w*!v]: Advance the remaining amout
    [x,y]                   Nothing to do, zero input

Może to być spowodowane tym, że moja przeglądarka (Opera 40.0.2308.81), ale wygląda na to, że ma trochę błędu zaokrąglania, f(42.234, 234.12, 2303.34) -> [-234.12, 80.09399999999988]co oznacza, że ​​nie ma 4-cyfrowej precyzji. Może dodanie formatowania wyjściowego to naprawi? Dobra odpowiedź! :)
— Kade

@Shebang Techniczne formatowanie wyjściowe wymagałoby zaokrąglenia, a zatem wprowadziłoby potencjalny błąd zaokrąglania. Wygenerowane liczby są możliwie najbliższe w granicach arytmetyki zmiennoprzecinkowej, co nie powinno dawać dokładnych wyników dla dowolnych reprezentacji dziesiętnych. Trzymaj się ułamków binarnych, jeśli chcesz dokładnych odpowiedzi.
— Neil,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.