Rotation de Chebyshev réel

15

C'est un défi inspiré par la rotation de Chebyshev . Je suggère de chercher des réponses pour trouver l'inspiration pour ce défi.

Étant donné un point sur le plan, il existe un carré unique (un rectangle à côtés égaux) qui est centré sur l'origine et coupe ce point ( démo interactive ):

entrez la description de l'image ici

Étant donné un point p et une distance d , renvoyez le point obtenu en déplaçant la distance d de p , dans le sens inverse des aiguilles d'une montre (et dans le sens des aiguilles d'une montre pour d négatif ), le long du périmètre du carré centré sur l'origine qui coupe p . Votre réponse doit être précise à au moins 4 chiffres décimaux.

Testcases:

(0, 0), 100 -> (0, 0)
(1, 1), 81.42 -> (-0.4200, 1.0000)
(42.234, 234.12), 2303.34 -> (-234.1200, 80.0940)
(-23, -39.234), -234.3 -> (39.2340, -21.8960)

Les cas de test suivants sont issus du défi original de Martin Ender, et tous sont avec d = 1 :

(0, 0)       -> (0, 0)
(1, 0)       -> (1, 1)
(1, 1)       -> (0, 1)
(0, 1)       -> (-1, 1)
(-1, 1)      -> (-1, 0)
(-1, 0)      -> (-1, -1)
(-1, -1)     -> (0, -1)
(0, -1)      -> (1, -1)
(1, -1)      -> (1, 0)
(95, -12)    -> (95, -11)
(127, 127)   -> (126, 127)
(-2, 101)    -> (-3, 101)
(-65, 65)    -> (-65, 64)
(-127, 42)   -> (-127, 41)
(-9, -9)     -> (-8, -9)
(126, -127)  -> (127, -127)
(105, -105)  -> (105, -104)
orlp
la source
La quasi-totalité de ces éléments ne pourrait-elle être que légèrement modifiée par rapport à l'autre défi? Cela semble être un ajout inutile.
ATaco
1
@ATaco Non, c'est un peu plus compliqué.
orlp
La distance doit-elle être calculée le long du périmètre à partir de p?
Gábor Fekete
@ GáborFekete Quoi d'autre?
orlp
Oui, je vois, les cas de test impliquent cela, mais ce n'est pas indiqué explicitement. J'ai d'abord pensé que cela commencerait à l'intersection positive sur l'axe des x.
Gábor Fekete

Réponses:

4

Python 2, 363 335 296 266 262 258 256 233 octets

Woo, 130 octets perdus! Merci à Neil pour avoir sauvé 4 octets, Nathan Merrill pour avoir sauvé 2 octets et xnor pour avoir sauvé 23 octets ridicules!

L'idée générale est la suivante: on peut réduire la distance parcourue en prenant son module contre le périmètre du carré. Le périmètre est défini comme 8 fois la plus grande des deux coordonnées, car le point doit reposer dessus. Ensuite, une fois le module pris, nous sommes garantis de ne pas avoir de chevauchement. Cela garantit également que nous ne devons jamais bouger dans le sens antihoraire, car le module donne un résultat positif.

À partir de là, j'utilise simplement ce que nous savons des coordonnées x et y données pour déterminer où nous sommes: en haut, en bas, à gauche, à droite ou dans un coin, et déterminer la direction, qui peut être l'une des suivantes 0, 1, 2, 3:

0 --> we are on the 'top', moving 'left'
1 --> we are on the 'left', moving 'down'
2 --> we are on the 'bottom', moving 'right'
3 --> we are on the 'right', moving 'up'

Après cela, c'est aussi simple que de boucler pendant que nous avons encore de la distance à parcourir, et en fonction de la direction que nous soustrayons ou ajoutons aux coordonnées appropriées, et indiquons à la boucle dans quelle direction nous allons.

