การหมุน Chebyshev จริง


15

นี่คือความท้าทายแรงบันดาลใจจากเซฟหมุน ฉันขอแนะนำให้ดูคำตอบที่นั่นเพื่อรับแรงบันดาลใจสำหรับความท้าทายนี้

เมื่อกำหนดจุดบนระนาบจะมีจตุรัสที่ไม่ซ้ำใคร (สี่เหลี่ยมผืนผ้าที่มีด้านเท่ากัน) ที่มีศูนย์กลางอยู่ที่จุดกำเนิดและจุดตัด ( การสาธิตเชิงโต้ตอบ ):

ป้อนคำอธิบายรูปภาพที่นี่

กำหนดจุดPและระยะdกลับมาจุดที่ได้รับโดยการย้ายระยะdจากP , ทวนเข็มนาฬิกา (ตามเข็มนาฬิกาและเชิงลบ d ) พร้อมปริมณฑลของตารางที่มีศูนย์กลางอยู่ที่จุดเริ่มต้นที่ตัดพี คำตอบของคุณจะต้องแม่นยำอย่างน้อย 4 หลักทศนิยม

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)

กรณีทดสอบต่อไปนี้มาจากความท้าทายเริ่มต้นโดย Martin Ender และทุกอย่างอยู่ที่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)

ไม่สามารถเปลี่ยนแปลงทั้งหมดนี้ได้เพียงเล็กน้อยจากความท้าทายอื่น ๆ ดูเหมือนว่าจะเป็นการเพิ่มที่ไม่จำเป็น
ATaco

1
@ ATaco ไม่มันค่อนข้างซับซ้อนกว่านิดหน่อย
orlp

ควรคำนวณระยะทางตามเส้นรอบวงเริ่มต้นที่ p หรือไม่
Gábor Fekete

@GáborFeketeมีอะไรอีกบ้าง?
orlp

ใช่ฉันเห็นว่ากรณีทดสอบบ่งบอกถึงสิ่งนี้ แต่มันไม่ได้ระบุอย่างชัดเจน ตอนแรกฉันคิดว่ามันจะเริ่มที่จุดตัดบวกที่แกน x
Gábor Fekete

คำตอบ:


4

Python 2, 363 335 296 266 262 258 256 233 ไบต์

แสวงหาหายไป 130 ไบต์! ขอบคุณ Neil สำหรับการบันทึก 4 ไบต์, Nathan Merrill สำหรับการบันทึก 2 ไบต์และ xnor สำหรับการบันทึก 23 ไบต์ที่ไร้สาระ!

แนวคิดทั่วไปคือสิ่งนี้: เราสามารถลดระยะทางที่เดินทางได้โดยการนำโมดูลัสของมันเทียบกับเส้นรอบวงของสี่เหลี่ยมจัตุรัส เส้นรอบวงถูกกำหนดให้เป็น 8 เท่าของพิกัดทั้งสองที่ใหญ่ที่สุดเนื่องจากจุดต้องอยู่บนจุดนั้น จากนั้นหลังจากถ่ายโมดูลัสแล้วเรารับประกันว่าจะไม่ทับซ้อนกัน นอกจากนี้ยังรับประกันว่าเราจะต้องขยับทวนเข็มนาฬิกาเท่านั้นเนื่องจากโมดูลัสให้ผลบวก

จากนั้นฉันก็ใช้สิ่งที่เรารู้จากพิกัด x และ y ที่กำหนดเพื่อหาว่าเราอยู่ที่ไหน: บน, ล่าง, ซ้าย, ขวาหรือในมุมหนึ่งและกำหนดทิศทางซึ่งอาจเป็นหนึ่งใน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'

หลังจากนี้มันง่ายพอ ๆ กับการวนลูปในขณะที่เรายังมีระยะทางในการเดินทางและขึ้นอยู่กับทิศทางที่เราลบหรือเพิ่มพิกัดที่เหมาะสมและบอกลูปทิศทางที่เรากำลังจะไปต่อไป

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)

ในขณะที่ค่อนข้างนานมันได้ผลแน่นอน นี่คือตัวอย่าง 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

ลองมันออนไลน์หรือเรียกใช้กรณีทดสอบ


ไม่s=max(x,y,-x,-y)ทำงานหรือไม่
Neil

@ ไม่มีมันขอบคุณมาก!
Kade

(s>0)*(d>0)s>0<dเป็น "%.4f "*2%tuple(p)เอาท์พุทสามารถ สามารถif s:d=d%(8*s) สามารถ สามารถเป็นได้ สามารถd%(s*8or 1)(r+1)~-r1*(x>-s)(x>-s)abs(y)==abs(x)y*y==x*x
xnor

@xnor ว้าวขอบคุณมาก! เดียวที่ฉันจะเปลี่ยนเรทที่(x>-s)ไม่จำเป็นต้องวงเล็บและการลดลงดังนั้นฉันใช้~-r -~r
Kade

3

JavaScript (ES6), 147 ไบต์

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]

คำอธิบาย: ทำงานโดยพยายามเพิ่มเวกเตอร์ทิศทางในขณะที่อยู่ในขอบเขตของสี่เหลี่ยม การหมุนเกินพิกัดใด ๆ จะถูกส่งกลับแบบวนซ้ำโดยทิศทางหมุนทวนเข็มนาฬิกา 90 ° ทิศทางจะถูกเข้ารหัสโดยใช้ธงแนวตั้งvและหน่วยwเพื่อให้เวกเตอร์ (1, 0), (0, 1), (-1, 0) และ (0, -1) ถูกเข้ารหัสด้วยv0, 1, 0 , 1 และw1, 1, -1, -1 ตามลำดับ เวกเตอร์ทิศทางอาจไม่ได้ชี้ไปในทิศทางที่เหมาะสม แต่เริ่มแรกมันไม่เคยชี้ไปข้างหลังดังนั้นในที่สุดมันจะหมุนไปในทิศทางที่ใช้งานได้

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

อาจเป็นเพราะเบราว์เซอร์ของฉัน (Opera 40.0.2308.81) แต่ดูเหมือนว่ามีข้อผิดพลาดในการปัดเศษเล็กน้อยเนื่องจากf(42.234, 234.12, 2303.34) -> [-234.12, 80.09399999999988]ความหมายมันไม่มีความแม่นยำ 4 หลัก บางทีการเพิ่มการจัดรูปแบบผลลัพธ์บางอย่างอาจช่วยแก้ไขปัญหานี้ได้ คำตอบที่ดีแม้ว่า! :)
Kade

@Shebang เทคนิคการจัดรูปแบบผลลัพธ์จะต้องมีการปัดเศษดังนั้นจึงอาจมีข้อผิดพลาดในการปัดเศษ ตัวเลขที่สร้างขึ้นมีความใกล้เคียงที่สุดที่เป็นไปได้ภายในขอบเขตของเลขคณิตทศนิยมซึ่งไม่ควรคาดหวังว่าจะให้ผลลัพธ์ที่แน่นอนสำหรับการแทนทศนิยมตามอำเภอใจ ติดเศษส่วนแบบไบนารีถ้าคุณต้องการคำตอบที่แน่นอน
Neil
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.