Tower of Hanoi using recursion - recursion

I have no idea about Tower of Hanoi. I want to write a program on this using recursion.

Another homework assignment. Pass your teacher's A to me ;)
Source: http://www.soc.napier.ac.uk/~andrew/hanoi/rechelp.html
Bonus: a step-by-step YouTube video.
A little bit about the Tower of Hanoi
An analysis of this and a discussion of the (invented) mythology and of the four peg version can be found in the rec.puzzles FAQ look for induction/hanoi.s
The Tower of Hanoi problem has a nice recursive solution.
Working out recursive solutions
To solve such problems ask yourself: "if I had solved the n-1 case could I solve the n case?"
If the answer to this question is positive you proceed under the outrageous assumption that the n-1 case has been solved. Oddly enough this works, so long as there is some base case (often when n is zero or one) which can be treated as a special case.
How to move n rings from pole A to pole C?
If you know how to move n-1 rings from one pole to another then simply move n-1 rings to the spare pole - there is only one ring left on the source pole now, simply move it to the destination, then pile the rest of them from the spare pole onto the destination pole.
For example when n is 4...
First move three onto the spare pole (worry how to do this later).
Now move one ring from the source pole to the destination pole.
Now move three rings from the spare pole to the destination pole
(again, we can worry about how to do this later).
We have finished!
More succinctly...
To move n rings from A to C using B as spare:
if n is 1
just do it,
otherwise...
move n-1 rings from A to B using C as spare
move one ring from A to C
move n-1 rings from B to C using A as spare
As with most recursive solutions we have to treat some base case specially - here the base case occurs where we have only one ring to move.
How to do it in C
/* Tower of Hanoi - the answer */
/* How to move four rings from pin 1 to pin 3 using pin 2 as spare */
#include <stdio.h>
void move(n, A, C, B)
/* number to move, source pole, destination pole and
spare pole respectively */
int n, A, B, C; {
if (n == 1) {
printf("Move from %d to %d.\n", A, C);
} else {
move(n - 1, A, B, C);
move(1, A, C, B);
move(n - 1, B, C, A);
}
}
main() {
move(4, 1, 3, 2);
}

Here is a compact implementation in Lisp: http://www.kernelthread.com/projects/hanoi/html/gcl.html. It is certainly recursive, but I did not verify it's correctness.

From Wikipedia:
The Tower of Hanoi or Towers of Hanoi
(also known as The Towers of Brahma)
is a mathematical game or puzzle. It
consists of three rods, and a number
of disks of different sizes which can
slide onto any rod. The puzzle starts
with the disks neatly stacked in order
of size on one rod, the smallest at
the top, thus making a conical shape.
Check out the recursive solution.

#!/usr/bin/env python
discs = 3
T = [range(discs, 0, -1), [], []]
def show_towers():
"""Render a picture of the current state of the towers"""
def render_disc(t, y):
return ("-"*(t[y]*2-1) if y < len(t) else "|").center(discs*2)
for y in range(discs):
print " ".join(render_disc(t, discs-y-1) for t in T)
print "="*(discs*6+3)
def move(n, source, destination):
"""Recursively move n discs from source to destination"""
while n > 0:
temp = 3 - source - destination
move(n-1, source, temp)
T[destination].append(T[source].pop())
show_towers()
n, source = n-1, temp # Simulate tail recursion
show_towers()
move(discs, 0, 2)
output for discs = 3
- | |
--- | |
----- | |
=====================
| | |
--- | |
----- | -
=====================
| | |
| | |
----- --- -
=====================
| | |
| - |
----- --- |
=====================
| | |
| - |
| --- -----
=====================
| | |
| | |
- --- -----
=====================
| | |
| | ---
- | -----
=====================
| | -
| | ---
| | -----
=====================

The Structure and Interpretation of Computer Programs video lectures contain helpful tips on solving this problem and a wealth of knowledge besides.