p,d=input()
x,y=p
s=max(x,y,-x,-y)
d=d%(s*8or 1)
r=[(y<s)*[2,[3,x>-s][x<s]][y>-s],[2*(y<0),3*(y<=0)][x>0]][y*y==x*x]
while s>0<d:f=1-2*(r<2);m=abs(f*s-p[r%2]);j=d>m;p[r%2]=[p[r%2]+f*d,f*s][j];r=-~r%4;d=(d-m)*j
print"%.4f "*2%tuple(p)

Bien que cela soit assez long, cela fonctionne certainement. Voici quelques exemples d'E / S:

[0, 0], 100 --> 0.0000 0.0000
[1, 1], 81.42 --> -0.4200 1.0000
[42.234, 234.12], 2303.34 --> -234.1200 80.0940
[-23, -39.234], -234.3 --> 39.2340 -21.8960

Essayez-le en ligne ou exécutez des cas de test .

Kade
la source
Ça s=max(x,y,-x,-y)marche?
Neil
@Neil Oui, merci beaucoup!
Kade
(s>0)*(d>0)est s>0<d. La sortie peut être "%.4f "*2%tuple(p). if s:d=d%(8*s)peut être d%(s*8or 1). (r+1)peut être ~-r. 1*(x>-s)peut être juste (x>-s). abs(y)==abs(x)peut êtrey*y==x*x
xnor
@xnor Wow, merci! Seuls les maigres que j'ai modifiés sont ceux qui (x>-s)n'avaient pas besoin des parenthèses et des ~-rdiminutions, alors j'ai utilisé -~r.
Kade
3

JavaScript (ES6), 147 octets

f=(x,y,d,s=Math.max(x,y,-x,-y),c=(d/8%s+s)%s*8,v=0,w=x+y>0?1:-1,b=(v?x:y)*w+c-s)=>c?b>0?f(v?s*w:x,v?y:s*w,d,s,b,!v,v?w:-w):[x+c*w*v,y+c*w*!v]:[x,y]

Explication: fonctionne en essayant d'ajouter le vecteur de direction tout en restant dans les limites du carré. Tout dépassement est récursivement renvoyé avec la direction tournée dans le sens antihoraire de 90 °. La direction est réellement encodée en utilisant un drapeau vertical vet une unité de wsorte que les vecteurs (1, 0), (0, 1), (-1, 0) et (0, -1) soient encodés avec vde 0, 1, 0 , 1 et wde 1, 1, -1, -1 respectivement. Le vecteur de direction peut ne pas pointer initialement dans une direction appropriée mais il ne pointe jamais vers l'arrière, il finira par tourner dans une direction utilisable.

f=(x,y,d,                   Input parameters
 s=Math.max(x,y,-x,-y),     Calculate half the side of the square
 c=(d/8%s+s)%s*8,           Reduce the distance modulo the perimeter
 v=0,                       Initial vertical flag
 w=x+y>0?1:-1,              Initial direction
 b=(v?x:y)*w+c-s)=>         Will we overshoot the corner?
  c?b>0?f(v?s*w:x,v?y:s*w,  Advance to the next corner
          d,s,b,!v,v?w:-w): Rotate the direction
        [x+c*w*v,y+c*w*!v]: Advance the remaining amout
    [x,y]                   Nothing to do, zero input
Neil
la source
Cela pourrait être dû à mon navigateur (Opera 40.0.2308.81), mais il semble qu'il présente une erreur d'arrondi, f(42.234, 234.12, 2303.34) -> [-234.12, 80.09399999999988]ce qui signifie qu'il n'a pas une précision de 4 chiffres. Peut-être que l'ajout d'un formatage de sortie pourrait résoudre ce problème? Belle réponse cependant! :)
Kade
@Shebang La mise en forme de sortie technique nécessiterait l'arrondi et, par conséquent, introduirait une erreur d'arrondi potentielle. Les nombres générés sont les plus proches possibles dans les limites de l'arithmétique à virgule flottante, ce qui ne devrait pas donner des résultats exacts pour les représentations décimales arbitraires. Tenez-vous aux fractions binaires si vous voulez des réponses exactes.
Neil