Rotasi Chebyshev nyata

15

Ini adalah tantangan yang terinspirasi oleh Rotasi Chebyshev . Saya sarankan mencari jawaban di sana untuk mendapatkan inspirasi untuk tantangan ini.

Diberi titik di pesawat ada kotak unik (persegi panjang dengan sisi yang sama) yang berpusat pada titik asal dan memotong titik itu ( demo interaktif ):

masukkan deskripsi gambar di sini

Diberi titik p dan jarak d , kembalikan titik yang diperoleh dengan memindahkan jarak d dari p , berlawanan arah jarum jam (dan searah jarum jam untuk negatif d ), di sepanjang perimeter dari persegi yang berpusat pada titik asal yang memotong p . Jawaban Anda harus akurat hingga setidaknya 4 digit desimal.

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)

Kasus uji berikut berasal dari tantangan asli oleh Martin Ender, dan semuanya dengan 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
sumber
Tidak bisakah hampir semua ini hanya sedikit berubah dari tantangan lain? Ini sepertinya tambahan yang tidak perlu.
ATaco
1
@ ASaco Tidak, ini sedikit lebih rumit.
orlp
Haruskah jarak dihitung di sepanjang perimeter mulai dari p?
Gábor Fekete
@ GáborFekete Apa lagi?
orlp
Ya saya melihat, kasus uji menyiratkan ini tetapi tidak dinyatakan secara eksplisit. Saya pikir pada awalnya bahwa itu akan mulai pada persimpangan positif pada sumbu x.
Gábor Fekete

Jawaban:

4

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

Woo, 130 byte hilang! Terima kasih kepada Neil karena telah menyimpan 4 byte, Nathan Merrill karena telah menyimpan 2 byte, dan xnor karena telah menyimpan 23 byte yang konyol!

Ide umumnya adalah ini: Kita dapat mengurangi jarak yang ditempuh dengan mengambil modulusnya terhadap perimeter persegi. Perimeter didefinisikan sebagai 8 kali terbesar dari dua koordinat, karena titik harus berada di atasnya. Kemudian, setelah modulus diambil, kami dijamin tidak memiliki tumpang tindih. Ini juga menjamin kita hanya perlu bergerak berlawanan arah jarum jam, karena modulus memberikan hasil positif.

Dari sana, saya hanya menggunakan apa yang kita ketahui dari koordinat x dan y yang diberikan untuk mencari tahu di mana kita berada: atas, bawah, kiri, kanan, atau di sudut, dan menentukan arah, yang dapat menjadi salah satu dari 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'

Setelah ini, sesederhana pengulangan sementara kita masih memiliki jarak untuk melakukan perjalanan, dan berdasarkan arah kita kurangi atau tambahkan ke koordinat yang sesuai, dan beri tahu pengulangan ke arah mana kita akan pergi berikutnya.

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)

Meskipun cukup lama, itu pasti berhasil. Inilah beberapa contoh 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

Cobalah online atau jalankan test case .

Kade
sumber
Apakah s=max(x,y,-x,-y)bekerja?
Neil
@Neil Ya, terima kasih banyak!
Kade
(s>0)*(d>0)adalah s>0<d. Outputnya bisa "%.4f "*2%tuple(p). if s:d=d%(8*s)bisa d%(s*8or 1). (r+1)bisa ~-r. 1*(x>-s)bisa saja (x>-s). abs(y)==abs(x)bisay*y==x*x
xnor
@ xnor Wow, terima kasih! Hanya aku yang berubah yang (x>-s)tidak membutuhkan tanda kurung, dan ~-rpengurangan, jadi aku gunakan -~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]

Penjelasan: Bekerja dengan mencoba menambahkan vektor arah sambil tetap dalam batas-batas alun-alun. Setiap overshoot secara rekursif dilewatkan kembali dengan arah diputar berlawanan arah jarum jam sebesar 90 °. Arah sebenarnya dikodekan menggunakan bendera vertikal vdan satuan wsehingga vektor (1, 0), (0, 1), (-1, 0) dan (0, -1) dikodekan dengan v0, 1, 0 , 1 dan w1, 1, -1, -1 masing-masing. Vektor arah mungkin awalnya tidak menunjuk ke arah yang sesuai tetapi tidak pernah menunjuk ke belakang sehingga pada akhirnya akan berputar ke arah yang dapat digunakan.

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
sumber
Ini bisa jadi karena browser saya (Opera 40.0.2308.81), tetapi sepertinya memiliki sedikit kesalahan pembulatan karena f(42.234, 234.12, 2303.34) -> [-234.12, 80.09399999999988]artinya tidak memiliki presisi 4 digit. Mungkin menambahkan beberapa format output akan memperbaikinya? Jawaban yang bagus! :)
Kade
@ Shebang Secara teknis format keluaran akan membutuhkan pembulatan, dan oleh karena itu memperkenalkan kesalahan pembulatan potensial. Angka-angka yang dihasilkan adalah yang paling dekat dalam batas aritmatika floating-point, yang seharusnya tidak diharapkan memberikan hasil yang tepat untuk representasi desimal sewenang-wenang. Tetap pada fraksi biner jika Anda menginginkan jawaban yang tepat.
Neil