See wikipedia towers of hanoi article for the description of recursive algorithm.
It goes something like this:
#include <iostream> // ostream
#include <algorithm> // for_each
#include <deque> // I can iterate over towers & print state,<stack> works as well
#include <boost/array.hpp> // just a wrapper for array
#include <boost/lambda/lambda.hpp> // easy one line for_each iterating
using namespace std;
typedef std::deque< int > tower_t; // stack works as well, deque for printing
typedef boost::array< tower_t ,3 > towers_t; // 3 towers
enum peg { A = 0, B = 1, C = 2 };
Printing:
ostream & show(ostream & os, const tower_t & t)
{
os << "[";
for_each (t.begin(), t.end(), os << boost::lambda::_1 );
return os << "]";
}
ostream & show(ostream & os, const towers_t & t)
{
show(os, t[0]); show(os, t[1]); show(os, t[2]);
return os;
}
Solve:
void move(peg from, peg to, towers_t & t)
{
// show move and state before move
cout << "mv: " << t[from].back() << " " << from << " --> " << to << "\t\t";
show(cout, t); cout << " --> ";
// the actual move: move top peg `from` stick `to` stick (and `pop` old top)
t[to].push_back(t[from].back());
t[from].pop_back();
// show state after move
show(cout, t); cout << endl;
}
// move n discs from A to B via C
void move(int n, peg from, peg to, peg via, towers_t & t)
{
if (n == 1) { move(from, to, t); return; }
move(n-1, from, via, to, t);
move(from, to, t);
move(n-1, via, to, from, t);
return;
}
Usage, solve tower with 4 pegs:
int main()
{
towers_t ttt;
tower_t & first_tower(ttt[0]);
first_tower.push_back(4);
first_tower.push_back(3);
first_tower.push_back(2);
first_tower.push_back(1);
move(first_tower.size(), A, C, B, ttt); // move n from A to C via B
}
Solved 3 towers with 4 pegs on the first tower, the biggest peg has the highest number, the smallest one is 1.
Output (mv: PegX FromTower ---> ToTower) followed by state before and after move, each tower from left to right showing pegs from bottom to top - top is on right:
mv: 1 0 --> 1 [4321][][] --> [432][1][]
mv: 2 0 --> 2 [432][1][] --> [43][1][2]
mv: 1 1 --> 2 [43][1][2] --> [43][][21]
mv: 3 0 --> 1 [43][][21] --> [4][3][21]
mv: 1 2 --> 0 [4][3][21] --> [41][3][2]
mv: 2 2 --> 1 [41][3][2] --> [41][32][]
mv: 1 0 --> 1 [41][32][] --> [4][321][]
mv: 4 0 --> 2 [4][321][] --> [][321][4]
mv: 1 1 --> 2 [][321][4] --> [][32][41]
mv: 2 1 --> 0 [][32][41] --> [2][3][41]
mv: 1 2 --> 0 [2][3][41] --> [21][3][4]
mv: 3 1 --> 2 [21][3][4] --> [21][][43]
mv: 1 0 --> 1 [21][][43] --> [2][1][43]
mv: 2 0 --> 2 [2][1][43] --> [][1][432]
mv: 1 1 --> 2 [][1][432] --> [][][4321]

Related

Why can Eva plugin calculate "(a >> 15) & 1" but cannot calculate "(a >> 0) & 1"?

I am trying to analyze a C source code using Eva plugin of Frama-C.
In the following example, I found that Eva can calculate the value of a shift expression in which the right-hand-side value is big, but cannot calculate when the right-hand-side value is small.
extern unsigned char a;
int main() {
int b, c, d;
b = (a >> 15) & 1;
c = (a >> 0) & 1;
d = b + c;
}
In this example above, Eva can calculate the value of b but not c.
Is (a >> 0) & 1 more complex than (a >> 15) & 1 to Eva?
Eva is giving the most precise answer from the initial context where a, an external variable, is in the range [0..255], namely that b is equal to 0 and c may be either 0 or 1.
If you want to explore what is going on, the Values panel at the bottom of of the graphical user interface (launched with frama-c-gui -eva file.c) is the way to go. Its usage is documented in section 4.3 of the Eva user manual, but basically if you click on any (sub)-expression in the normalized code view (the left buffer), the abstract value computed by Eva for this expression at this point will be displayed in the panel.
In your example, we have the following intermediate values for the computation of b:
a -> [0..255]
(int)a -> [0..255] (implicit promotion of an arithmetic operand)
(int)a >> 15 -> {0} (only the first 8 bits might be non 0)
(int)a >> 15 & 1 -> {0} (first argument is 0, the bitwise and is also 0}
For c, the first two steps are identical, but then we have
(int)a >> 0 -> [0..255] (no-op, we have the same values as (int)a)
((int)a >> 0) & 1 -> {0; 1} (in the interval [0..255], we have odd and even values, hence the result of the bitwise and can be either 0 or 1).

