Руби, 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
.