Рубі, 68
Функція лямбда приймає комплексне число як аргумент, повертає комплексне число.
->z{k=1
4.times{z*=?i.to_c
x,y=z.rect
y*y>=x*x&&y<-x&&(z+=k;k=0)}
z}
Ми обертаємо точку на 90 градусів 4 рази, множивши на i
. Тому він проходить через усі 4 квадранти і повертається в незмінному вигляді - за винятком того, що ми модифікуємо його, коли він знаходиться в конкретному одному з них. Той факт, що він завжди модифікований в одному квадранті, спрощує модифікацію.
Найпростіше наслідувати, якщо ми змінимо його, z
коли він знаходиться в правому квадранті. в цьому випадку нам потрібно збільшити координату y на 1 (тобто додати i
доz
.)
Перевіряємо x.abs>=y.abs
, порівнюючи квадрати x
та y
. Це говорить нам, що точка знаходиться в правому або лівому квадранті, а не вгорі або внизу. Щоб перевірити це насправді в правому квадранті, ми додатково перевіряємо це x>y
(суворо більше, тому що ми хочемо виключити випадокx=y
, який відноситься до «верхнього» квадранту.) Якщо це вірно , ми додамо i
доz
.
З міркувань гольфу додавання i
не бажано. Натомість ми модифікуємо число, коли воно знаходиться в нижньому квадранті, і в цьому випадку ми повинні додати 1 до x
координати (додати 1 к z
.). У цьому випадку ми перевіримо, що y*y>=x*x
для перевірки знаходиться у верхньому або нижньому квадранті. Щоб надалі переконатися, що він знаходиться в нижньому квадранті, нам потрібно перевірити y<-x
(суворо виключаючи корпус правого нижнього кута, де y=-x
.)
Перевагою цієї перевірки є відсутність спеціального випадку для координати 0,0. На жаль, було встановлено, що переміщення точки може перенести її на інший квадрант, а це означає, що другий рух повинен бути придушений у разі повторного перевірки цього квадранта, що, ймовірно, заперечує перевагу.
Приклад 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.
Приклад 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.
У тестовій програмі
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)
Діаграма
Наступне зображення показує (синьою) область, де x*x>=y*y
(жовта) область, де y<-x
та (зелена) перетин їх, тобто область, де правильне перетворення - додавання 1 до z
.