Rubí, 68
La función Lambda toma un número complejo como argumento, devuelve un número complejo.
->z{k=1
4.times{z*=?i.to_c
x,y=z.rect
y*y>=x*x&&y<-x&&(z+=k;k=0)}
z}
Rotamos el punto 90 grados 4 veces multiplicando por i
. Por lo tanto, pasa a través de los 4 cuadrantes, y se devolvería sin cambios, excepto por el hecho de que lo modificamos cuando está en uno específico de ellos. El hecho de que siempre se modifique en el mismo cuadrante simplifica la modificación.
Es más fácil de seguir si lo modificamos z
cuando está en el cuadrante derecho. en este caso, necesitamos aumentar la coordenada y en 1 (es decir, agregar i
a z
).
Verificamos x.abs>=y.abs
comparando los cuadrados de x
y y
. Esto nos dice que el punto está en el cuadrante derecho o izquierdo, no arriba o abajo. Para comprobar que es, de hecho, en el cuadrante derecha, comprobamos también que x>y
(estrictamente mayor porque queremos excluir el caso x=y
que pertenece al cuadrante "top".) Cuando esto es cierto añadimos i
a z
.
Por razones de golf, agregar i
no es deseable. En su lugar, modificamos el número cuando está en el cuadrante inferior, en cuyo caso tenemos que agregar 1 a la x
coordenada (agregar 1 a z
). En este caso, comprobamos que y*y>=x*x
para verificar que esté en el cuadrante superior o inferior. Para asegurarnos de que esté en el cuadrante inferior, debemos verificar y<-x
(excluyendo estrictamente el caso de la esquina inferior derecha donde y=-x
).
Una ventaja de esta comprobación es que no hay un caso especial para la coordenada 0,0. Desafortunadamente, se descubrió que mover el punto puede desplazarlo a un cuadrante diferente y esto significa que se debe suprimir un segundo movimiento en caso de que se vuelva a verificar ese cuadrante, lo que probablemente niega la ventaja.
Ejemplo 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.
Ejemplo 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.
En programa de prueba
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
La siguiente imagen muestra (azul) el área donde x*x>=y*y
, (amarillo) el área donde y<-x
y (verde) la intersección de estos, que es la región donde la transformación correcta es la suma de 1 a z
.