Calculating possible permutations in a grid with the given length?

I have a 4x4 grid full of letters. How can I calculate all possible routes from any point to any point that consist of 2 to 10 points?
All points within a route must be connected to another point within the same route vertically, horizontally or diagonally. For example you can go from A to B, A to E and A to F but not A to C.
Each point can be used only once in a route.
Here's an example of 25 possible permutations:
+---+---+---+---+
| A | B | C | D |
+---+---+---+---+
| E | F | G | H |
+---+---+---+---+
| I | J | K | L |
+---+---+---+---+
| M | N | O | P |
+---+---+---+---+
- AB
- ABC
- ABCD
- ABCDH
- ABCDHG
- ABCDHGF
- ABCDHGFE
- ABCDHGFEI
- ABCDHGFEIJ
- AE
- AEI
- AEIM
- AEIMN
- AEIMNJ
- AEIMNJF
- AIEMNJFB
- AIEMNJFBC
- AIEMNJFBCG
- AFKP
- PONM
- FGKL
- NJFB
- MNJGD
Now I should clear the question. I'm not asking HOW to get all the permutations. I'm asking what is the total amount of the possible permutations (i.e. an integer) and how to calculate it.
As mentioned in the comments the question can be answered with basic DFS in java starting at top left at (0,0)
EDIT: I added if(count(visited)>10) return; for the constraint
static int count=0;
static int count(boolean[][] b){
int r = 0;
for(int i=0;i<b.length;i++){
for(int j=0;j<b[0].length;j++){
if(b[i][j]) r++;
}
}
return r;
}
static boolean[][] copy(boolean[][] arr){
boolean [][] r = new boolean[arr.length][];
for(int i = 0; i < arr.length; i++)
r[i] = arr[i].clone();
return r;
}
static void dfs(int i, int j,boolean[][] visited) {
visited[i][j] = true;
if(count(visited)>10) return;
count++;
for (int k=-1;k<2;k++) {
for (int l=-1;l<2;l++) {
int r = i+k;
int c = j+l;
if (r>-1 && r<visited.length && c>-1 && c<visited.length && !visited[r][c]){
dfs(r,c,copy(visited));
}
}
}
}
public static void main(String args[]) {
boolean[][] visited = {
{false, false, false, false},
{false, false, false, false},
{false, false, false, false},
{false, false, false, false}
};
// dfs(row,column,initialize all to false)
dfs(0,0,visited);
System.out.println(count-1);
}
The above script just goes through each permutation and increments count every time since this includes the starting point (for example (0,0)) i have at the bottom count-1
Output: 105837 (edited from my incorrect original 1012519)
for 2x2 starting at same place i get 15. Which you can see from running
static int count=0;
static int count(boolean[][] b){
int r = 0;
for(int i=0;i<b.length;i++){
for(int j=0;j<b[0].length;j++){
if(b[i][j]) r++;
}
}
return r;
}
static boolean[][] copy(boolean[][] arr){
boolean [][] r = new boolean[arr.length][];
for(int i = 0; i < arr.length; i++)
r[i] = arr[i].clone();
return r;
}
static void dfs(int i, int j,boolean[][] visited,String str) {
visited[i][j] = true;
if (count(visited)>10) return;
count++;
str+="("+i+","+j+")";
System.out.println(str+": "+count);
for (int k=-1;k<2;k++) {
for (int l=-1;l<2;l++) {
int r = i+k;
int c = j+l;
if (r>-1 && r<visited.length && c>-1 && c<visited.length && !visited[r][c]){
dfs(r,c,copy(visited),str);
}
}
}
}
public static void main(String args[]) {
boolean[][] visited = {
{false, false},
{false, false}
};
dfs(0,0,visited,"");
// "count-1" to account for the starting position
System.out.println(count-1);
}
Output:
(0,0): 1
(0,0)(0,1): 2
(0,0)(0,1)(1,0): 3
(0,0)(0,1)(1,0)(1,1): 4
(0,0)(0,1)(1,1): 5
(0,0)(0,1)(1,1)(1,0): 6
(0,0)(1,0): 7
(0,0)(1,0)(0,1): 8
(0,0)(1,0)(0,1)(1,1): 9
(0,0)(1,0)(1,1): 10
(0,0)(1,0)(1,1)(0,1): 11
(0,0)(1,1): 12
(0,0)(1,1)(0,1): 13
(0,0)(1,1)(0,1)(1,0): 14
(0,0)(1,1)(1,0): 15
(0,0)(1,1)(1,0)(0,1): 16
15
the same script with 4x4 instead last 6 lines of output are:
(0,0)(1,1)(2,2)(3,3)(3,2)(3,1)(3,0)(2,1)(1,2)(0,3): 105834
(0,0)(1,1)(2,2)(3,3)(3,2)(3,1)(3,0)(2,1)(1,2)(1,3): 105835
(0,0)(1,1)(2,2)(3,3)(3,2)(3,1)(3,0)(2,1)(1,2)(2,3): 105836
(0,0)(1,1)(2,2)(3,3)(3,2)(3,1)(3,0)(2,1)(2,0): 105837
(0,0)(1,1)(2,2)(3,3)(3,2)(3,1)(3,0)(2,1)(2,0)(1,0): 105838
105837
The requirements for your problem are complex enough that I doubt there is a simple mathematical calculation--at least I cannot think of one. Here is recursive Python code to find your path count.
SIDE = 4 # Length of side of grid
MAXLEN = 10 # Maximum path length allowed
SIDE2 = SIDE + 2
DIRS = ( # offsets for directions
-1 * SIDE2 - 1, # up & left
-1 * SIDE2 + 0, # up
-1 * SIDE2 + 1, # up & right
0 * SIDE2 - 1, # left
0 * SIDE2 + 1, # right
1 * SIDE2 - 1, # down & left
1 * SIDE2 + 0, # down
1 * SIDE2 + 1, # down & right
)
def countpaths(loc, pathlen):
"""Return the number of paths starting at the point indicated by
parameter loc of length at most parameter pathlen, not repeating
points or using points marked False in global variable isfree[]."""
global isfree
pathcnt = 1 # count sub-path of just this one point
if pathlen > 1:
isfree[loc] = False
for dir in DIRS:
if isfree[loc + dir]:
pathcnt += countpaths(loc + dir, pathlen - 1)
isfree[loc] = True
return pathcnt
# Init global boolean array variable to flag which points are still available
isfree = [1 <= r <= SIDE and 1 <= c <= SIDE
for r in range(SIDE2) for c in range(SIDE2)]
# Use the symmetries of the square grid to find count of paths in grid
allpathcnt = 0
for r in range(1, (SIDE + 1) // 2 + 1): # do a triangular slice of the grid
for c in range(1, r + 1):
# Find the number of similar (by symmetry) points in the grid
if 2 * r - 1 == SIDE:
if r == c:
sym = 1 # center of entire grid
else:
sym = 4 # center of column
else:
if r == c:
sym = 4 # diagonal
else:
sym = 8 # other
# Add paths starting at this kind of point removing those of length 1
allpathcnt += sym * (countpaths(r * SIDE2 + c, MAXLEN) - 1)
print('Total path count is ' + str(allpathcnt))
This code takes into account the requirement that paths have lengths between 2 and 10 by limiting the path length to 10 and removing the paths of length 1. The requirement that points are not repeated is fulfilled by using array isfree[] to note which points are still free (True) and which are already used or should not be used (False).
Python is a somewhat slow language, so I increased speed by moving some calculations out of the inner recursions. I used a surrounding border of always-False points around your 4x4 grid, removing the need for explicit bounds checking. I used a one-dimensional list rather than two-dimensional and pre-coded the offsets from each cell to neighboring cells in constant DIRS (for "directions"). I used a final optimization by not using all 16 starting points. There are 4 corner points like A, 8 side points like B, and 4 center points like F, so I just found the numbers of paths from A, B, and F and calculated what the total would be for starting at all points.
This version of my code can handle any size square grid and maximum path length. I checked my code by varying SIDE and MAXLEN separately to 1, 2, and 3, and checking the results for each point by hand.
The final answer I get is
1626144
I was interested to note that the section of code taking the most space is the part that determines the symmetries of a point in the grid. I have found other, more concise ways to do this, but they are all much less readable.

grid unique paths - recursion

I am trying to solve the grid unique paths problem. The problem involves finding the number of possible unique paths in a 2D grid starting from top left (0,0) to the bottom right (say A,B). One can only move right or down. Here is my initial attempt:
#include <stdio.h>
int count=0;
void uniquePathsRecur(int r, int c, int A, int B){
if(r==A-1 & c==B-1){
count++;
return;
}
if(r<A-1){
return uniquePathsRecur(r++,c,A,B);
}
if(c<B-1){
return uniquePathsRecur(r,c++,A,B);
}
}
int uniquePaths(int A, int B) {
if(B==1 | A==1){
return 1;
}
uniquePathsRecur(0,0,A,B);
return count;
}
int main(){
printf("%d", uniquePaths(5,3));
return 0;
}
I end up getting segmentation fault: 11 with my code. I tried to debug in gdb and i get the following:
lldb) target create "a.out"
Current executable set to 'a.out' (x86_64).
(lldb) r
Process 12171 launched: '<path to process>/a.out' (x86_64)
Process 12171 stopped
* thread #1: tid = 0x531b2e, 0x0000000100000e38 a.out`uniquePathsRecur + 8, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0x7fff5f3ffffc)
frame #0: 0x0000000100000e38 a.out`uniquePathsRecur + 8
a.out`uniquePathsRecur:
-> 0x100000e38 <+8>: movl %edi, -0x4(%rbp)
0x100000e3b <+11>: movl %esi, -0x8(%rbp)
0x100000e3e <+14>: movl %edx, -0xc(%rbp)
0x100000e41 <+17>: movl %ecx, -0x10(%rbp)
(lldb)
What is wrong with the above code?
I don't know the problem of your code. But you can solve the problem without using recursion.
Method 1: We can solve this problem with simple math skill. The
requirement is that you can only move either down or right at any
point. So it requires exact (m + n) steps from S to D and n out of (m
+ n) steps go down. Thus, the answer is C(m + n, n).
Method 2: Let us solve the issue in computer science way. This is a typical dynamic
programming problem. Let us assume the robot is standing at (i, j).
How did the robot arrive at (i, j)? The robot could move down from (i
- 1, j) or move right from (i, j - 1). So the path to (i, j) is equal to the sum of path to (i - 1, j) and path to (i, j - 1). We can use
another array to store the path to all node and use the equation
below: paths(i, j) = 1 // i == 0 or j == 0 paths(i, j) = paths(i - 1,
j) + paths(i, j - 1) // i != 0 and j != 0 However, given more
thoughts, you will find out that you don't actually need a 2D array to
record all the values since when the robot is at row i, you only need
the paths at (i - 1). So the equation is: paths(j) = 1 //j == 0 for
any i paths(j) = paths(j - 1) + paths(j) // j != 0 for any i
For more information, please see here: https://algorithm.pingzhang.io/DynamicProgramming/unique_path.html

Drawing a line segment on a space that wraps toroidally

I have a 2D space of angles [0, 2pi] x [0, 2pi] which wraps around, with toroid like topology (the horizontal edges correspond to each other, as do the vertical ones). I have two points in this space, and I would like to draw a line segment between those two points.
In some cases, this line segment is the obvious line segment, from one point to the other. In other cases, the line segment is supposed to "go around the edge" instead of going "the long way, through the middle":
+--------+
| |
| A--B |
| |
+--------+
+--------+
| |
|-A B-|
| |
+--------+
While these cases are moderately easy to handle, there is one case that is really vexing for me and which my code so far does not handle correctly:
+-----------+
| / |
| B |
| |
| A /|
| / / |
+-----------+
I.e. if the line wraps around both directions, it sometimes wraps around the opposite corner. I'm not entirely sure if there are more of these tricky cases.
The only algorithm I've come up that works reliably so far is to calculate the midpoint as (A + B) / 2 while making appropriate use of the modulo arithmetics, draw a dot at this position, and then recursively subdivide the left and right intervals similarly, until the distance between the dots is less than a single pixel. Obviously, this is not going to be very fast.
My other approach was to detect (separately for x and y) whether the short distance is direct or around the edge, and then either draw one line segment or two. This does not handle the third case correctly, unless the line is divided in two and the midpoint lies on the segment that is in the lower-right corner in the example image. I'm not sure how to detect this efficiently, or how to calculate the position of the midpoint, as simply the point in the half does not always work, it might end up at the edge together with one of the endpoints, if their respective distance from the edge is not equal.
Is there a better algorithm? Is there an obvious solution that I'm not seeing? I'm not even sure how to google for this problem. I don't want to implement my own line rasterization algorithm, I would just like to break this problem to Euclidean straight lines and draw these using OpenGL or GDI or whatever.
My code so far is:
void Draw_WrappedSegment(float f_x0, float f_y0, float f_x1, float f_y1)
{
const float s = 2 * f_pi;
f_x0 = fmod(fmod(f_x0, s) + s, s);
f_y0 = fmod(fmod(f_y0, s) + s, s);
f_x1 = fmod(fmod(f_x1, s) + s, s);
f_y1 = fmod(fmod(f_y1, s) + s, s);
// make sure the coordinates end up being positive and modulo 2pi
float f_ydist0 = fabs(f_y0 - f_y1);
float f_ydist1 = fabs(fmod(f_y0 + s - f_y1, s));
float f_ydist2 = fabs(fmod(f_y1 - f_y0 + s, s));
float f_xdist0 = fabs(f_x0 - f_x1);
float f_xdist1 = fabs(fmod(f_x0 + s - f_x1, s));
float f_xdist2 = fabs(fmod(f_x1 - f_x0 + s, s));
// 0 2pi 4pi
//p1'' | p0 p1 | p0' p1' |
// <---f_dist0--->
// <-f_dist1->
// <-f_dist2->
const float f_epsilon = 1e-3f; // sometimes the modulo causes an error and even though the díst 0 and dist 2 should equal, dist 2 is slightly smaller
if(f_xdist0 <= f_xdist1 + f_epsilon && f_xdist0 <= f_xdist2 + f_epsilon) {
if(f_ydist0 <= f_ydist1 + f_epsilon && f_ydist0 <= f_ydist2 + f_epsilon) {
MoveTo(f_x0, f_y0);
LineTo(f_x1, f_y1); // the "short" way in both directions
} else {
float f_sign = (f_y0 < f_y1)? 1 : -1; // swap the lower and upper edge if the points are not sorted by y
MoveTo(f_x0, f_y0);
LineTo(f_x1, f_y1 - f_sign * s); // from point 0 to the lower edge
MoveTo(f_x1, f_y1);
LineTo(f_x0, f_y0 + f_sign * s); // from point 1 to the upper edge
}
} else {
if(f_ydist0 <= f_ydist1 + f_epsilon && f_ydist0 <= f_ydist2 + f_epsilon) {
float f_sign = (f_x0 < f_x1)? 1 : -1; // swap the left and right edge if the points are not sorted by x
MoveTo(f_x0, f_y0);
LineTo(f_x1 - f_sign * s, f_y1); // from point 0 to the left edge
MoveTo(f_x1, f_y1);
LineTo(f_x0 + f_sign * s, f_y0); // from point 1 to the right edge
} else {
float f_sign_x = (f_x0 < f_x1)? 1 : -1; // swap the left and right edge if the points are not sorted by x
float f_sign_y = (f_y0 < f_y1)? 1 : -1; // swap the lower and upper edge if the points are not sorted by y
MoveTo(f_x0, f_y0);
LineTo(f_x1 - f_sign_x * s, f_y1 - f_sign_y * s); // from point 0 to one edge
MoveTo(f_x1, f_y1);
LineTo(f_x0 + f_sign_x * s, f_y0 + f_sign_y * s); // from point 1 to the other edge
}
}
}
Instead of working with just the square [0, 2pi] x [0, 2pi], try tiling the space [-2pi,4pi] x [-2pi,4pi] with nine copies of this square (like a tic-tac-toe board). Place A in the center square, and then place copies of B (translating the coordinates by ±2pi as required ) in each of the nine squares. Choose the copy of B that is closest to A, and then draw the line from A to that copy of B. This line may have more than one segment as it travels through the squares. Just "untranslate" these segments back to the central square and you will have the diagram you want.

Efficient access a non-linearly filled 1D array using (x, y) co-ords and bit manipulation

I'm making a quad tree to hold values for a large square grid. Many regions of the grid are filled with the same value so instead of holding the same value in many nodes I hold one node that tells the function looking for values anywhere in that region that the value is the one that node holds. When lots of nodes together are very different I put them in a single node that holds an array of those values to cut out the overhead of having many middle-man nodes.
For simplicity I'll use byte sized examples, but my grid is much larger. A 16x16 gird of 256 values might look like this:
[ root ] <----16x16
/ | | \
/ [1][1] [64] <-+--8x8
[ node ] <-+
/ | | \
/[16][16][16] <-+--4x4
[ node ] <-+
| | | \
[1][1][1] [4] <----2x2
These values change frequently during the course of my application so the arrays in leaf nodes have to get divided and concatenated a lot. I started out using a standard 2D array but realized that if I try to take out a quadrant of that array it'd be grabbing data from many places because I'm essentially asking for one half of one half of the 1D arrays in the 2D arrays. My solution was to nest quadrants inside larger quadrants so that dividing a 1D array into quarters would give you the values for the four nested quadrants.
I've arranged them top to bottom, left to right. These grids illustrate the allocation scheme on two scales that remains consistent across all scales.
0 1 0 1 2 3
0 | 0| 1| 0 | 0 | 1 |
1 | 2| 3| 1 |_____|_____|
2 | 2 | 3 |
3 |_____|_____|
Here is what it'd look like if you printed the index of the 1D array out onto a 2D grid.
0 1 2 3 4 5 6
0 | 0| 1| 4| 5|16|17|20|
1 | 2| 3| 6| 7|18|19|
2 | 8| 9|12|13|
3 |10|11|14|15|
4 |32|33|
5 |34|35|
6 |40| etc.
So of course now that I've got a solution to cutting up the grid I've just made it annoying to retrieve anything from it. Here is how I currently get the index of the 1D array from (x, y) co-ords.
uint index( uint x, uint y ){
uint l = sqrt(array.length);
uint index;
uint chunk = array.length;
while ( l > 1 ){
l /= 2;
chunk /= 2;
if( y >= l ){
y -= l;
index += chunk;
}
chunk /= 2;
if( x >= l ){
x -= l;
index += chunk;
}
}
return index;
}
It works but it's painful... while thinking about it after I'd written it, it occurred to me that I was manipulating bits at a high level. So it should theoretically be possible to look at the bits of (x, y) directly to determine bits of the index for the array without doing as much work.
I've been trying to work out what I need to do in binary by looking at x, y, and index binary together, but I'm not having any luck deriving a method beyond "If x ends in 1, the index is odd".
N7 N6 N5 N4 N3 N2 N1 N0
x 5 |--|--|--|--|00|00|01|01|
y 1 |--|--|--|--|00|00|00|01|
Index 17 |00|00|00|00|00|01|00|01|
N7 N6 N5 N4 N3 N2 N1 N0
x 1 |--|--|--|--|00|00|00|01|
y 6 |--|--|--|--|00|00|01|10|
Index 41 |00|00|00|00|01|00|10|01|
I'm certain that the x y values can tell me which quadrant the index is in with x giving me east or west and y giving me north or south at any scale. I think I might need to make a bit mask or something, idk, I've never had to deal with bits directly outside of college, well, beyond bit-flags. So if someone can help me out with what I can do to get the index that'd be a huge help!

Resources