真正的切比雪夫旋转


15

这是受Chebyshev Rotation启发的挑战。我建议在那里查看答案以从中获得灵感。

给定平面上的一个点,存在一个以原点为中心并与该点相交的唯一正方形(边长相等的矩形)(Interactive demo):

在此处输入图片说明

给定一个点p和距离d,返回由移动距离获得的点dp,逆时针(顺时针和负 d),沿方形的周边围绕原点相交p。您的答案必须精确到至少4个十进制数字。

测试用例:

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

@GáborFekete还有什么?
orlp

是的,我知道,测试用例暗示了这一点,但并未明确说明。我最初以为它将从x轴的正交点开始。
加博尔·费克特(GáborFekete)

Answers:


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的确如此,谢谢大家!
卡德,2016年

(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
卡德

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)与编码v的0,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从技术上讲,输出格式将需要取整,因此会导致潜在的取整错误。生成的数字在浮点运算的范围内是最接近的,不应期望对任意十进制表示形式给出准确的结果。如果需要确切的答案,请坚持使用二进制分数。
尼尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.