Ruby, 68
Funkcja Lambda przyjmuje jako argument liczbę zespoloną, zwraca liczbę zespoloną.
->z{k=1
4.times{z*=?i.to_c
x,y=z.rect
y*y>=x*x&&y<-x&&(z+=k;k=0)}
z}
Obracamy punkt o 90 stopni 4 razy, mnożąc przez i
. W związku z tym przechodzi przez wszystkie 4 ćwiartki i zostanie zwrócony w niezmienionej formie - z wyjątkiem tego, że modyfikujemy go, gdy znajduje się w jednym z nich. Fakt, że zawsze jest modyfikowany w tej samej ćwiartce, upraszcza modyfikację.
Najłatwiej jest naśladować, jeśli zmienimy go, z
gdy znajduje się on w prawej ćwiartce. w tym przypadku musimy zwiększyć współrzędną y o 1 (tj. dodać i
do z
.)
Sprawdzamy x.abs>=y.abs
, porównując kwadraty x
i y
. To mówi nam, że punkt znajduje się w prawej lub lewej ćwiartce, a nie u góry lub u dołu. Aby sprawdzić to w rzeczywistości w kwadrancie stroną możemy dodatkowo sprawdzić, że x>y
(ściśle większa, ponieważ chcemy, aby wykluczyć przypadek, x=y
który należy do „top” ćwiartce.) Jeżeli to prawda dodamy i
do z
.
Z powodów golfowych dodawanie i
nie jest pożądane. Zamiast tego modyfikujemy liczbę, gdy znajduje się ona w dolnej ćwiartce, w którym to przypadku musimy dodać 1 do x
współrzędnej (dodać 1 do z
.) W tym przypadku testujemy, y*y>=x*x
aby sprawdzić, czy jest ona w górnej lub dolnej ćwiartce. Aby dodatkowo upewnić się, że znajduje się w dolnej ćwiartce, musimy to sprawdzić y<-x
(ściśle wykluczając przypadek prawego dolnego rogu, gdzie y=-x
.)
Zaletą tego sprawdzenia jest to, że nie ma specjalnego przypadku dla współrzędnej 0,0. Niestety stwierdzono, że przesunięcie punktu może przesunąć go do innej ćwiartki, a to oznacza, że drugi ruch musi zostać stłumiony, jeśli ćwiartka zostanie ponownie sprawdzona, co prawdopodobnie neguje przewagę.
Przykład 1
Input 95,-12
Rotate 90deg 12,95
Rotate 90deg -95,12
Rotate 90deg -12,-95
Rotate 90deg 95,-12
y.abs>=x.abs=TRUE, y<-x=TRUE, increase x 95,-11
The check and alteration of the coordinate is done AFTER the rotation.
Thus in this case it gets done in the 4th iteration of the loop, not the 1st.
If the code were rewritten to do the check and alteration BEFORE the rotation,
it would be done in the 1st iteration instead of the 4th.
Przykład 2
Input -1,0
Rotate 90deg 0,-1
y.abs>=x.abs=TRUE, y<-x=TRUE, increase x 1,-1
Rotate 90deg 1,1
Rotate 90deg 1,-1
Rotate 90deg -1,-1
y.abs>=x.abs?=TRUE, y<-x=TRUE but DO NOT CHANGE x!
This is an unusual situation due to the fact that the first move caused the
point to advance by one quadrant. We do NOT want to move it again, for this
reason we need to set k to 0 the first time it is moved.
W programie testowym
f=->z{k=1 #amount to be added to coordinate
4.times{z*=?i.to_c #iterate 4 times, rotating point by 90deg till it reaches the original orientation
x,y=z.rect #separate out x and y for testing
y*y>=x*x&&y<-x&&(z+=k;k=0)} #if y.abs>=x.abs and y negative and not equal -x, move the point and zero k.
z} #return z
puts f[Complex(0, 0)] # (0, 0)
puts f[Complex(1, 0)] # (1, 1)
puts f[Complex(1, 1)] # (0, 1)
puts f[Complex(0, 1)] # (-1, 1)
puts f[Complex(-1, 1)] # (-1, 0)
puts
puts f[Complex(-1, 0)] # (-1, -1)
puts f[Complex(-1, -1)] # (0, -1)
puts f[Complex(0, -1)] # (1, -1)
puts f[Complex(1, -1)] # (1, 0)
puts f[Complex(95, -12)] # (95, -11)
puts f[Complex(127, 127)] # (126, 127)
puts
puts f[Complex(-2, 101)] # (-3, 101)
puts f[Complex(-65, 65)] # (-65, 64)
puts f[Complex(-127, 42)] # (-127, 41)
puts f[Complex(-9, -9)] # (-8, -9)
puts f[Complex(126, -127)] # (127, -127)
puts f[Complex(105, -105)] # (105, -104)
Diagram
Poniższy obraz pokazuje (niebieski) obszar, w którym x*x>=y*y
(żółty) obszar, w którym y<-x
i (zielony) ich przecięcie, czyli region, w którym poprawna transformacja jest dodaniem 1 do z
.