Rotazione di Chebyshev reale


15

Questa è una sfida ispirata alla rotazione di Chebyshev . Suggerisco di cercare le risposte lì per trarre ispirazione per questa sfida.

Dato un punto sul piano c'è un quadrato unico (un rettangolo con lati uguali) che è centrato sull'origine e interseca quel punto ( demo interattiva ):

inserisci qui la descrizione dell'immagine

Dato un punto p e una distanza d , restituisce il punto ottenuto spostando la distanza d da p , in senso antiorario (e in senso orario per d negativa ), lungo il perimetro del quadrato centrato sull'origine che interseca p . La tua risposta deve essere accurata con almeno 4 cifre decimali.

Casi test:

(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)

I seguenti casi di test sono tratti dalla sfida originale di Martin Ender e tutti sono con 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)

Quasi tutti questi non potrebbero essere leggermente modificati dall'altra sfida? Sembra un'aggiunta inutile.
ATaco,

1
@ATaco No, è un po 'più complicato.
orlp,

La distanza dovrebbe essere calcolata lungo il perimetro a partire da p?
Gábor Fekete,

@ GáborFekete Cos'altro?
orlp

Sì, vedo, i casi di test implicano questo, ma non è indicato esplicitamente. All'inizio ho pensato che sarebbe iniziato all'intersezione positiva sull'asse x.
Gábor Fekete,

Risposte:


4

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

Woo, 130 byte persi! Grazie a Neil per aver salvato 4 byte, Nathan Merrill per aver salvato 2 byte e xnor per aver salvato un ridicolo 23 byte!

L'idea generale è questa: possiamo ridurre la distanza percorsa prendendo il suo modulo contro il perimetro del quadrato. Il perimetro è definito come 8 volte la più grande delle due coordinate, poiché il punto deve poggiare su di esso. Quindi, dopo che il modulo è stato preso, ci viene garantito che non ci sono sovrapposizioni. Garantisce inoltre che dobbiamo sempre muoverci in senso antiorario, poiché il modulo dà un risultato positivo.

Da lì, uso semplicemente ciò che sappiamo dalle coordinate x e y per capire dove siamo: in alto, in basso, a sinistra, a destra o in un angolo e determinare la direzione, che può essere una delle seguenti 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'

Dopodiché, è semplice come il loop mentre abbiamo ancora distanza da percorrere e in base alla direzione che sottraggiamo o aggiungiamo alla coordinata appropriata, e indica al loop quale direzione stiamo andando avanti.

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)

Anche se abbastanza lungo, sicuramente funziona. Ecco alcuni esempi di I / O:

[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

Provalo online o esegui test case .


Funziona s=max(x,y,-x,-y)?
Neil,

@Neil Lo fa, grazie mille!
Kade,

(s>0)*(d>0)lo è s>0<d. L'output può essere "%.4f "*2%tuple(p). if s:d=d%(8*s)può essere d%(s*8or 1). (r+1)può essere ~-r. 1*(x>-s)può essere (x>-s). abs(y)==abs(x)può esserey*y==x*x
xnor

@xnor Wow, grazie! Solo le cose che ho cambiato sono che (x>-s)non avevano bisogno della parentesi e dei ~-rdecrementi, quindi l'ho usato -~r.
Kade,

3

JavaScript (ES6), 147 byte

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]

Spiegazione: Funziona tentando di aggiungere il vettore di direzione mantenendo i limiti del quadrato. Qualsiasi superamento viene ricorsivamente ricondotto con la direzione ruotata in senso antiorario di 90 °. La direzione viene effettivamente codificata usando una bandiera verticale ve un'unità in wmodo che i vettori (1, 0), (0, 1), (-1, 0) e (0, -1) siano codificati con v0, 1, 0 , 1 e w1, 1, -1, -1 rispettivamente. Il vettore di direzione potrebbe inizialmente non puntare in una direzione adatta ma non punta mai all'indietro, quindi alla fine ruoterà in una direzione utilizzabile.

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

Ciò potrebbe essere dovuto al mio browser (Opera 40.0.2308.81), ma sembra che abbia un po 'di errore di arrotondamento nel f(42.234, 234.12, 2303.34) -> [-234.12, 80.09399999999988]senso che non ha una precisione di 4 cifre. Forse l'aggiunta di un po 'di formattazione dell'output potrebbe risolvere questo problema? Bella risposta però! :)
Kade,

@Shebang La formattazione dell'output tecnico richiederebbe arrotondamenti e quindi introdurre un potenziale errore di arrotondamento. I numeri generati sono il più vicino possibile entro i limiti dell'aritmetica in virgola mobile, che non dovrebbe prevedere risultati esatti per rappresentazioni decimali arbitrarie. Attenersi alle frazioni binarie se si desidera risposte esatte.
Neil,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.