For example, here is the shape of intended spiral (and each step of the iteration)
y
|
|
16 15 14 13 12
17 4 3 2 11
-- 18 5 0 1 10 --- x
19 6 7 8 9
20 21 22 23 24
|
|
Where the lines are the x and y axes.
Here would be the actual values the algorithm would "return" with each iteration (the coordinates of the points):
[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]..
etc.
I've tried searching, but I'm not exactly sure what to search for exactly, and what searches I've tried have come up with dead ends.
I'm not even sure where to start, other than something messy and inelegant and ad-hoc, like creating/coding a new spiral for each layer.
Can anyone help me get started?
Also, is there a way that can easily switch between clockwise and counter-clockwise (the orientation), and which direction to "start" the spiral from? (the rotation)
Also, is there a way to do this recursively?
My application
I have a sparse grid filled with data points, and I want to add a new data point to the grid, and have it be "as close as possible" to a given other point.
To do that, I'll call grid.find_closest_available_point_to(point)
, which will iterate over the spiral given above and return the first position that is empty and available.
So first, it'll check point+[0,0]
(just for completeness's sake). Then it'll check point+[1,0]
. Then it'll check point+[1,1]
. Then point+[0,1]
, etc. And return the first one for which the position in the grid is empty (or not occupied already by a data point).
There is no upper bound to grid size.
I have an algorithm in java that outputs a similar output to yours, except that it prioritizes the number on the right, then the number on the left.
This is the javascript solution based on the answer at Looping in a spiral
fiddle: http://jsfiddle.net/N9gEC/18/
Try searching for either parametric or polar equations. Both are suitable to plotting spirally things. Here's a page that has plenty of examples, with pictures (and equations). It should give you some more ideas of what to look for.
I've done pretty much the same thin as a training exercise, with some differences in the output and the spiral orientation, and with an extra requirement, that the functions spatial complexity has to be O(1).
After think for a while I came to the idea that by knowing where does the spiral start and the position I was calculating the value for, I could simplify the problem by subtracting all the complete "circles" of the spiral, and then just calculate a simpler value.
Here is my implementation of that algorithm in ruby:
This is not exactly the thing you asked for, but I believe it'll help you to think your problem
I would solve it using some math. Here is Ruby code (with input and output):
E.g.
And golfed version:
Edit
First try to approach the problem functionally. What do you need to know, at each step, to get to the next step?
Focus on plane's first diagonal
x = y
.k
tells you how many steps you must take before touching it: negative values mean you have to moveabs(k)
steps vertically, while positive mean you have to movek
steps horizontally.Now focus on the length of the segment you're currently in (spiral's vertices - when the inclination of segments change - are considered as part of the "next" segment). It's
0
the first time, then1
for the next two segments (= 2 points), then2
for the next two segments (= 4 points), etc. It changes every two segments and each time the number of points part of that segments increase. That's whatj
is used for.Accidentally, this can be used for getting another bit of information:
(-1)**j
is just a shorthand to "1
if you're decreasing some coordinate to get to this step;-1
if you're increasing" (Note that only one coordinate is changed at each step). Same holds forj%2
, just replace1
with0
and-1
with1
in this case. This mean they swap between two values: one for segments "heading" up or right and one for those going down or left.This is a familiar reasoning, if you're used to functional programming: the rest is just a little bit of simple math.
This problem is best understood by analyzing how changes coordinates of spiral corners. Consider this table of first 8 spiral corners (excluding origin):
By looking at this table we can calculate X,Y of k-th corner given X,Y of (k-1) corner:
Now when you know coordinates of k and k+1 spiral corner you can get all data points in between k and k+1 by simply adding 1 or -1 to x or y of last point. Thats it.
good luck.