且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

需要帮助更改算法

更新时间:2021-12-09 06:06:09

让我们将其转换为简单的点序列.

Let's turn this into a simple sequence of points.

我们知道我们将朝四个方向之一前进.

We know that we are going in one of four directions.

var steps = new (int dx, int dy)[] { (1, 0), (0, 1), (-1, 0), (0, -1) };

要创建螺旋,我们将第一个方向移动一次,然后将第二个方向移动一次;然后是接下来的两次,然后是接下来的两个三倍,然后是接下来的两个四倍,依此类推.如果我们到达列表的末尾,那么我们将循环回到起点.因此,如果我们以 n = 0 开始,那么我们将每个方向重复 n/2 + 1 次(知道这是整数数学).

To create a spiral we move the first direction once, then the second once; then the next two twice, then the next two three times, then the next two four times, etc. If we hit the end of the list we then cycle back to the start. So if we start with n = 0 then we repeat each direction n / 2 + 1 times (knowing that this is integer maths).

这是我的 Spiral 生成器方法:

public IEnumerable<Point> Spiral(int x, int y)
{
    yield return new Point(x, y);
    var steps = new(int dx, int dy)[] { (1, 0), (0, 1), (-1, 0), (0, -1) };
    var i = 0;
    var n = 0;
    while (true)
    {
        for (var j = 0; j < n / 2 + 1; j++)
        {
            var (sx, sy) = steps[i];
            x += sx;
            y += sy;
            yield return new Point(x, y);
        }
        if (++i >= steps.Length)
            i = 0;
        n++;
    }
}

前50个点(即 Spiral(0,0).Take(50))是这样的:

The first 50 points (i.e. Spiral(0, 0).Take(50)) are then this:

(0,0),(1,0),(1,1),(0,1),(-1,1),(-1,0),(-1,-1),(0,-1),(1,-1),(2,-1),(2,0),(2,1),(2,2),(1,2),(0,2),(-1,2),(-2,2),(-2,1),(-2,0),(-2,-1),(-2,-2),(-1,-2),(0,-2),(1,-2),(2,-2),(3,-2),(3,-1),(3、0),(3、1),(3,2),(3,3),(2,3),(1,3),(0,3),(-1,3),(-2,3),(-3,3),(-3,2),(-3,1),(-3,0),(-3,-1),(-3,-2),(-3,-3),(-2,-3),(-1,-3),(0,-3),(1,-3),(2,-3),(3,-3),(4,-3)

(0, 0), (1, 0), (1, 1), (0, 1), (-1, 1), (-1, 0), (-1, -1), (0, -1), (1, -1), (2, -1), (2, 0), (2, 1), (2, 2), (1, 2), (0, 2), (-1, 2), (-2, 2), (-2, 1), (-2, 0), (-2, -1), (-2, -2), (-1, -2), (0, -2), (1, -2), (2, -2), (3, -2), (3, -1), (3, 0), (3, 1), (3, 2), (3, 3), (2, 3), (1, 3), (0, 3), (-1, 3), (-2, 3), (-3, 3), (-3, 2), (-3, 1), (-3, 0), (-3, -1), (-3, -2), (-3, -3), (-2, -3), (-1, -3), (0, -3), (1, -3), (2, -3), (3, -3), (4, -3)

现在,生成所需螺旋非常容易.

Now, it's super easy to generate the spiral you want.

如果我假设您是从屏幕中间开始的,那么就是这样:

If I assume that you're starting at the middle of the screen, then this is it:

IEnumerable<Point> query =
    Spiral(1920 / 2, 1080 / 2)
        .Where(z => z.X >= 0 && z.X < 1920)
        .Where(z => z.Y >= 0 && z.Y < 1080)
        .Take(1920 * 1080);

如果我们要使用您的问题中给出的较小屏幕进行验证,则该代码应如下所示:

If we want to verify with the smaller screen as given in your question, the that looks like this:

IEnumerable<Point> query =
    Spiral(0, 0)
        .Where(z => z.Y >= -1 && z.Y <= 1)
        .Where(z => z.X >= -2 && z.X <= 2)
        .Take(5 * 3);

给出:

(0,0),(1,0),(1,1),(0,1),(-1,1),(-1,0),(-1,-1),(0,-1),(1,-1),(2,-1),(2,0),(2,1),(-2,1),(-2,0),(-2,-1)

(0, 0), (1, 0), (1, 1), (0, 1), (-1, 1), (-1, 0), (-1, -1), (0, -1), (1, -1), (2, -1), (2, 0), (2, 1), (-2, 1), (-2, 0), (-2, -1)


这里将其包装为一个方法:


Here it is wrapped up in a single method:

public static void Spiral()
{
    IEnumerable<Point> SpiralPoints(int x, int y)
    {
        yield return new Point(x, y);
        var steps = new(int dx, int dy)[] { (1, 0), (0, 1), (-1, 0), (0, -1) };
        var i = 0;
        var n = 0;
        while (true)
        {
            for (var j = 0; j < n / 2 + 1; j++)
            {
                var (sx, sy) = steps[i];
                x += sx;
                y += sy;
                yield return new Point(x, y);
            }
            if (++i >= steps.Length)
                i = 0;
            n++;
        }
    }

    var w = Screen.PrimaryScreen.Bounds.Width;
    var h = Screen.PrimaryScreen.Bounds.Height;
    var l = Screen.PrimaryScreen.Bounds.Left;
    var r = Screen.PrimaryScreen.Bounds.Right;
    var t = Screen.PrimaryScreen.Bounds.Top;
    var b = Screen.PrimaryScreen.Bounds.Bottom;

    foreach (Point point in SpiralPoints(w / 2, h / 2)
        .Where(z => z.X >= l && z.X < r)
        .Where(z => z.Y >= t && z.Y < b)
        .Take(w * h))
    {
        /* Do Stuff With Each Point Here */
    }

}