Ruby, 68
A função Lambda recebe um número complexo como argumento, retorna um número complexo.
->z{k=1
4.times{z*=?i.to_c
x,y=z.rect
y*y>=x*x&&y<-x&&(z+=k;k=0)}
z}
Giramos o ponto 90 graus 4 vezes multiplicando por i
. Portanto, ele passa por todos os quatro quadrantes e seria devolvido inalterado - exceto pelo fato de modificá-lo quando estiver em um deles específico. O fato de sempre ser modificado no mesmo quadrante simplifica a modificação.
É mais fácil segui-lo se o alterarmos z
quando estiver no quadrante do lado direito. neste caso, precisamos aumentar a coordenada y em 1 (por exemplo, adicionar i
a z
.)
Verificamos x.abs>=y.abs
comparando os quadrados de x
e y
. Isso nos diz que o ponto está no quadrante direito ou esquerdo, não em cima ou em baixo. Para verificar se, de fato, está no quadrante do lado direito, verificamos ainda mais x>y
(estritamente maior porque queremos excluir o caso x=y
que pertence ao quadrante "superior".) Onde isso é verdade, adicionamos i
a z
.
Por razões de golfe, a adição i
não é desejável. Em vez disso, modificamos o número quando ele está no quadrante inferior; nesse caso, temos que adicionar 1 à x
coordenada (adicionar 1 a z
.) Nesse caso, testamos se y*y>=x*x
a verificação está no quadrante superior ou inferior. Para garantir ainda mais que ele esteja no quadrante inferior, precisamos verificar y<-x
(excluindo estritamente o caso do canto inferior direito, onde y=-x
.)
Uma vantagem dessa verificação é que não há um caso especial para a coordenada 0,0. Infelizmente, verificou-se que mover o ponto pode deslocá-lo para um quadrante diferente e isso significa que um segundo movimento deve ser suprimido, caso esse quadrante seja verificado novamente, o que provavelmente nega a vantagem.
Exemplo 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.
Exemplo 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.
No programa de teste
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)
Diagrama
A imagem a seguir mostra (azul) a área onde x*x>=y*y
, (amarelo) a área onde y<-x
e (verde) a interseção dessas, que é a região em que a transformação correta é a adição de 1 a z
.