确定以0,0为中心并以原点为中心螺旋增加的网格坐标的索引

时间:2015-06-12 21:19:23

标签: math

这是以下相反的问题:

Determine position of number in a grid of numbers centered around 0 and increasing in spiral

这两种方式是: index - >坐标(完成,见上面的问题) 坐标 - > index(我的问题)

我坚持的部分是从原始坐标获取扇区而没有庞大的丑陋逻辑分支。

是否有一种简单的算术方法来确定扇区?如何反转此函数以获取坐标对并返回索引?

3 个答案:

答案 0 :(得分:2)

如果你在螺旋线上绘制素数的位置,这是一个Ulam spiral它有一些有趣的属性。

25|26|27|28|29|30
24| 9|10|11|12|31
23| 8| 1| 2|13|32
22| 7| 0| 3|14|33
21| 6| 5| 4|15|34
20|19|18|17|16|35
 ........     |36

首先要注意的是方形数字的位置。它们位于对角线上,左上对角线为奇数方块,右下对角线为偶数方块。

25|  |  |  |  |  
  | 9|  |  |  |
  |  | 1|  |  |
  |  | 0|  |  |
  |  |  | 4|  |
  |  |  |  |16|
 ........     |36

让我们看看这些坐标(x,y)

的对角线
 (-2,3)|       |      |      |      | (3,3)  
       | (-1,2)|      |      | (2,2)|
       |       | (0,1)| (1,1)|      |
       |       | (0,0)|      |      |
       |(-1,-1)|      |(1,-1)|      |
(-2,-2)|       |      |      |(2,-2)|
       |       |      |      |      |(3,-3)

首先注意对角线,如果y> = 0且x = 1-y,我们位于左上角,值为(2 y-1)^2(1-2x)^2

如果y <0且x = -y,我们在右下对角线,值为(2x)^ 2 = 4x ^ 2或(-2y)^ 2 = 4y ^ 2.

如果y&gt; = 0且x&gt; = 1-y,xpos = x + y-1,我们在顶部的水平行上。该值为(2 y-1)^2 + pos

底部的水平行具有y <0且x> = y,x <= - y。平方数左边的步数是pos = -x-y。值为4y^2+pos

类似的计算适用于垂直行。这些都可以在函数

中编码
function spiral(x,y) {
    var pos,squ;
    // Horizontal row at top
    if(y>=0 && ( x >= 1-y && x<y ) ) {
        pos = x+y-1;
        squ = (2 *y-1)*(2*y-1);
    // Horizontal row at bottom
    } else if( y < 0 && ( x >= y && x<= -y ) ) {
        pos = -x-y;
        squ = 4*y*y;
    // Vertical row on right
    } else if( x >0 ) {
        pos = -x-y;
        squ = 4*x*x;
    // Vertical row on left
    } else {
        squ = (1-2*x)*(1-2*x);
        pos = x+y-1;
    }
    return squ+pos;
}

我在fiddle进行了javascript实施。这样就可以将数字螺旋上升到99.

稍微简单的功能是

spiral = function(x,y) {
    var res;
    var u = x+y;
    var v = x-y;
    if(u>0) {
        if(v>=0) {
            x <<= 1;
            res = x*(x-1) + v;
        } else {
            y <<= 1;
            res = y*(y-1) + v;
        }
    } else {
        if(v<0) {
            x <<= 1;
            res = -x*(1-x) - v;
        } else {
            y <<= 1;
            res = -y*(1-y) - v;
        }
    }
    return res;
}

在这里,你告诉你在对角线方向上的移动距离。两个数字的符号告诉您您所在的行业。我们可以通过查找x = y行上的值来获取每个水平/垂直边的基数。去东北方向的是2,12,30(即1 * 2,3 * 4,5 * 6),西南方向是6,20,42(即2 * 3,4 * 5,6 *) 7)。这些方程是2*x*(2*x-1)-2*x*(1-2*x)或使用y相同。为了获得每个点的索引,我们可以简单地将v添加或减去这些索引。

这使用1次乘法,2次比较,1位移位和4次加法。有可能删除其中一个添加内容,但我相信你需要一个乘法和2个比较。

答案 1 :(得分:0)

考虑在不改变方向的情况下采取的步数。您会发现该序列为1,1,2,2,3,3,4,4,5,5 ......模式应该是显而易见的。现在经过四条这样的直边后,你几乎回到了同一个角落。因此,您可以找到连接这些角的线的索引:

c0: 0,       1+1+2+2, …+3+3+4+4, …+5+5+6+6, …+7+7+8+8, …
c1: 1,     …+1+2+2+3, …+3+4+4+5, …
c2: 1+1,   …
c3: 1+1+2, …

对于其中每一项,您都可以编写公式。第一个是这样的:

c0[i] = sum((2*i - 1) + (2*i - 1) + (2*i) + (2*i)) = sum(8*i - 2)

现在ask Wolfram Alpha。它会告诉你

c0[i] = 4i² + 2i

因此,如果有人为您提供索引 n ,您可以通过solving the above equation for i解决上次访问该边缘线的问题,采取正解决方案,然后将其四舍五入为整数。您可以对其他边缘线执行相同操作,或者在最坏的情况下接受围绕中心旋转一整圈。整个回合意味着四个星际区域,你不想一个接一个地去。

Wolfram Alpha还打印序列的前几个元素:6,20,42,72,110。您可以将其用于look this up in OEIS,并查找注释中的A002943

  

以顺时针方向螺旋写入0,1,2,...序列在4个对角线中的一个上给出数字。

但我可以向你保证,它适用于逆时针螺旋... ...

答案 2 :(得分:0)

这将是一个很晚的答案,但我还是要回答,因为我本人已经遇到了这个确切的问题,却从未真正找到解决其他问题的可靠方法。这是对所有其他答案的免费解答,因为为什么不这样做

以下是我找到的解决方案的伪代码:

// n is the number in the spiral at (x, y)
// m is an intermediate step towards calculating n
m = 2 * max(abs(x), abs(y)) - (x > -y) // this relies on booleans being evaluated as 0 or 1
n = m^2 + abs(x + (-1)^m * floor((m + 1) / 2)) + abs(y - (-1)^m * floor(m / 2))

在Python 3中:(最新测试在3.7.0中进行)

import math

def number_in_spiral(x, y):
    m = 2 * max(abs(x), abs(y)) - (x > -y)
    return m * m + abs(x + pow(-1, m) * math.floor((m + 1) / 2)) + \
                   abs(y - pow(-1, m) * math.floor(m / 2))

在JavaScript中:

function number_in_spiral(x, y)
{
    var m = 2 * Math.max(Math.abs(x), Math.abs(y)) - (x > -y);
    return m * m + Math.abs(x + Math.pow(-1, m) * Math.floor((m + 1) / 2)) + 
                   Math.abs(y - Math.pow(-1, m) * Math.floor(m / 2));
}

请记住,此公式中的y向上增加,在很多情况下并不理想。在这种情况下,可以在公式的每个实例中将输入y乘以-1,或将y替换为-y。

我希望这对某人有用。如果不是这样,当我不可避免地从4年后回到这个问题时,这至少对我有用。