I am trying to implement the midpoint displacement algorithm in Java. It's also called the diamond square algorithm. My reference is http://www.lighthouse3d.com/opengl/terrain/index.php3?mpd. It seems to work correctly except on the right and bottom edges.
See Midpoint Displacement Results
Upon close inspection, the "rough" edges can be seen. Could anyone point out what is wrong?
This effect hasn't been observed in other online implementations of this algorithm.
Code
private void generateWorldMPD() {
/* The following is my first attempt at the MDP algorithm. */
// displacement boundary.
double displacementBound = Constants.DEFAULT_ROUGHNESS_CONSTANT;
double[][] A = Utilities.get2DDoubleArray(Constants.MPD_PRESET_HEIGHT, 2, 2);
int iterations =0;
while (iterations < mPDIterations) {
// create a new array large enough for the new points being added.
double [][] B = new double[A.length * 2 - 1][A[0].length * 2 - 1];
// move the points in A to B, skipping every other element as space for a new point
for (int i = 0; i < B.length; i +=2)
for (int j = 0; j < B[i].length; j+=2) {
B[i][j] = A[i / 2][j / 2];
}
//calculate the height of each new center point as the average of the four adjacent elements
//(diamond step) and add a random displacement to each
for (int i = 1; i < B.length; i+= 2)
for (int j = 1; j < B[i].length; j+=2) {
averageFromCornersAndDisplace(B, i, j, displacementBound);
}
//calculate the height of each new non-center point (square step) and add a random displacement to each
for (int i = 0; i < B.length; i ++)
for (int j = 0; j < B[i].length; j++)
if (i % 2 == 0) //on every even row, calculate for only odd columns
if (j % 2 == 0) continue;
else
averageFromAdjAndDisplace( B , i, j, displacementBound );
else //on every odd row, calculate for only even columns
if (j % 2 == 0)
averageFromAdjAndDisplace( B , i, j, displacementBound );
else
continue;
displacementBound *= Math.pow(2, -Constants.DEFAULT_ROUGHNESS_CONSTANT);
// assign B to A
A = B;
iterations++;
}
}
private void averageFromCornersAndDisplace(double[][] A, int i, int j, double displacementBoundary) {
double nw = A[ wrap(i - 1, 0, A.length - 1) ][ wrap(j - 1, 0, A[i].length - 1) ];
double ne = A[ wrap(i + 1, 0, A.length - 1) ][ wrap(j - 1, 0, A[i].length - 1) ];
double sw = A[ wrap(i - 1, 0, A.length - 1) ][ wrap(j + 1, 0, A[i].length - 1) ];
double se = A[ wrap(i + 1, 0, A.length - 1) ][ wrap(j + 1, 0, A[i].length - 1) ];
A[i][j] = (nw + ne + sw + se) / 4;
A[i][j] += randomDisplacement(displacementBoundary);
}
private void averageFromAdjAndDisplace(double[][] A, int i, int j, double displacementBoundary) {
double north = A[i][ wrap(j - 1, 0, A[i].length - 1)];
double south = A[i][ wrap(j + 1, 0, A[i].length - 1)];
double west = A[ wrap(i - 1, 0, A.length - 1) ][j];
double east = A[ wrap(i + 1, 0, A.length - 1) ][j];
A[i][j] = (north + south + east + west) / 4;
A[i][j] += randomDisplacement(displacementBoundary);
}
// This function returns a value that is wrapped around the interval if
// it exceeds the given bounds in the negative or positive direction.
private int wrap(int n, int lowerBound, int upperBound) {
int lengthOfInterval = upperBound - lowerBound;
if (n < lowerBound)
return (lowerBound - n) % lengthOfInterval;
else
return (n - upperBound) % lengthOfInterval;
}
Annotations
private void generateWorldMPD() {
/* The following is my first attempt at the MDP algorithm. */
// displacement boundary.
double displacementBound = Constants.DEFAULT_ROUGHNESS_CONSTANT;
double[][] A = Utilities.get2DDoubleArray(Constants.MPD_PRESET_HEIGHT, 2, 2);
int iterations =0;
This part defines a variable displacementBound, a 2D array of doubles initialized to default values, and another variable called iterations.
while (iterations < mPDIterations) {
// create a new array large enough for the new points being added.
double [][] B = new double[A.length * 2 - 1][A[0].length * 2 - 1];
// move the points in A to B, skipping every other element as space for a new point
for (int i = 0; i < B.length; i +=2)
for (int j = 0; j < B[i].length; j+=2) {
B[i][j] = A[i / 2][j / 2];
}
This part is where the loop is declared. It will run for mPDIterations loops. A makeshift array B is created to hold an updated version of A, making B larger than A to hold new data points. After that there are two for loops, one nested inside another, which places the current values of A into the temporary B, taking care to leave every other row and every other column blank. Take a look at this example:
// The '*'s represent a cell in an array that is populated with a value.
// The '_'s represent a cell in an array that is empty.
// This is 'A'.
* *
* *
// This is 'B'. At the moment, completely empty.
_ _ _
_ _ _
_ _ _
// The elements of 'A' are tranferred to 'B'.
// Blank cells are inserted in every other row, and every other column.
* _ *
_ _ _
* _ *
Now for the next bit of code:
//calculate the height of each new center point as the average of the four adjacent elements
//(diamond step) and add a random displacement to each
for (int i = 1; i < B.length; i+= 2)
for (int j = 1; j < B[i].length; j+=2) {
averageFromCornersAndDisplace(B, i, j, displacementBound);
}
In this section, every point at a center, which refers to a cell that has an empty adjacent cell in every cardinal direction of north, south, east, and west, is given a value averaged from the four adjacent corner points and with a random displacement value added to it. This is called the diamond step. To clarify what a 'center' is:
// The big "O" indicates the 'center' in this 2D array.
* _ *
_ O _
* _ *
And the next code section:
//calculate the height of each new non-center point (square step) and add a random displacement to each
for (int i = 0; i < B.length; i ++)
for (int j = 0; j < B[i].length; j++)
if (i % 2 == 0) //on every even row, calculate for only odd columns
if (j % 2 == 0) continue;
else
averageFromAdjAndDisplace( B , i, j, displacementBound );
else //on every odd row, calculate for only even columns
if (j % 2 == 0)
averageFromAdjAndDisplace( B , i, j, displacementBound );
else
continue;
This part does is analogous to the previous section of code. It assigns to each non-center and empty point a new value; this value is the average of the adjacent elements in the cardinal directions north, south, east, and west, with another random displacement value added to it. This is called the square step. The code above assures that only the non-center and empty points are given new values; these points being equivalent to side points, which are clarified below:
// The big 'O's indicate the 'side points' in this 2D array.
* O *
O * O
* O *
The section that concludes the while loop is given below:
displacementBound *= Math.pow(2, -Constants.DEFAULT_ROUGHNESS_CONSTANT);
// assign B to A
A = B;
iterations++;
} // end of while loop
The variable displacementBound is reduced in the section above, which comprises the end of the while loop, according to the information given in the aforementioned article. The contents of A are renewed by assigning the updated contents of B to A prior to beginning another iteration of the loop or terminating it.
Lastly, the ancillary methods averageFromCornersAndDisplace(), averageFromSidesAndDisplace(), and wrap() have been included but additional explanations for them are unnecessary. The method randomDisplacement() has not been included at all. For your information, it returns a random floating-point number x bounded by the given number b:
// The method returns a double x, where -b <= x < b
double randomDisplacement(double b);
I just saw your post pop up, and I guess you've already sorted it out. Anyway, if you want to do a wrap like that, there is a neat trick to fix the fact that negative mods don't work right in C/Java. What you do is just add some multiple of the modulus (being careful not to overflow) back to the number to ensure that it is non-negative. Then you can mod out as usual without it breaking. Here is an example:
private int wrap(int n, int lowerBound, int upperBound) {
int lengthOfInterval = upperBound - lowerBound;
return lowerBound + ((n - lowerBound + lengthOfInterval) % lengthOfInterval);
}
The wrap() function is the culprit. It wraps indexes around when they exceed the boundaries of the array, so that on the edges two (often disparate) values are averaged together. Which lead to the weird incompatibility. I deleted all calls to wrap() and chose to average three adjacent points instead of four whenever wrapping was necessary.
The method wrap() was meant to provide seamless tiling, but in this case seems to have caused a problem. And the tiling doesn't even look seamless.
Related
I am working on a project that requires finding some smaller 2d int arrays contained within a larger 2d int array.
To be more specific, I will be provided with a text file for input. The text file will contain an N, M, and K value, as well as integers to populate a "large" MxN grid. I will then need to find all "small" KxK grids within that larger MxN grid, and return the largest int within each KxK grid.
So, for example:
m = 3; n = 4; k = 2
MxN:
3 4 2
2 3 1
8 3 2
7 8 1
The 1st KxK grid to analyze would be:
3 4
2 3
return 4;
The 2nd:
4 2
3 1
return 4;
The 3rd:
2 3
8 3
return 8;
etc, etc.
Is there a slick way of iterating through these KxK grids with the mod operator or something? I feel like there is a simple solution for this, but it's not obvious to me.
I know this is more of a math problem than a programming one, but any help would be appreciated.
Thanks.
I've tried to write little code here:
private int[] getMaxFromGrids(int k, int[][] yourArray){
int m = yourArray.length; //height of grid
int n = yourArray[0].length; //width of grid, assuming that all inner array have same length!
//argument k is size of smaller grid
//computing max possibilities to fit smaller grid to larger one
int maxPossibilities = (m - k + 1) * (n - k + 1);
if(maxPossibilities < 1 || k < 1) return null;
int[] maxValuesSmallGrid = new int[maxPossibilities];
for (int i = 0; i < (maxPossibilities); i++) {
//computing actual start element for small grid
int colStartElement = i % (n - (k - 1));
int rowStartElement = i / (n - (k - 1));
//creating smaller grid
int[] smallGrid = new int[k * k];
int o = 0; //index of smaller grid
for (int j = colStartElement; j < colStartElement + k; j++) {
for (int l = rowStartElement; l < rowStartElement + k; l++) {
smallGrid[o++] = yourArray[j][l];
}
}
maxValuesSmallGrid[i] = getMax(smallGrid);
}
return maxValuesSmallGrid;
}
//method for getting max number from given array
private int getMax(int[] numbers) {
int max = Integer.MIN_VALUE;
for(int num : numbers) {
if(num > max) max = num;
}
return max;
}
Given that K<=N && K<=M, you can easily find all subarray2d by moving their top left corner from 0,0 to N-K,M-K (use 2 for loops)
Then make a function taking the coordinates of the top left corner of a K*K subarray2d and returning its higher value :)
I am calculating the index of an n dimensional array transformed to a flat 1d array.
private int toFlatindex(int... dimensionIndices){
int index = 0;
for (int k = dimensionIndices.length - 1; k >= 0; k--) {
// Check if the specified index is within the bounds of the array
if(dimensionIndices[k] < 0 || dimensionIndices[k] >= dimensionSizes[k]) {
return -1;
}
// get the index in the flat array using the formula from https://en.wikipedia.org/wiki/Row-major_order#Address_calculation_in_general
int start = 1;
for (int l = dimensionSizes.length - 1; l >= k+1; l--) {
start = start * dimensionSizes[l];
}
index += dimensionIndices[k]*start;
}
return index;
}
I have written this code which appears and tests correct. Although I have coded the formula from wikipedia I don't fully understand what is happening. I would appreciate someone explaining this, or even better linking a video tutorial/lecture on the address calculation.
Let's work through the first few dimensions manually.
For a 1d array, which is a single row, element [k] is at position k.
For a 2d array, element [j,k] specifies the k'th element of row j. This is k + start of row j. The start of row j is at j * number of columns. If the dimensions are listed in the array dimensionSize, then the number of columns is dimensionSize[0].
Putting this together, element [j,k] is at dimensionSize[0] * j + k.
For a 3d array, element [i,j,k] specifies the k'th element of row j within "plane" i of the cube of elements. This is k + start of row j in plane i. The start of row j in plane i is i * size of plane + j * size of row. Putting this together, element [i,j,k] is at
dimensionSize[0] * dimensionSize[1] * i + dimensionSize[0] * j + k.
Another way of writing this is
dimensionSize[0] * (dimensionSize[1] * i + j) + k.
The pattern is emerging. If we had a 4d array, element [h,i,j,k] would be
dimensionSize[0] * (dimensionSize[1] * (dimensionSize[2] * h + i) + j) + k
Now replace the indices k,j,i,h with an array dimensionIndices[0..3] and you should be able to see that function is doing this computation for an arbitrary number of dimensions.
A simpler coding would be:
int getOffset(int [] sizes, int [] indices) {
int ofs = indices[sizes.length - 1];
for (int d = sizes.length - 2; d >= 0; --d) {
ofs = ofs * sizes[d] + indices[d];
}
return ofs;
}
So you find the code below here. Most of the code I understand, but there is one bit I don't. The place where we create the boolean array called digits and the bit after that 3 * (x / 3).
I think it's used to check if each square in the sudoku has 9 unique numbers as well, but I'm not sure on how I can explain this to let's say someone next to me.
Why do I need the array of boolean here? Can someone explain to me what it is doing and why?
Kind regards!
public int[][] solvePuzzle(int[][] matrix) {
int x, y = 0;
boolean found = false;
// First we check if the matrix contains any zeros.
// If it does we break out of the for loop and continue to solving the puzzle.
for (x = 0; x < 9; x++) {
for (y = 0; y < 9; y++) {
if (matrix[x][y] == 0) {
found = true;
break;
}
}
if (found) {
break;
}
}
// If the puzzle doesn't contain any zeros we return the matrix
// We now know that this is the solved version of the puzzle
if (!found) {
return matrix;
}
boolean digits[] = new boolean[11];
for (int i = 0; i < 9; i++) {
digits[matrix[x][i]] = true;
digits[matrix[i][y]] = true;
}
int boxX = 3 * (x / 3), boxY = 3 * (y / 3);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
digits[matrix[boxX + i][boxY + j]] = true;
}
}
// We loop over all the numbers we have to check if the next number fits in the puzzle
// We update the matrix and check recursively by calling the same function again to check if the puzzle is correct
// If it's not correct we reset the matrix field to 0 and continue with the next number in the for loop
for (int i = 1; i <= 9; i++) {
if (!digits[i]) {
matrix[x][y] = i;
if (solvePuzzle(matrix) != null) {
return matrix;
}
matrix[x][y] = 0;
}
}
// The puzzle can't be solved so we return null
return null;
}
I have added some explanation as comments inline:
//we need to know what digits are we still allowed to use
//(not used in this row, not used in this column, not used in
//the same 3x3 "sub-box")
boolean digits[] = new boolean[11];
//so we run through the rows/coumns around the place (x,y)
//we want to fill in this iteration
for (int i = 0; i < 9; i++) {
//take a used number from the row of x (matrix[x][i]) and mark it
// as used
digits[matrix[x][i]] = true;
//take a used number from the column of y (matrix[i][y]) and mark it
// as used
digits[matrix[i][y]] = true;
}
//find the top-left corner of the sub-box for the position (x,y) we
//want to fill in
//example: x is 8 -> 3 * 8/3 -> 6, so we start from 6
int boxX = 3 * (x / 3), boxY = 3 * (y / 3);
//iterate through the sub-box horizontally and vertically
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
//take a used number from the sub-box and mark it
// as used
digits[matrix[boxX + i][boxY + j]] = true;
}
}
There seem to be two issues you are unclear on:
The boolean array - this array is used to track which digits have been used already on a specific row or column. So imagine a row of tick boxes each with a digit written next to it (the array index) - these boxes are checked or unchecked to show a digit has been used or not.
The expressions 3* (x/3) and 3 * (y/3) - what you need to remember here is that this is integer division (that means the result of the division is always rounded down to an integer. For example if x=1 then 3 (x/3) is 3 (1/3) is 3 * (0) =0 (whereas if this was float division the result would be 3*(0.3333)=1. So these maths expressions essentially change you number to the next lowest multiple of three - that is 1 -> 0, 2 -> 0, 3 -> 3, 4 -> 3 etc.
I have a 36x25 grid of nodes that I wish to search through all triangular numbers from the corner opposite of the hypotenuse. Here's psuedocode for what I was considering, but this method only works until it hits the next corner of the grid, and I'm sure there is a much simpler way to do this recursively, I just am having difficulty figuring it out.
for(int iteration; iteration < maxDistance(49); iteration++)
{
int xAdd = iteration;
int yAdd = 0;
while(xAdd != 0)
{
checkStuff(nodeGrid[x+xAdd][y+yAdd]);
xAdd--;
yAdd++;
}
}
What I want program to do:
[0][1][2][3][4][5]
[1][2][3][4][5][6]
[2][3][4][5][6][7]
[3][4][5][6][7][8]
[4][5][6][7][8][9]
check in this order. So first check all tiles with value 0, then 1 and so on.
Note: in this case my function will only work up until the 4th set up tiles. Any further and it will reach out of bounds.
/**
* Only works for rectangular arrays
*/
public void iterateOver(Node[][] a){
int x_dim = a[0].length;
int y_dim = a.length;
for (int i = 0; i < x_dim + y_dim - 1; i++){
int x, y;
if (i < x_dim){
x = i;
y = 0;
}
else{
x = x_dim - 1;
y = i - x_dim + 1;
}
for (;x >=0 && y < y_dim; y++, x--){
doStuff(a[y][x]);
}
}
}
How it works
Picture your rectangular array:
[0][1][2][3][4][5]
[1][2][3][4][5][6]
[2][3][4][5][6][7]
[3][4][5][6][7][8]
[4][5][6][7][8][9]
There are clearly 6 columns and 5 rows (or 6 x values and 5 y values). That means that we need to do 6 + 5 - 1 iterations, or 10. Thus, the for (int i = 0; i < x_dim + y_dim - 1; i++). (i is the current iteration, measured from 0).
We start by columns. When i is less than the x dimension, x = i and y = 0 to start with. x is decremented and y is incremented until x is less than zero or y is equal to the y dimension. Then, we do a similar thing down the right hand side.
I have a problem that comes up when I was developing an app on Android. However, the problem is:
There are x boxes and y balls where x <= y, and I want to distribute the balls to put them inside the boxes in order. For example: 3 boxes; box A, box B and box C - and 5 balls; ball 1, ball 2, ball 3, ball 4, ball 5.
What I need is to put the first ball ball 1 inside box A, and ball 5 inside box C and the other balls are distributed between them all (does not matter if one box has more balls than the others). Here is a loop (missing an increment value) that simulates the problem:
int boxCount = 0; // first box is 0 and last box is x
int numOfBalls = y;
for(int i = 0; i < numOfBalls; i++, boxCount += ???)
{
boxes.get(boxCount).add(balls.get(i));
}
What equation should I used instead of ??? to solve the problem?
EDIT:
Since x <= y, that means:
None of the boxes should be empty.
The difference between the boxes' balls number should not be more than 1.
EDIT2
By in order, I meant this:
A B C
---------
1 3 5
2 4
not
A B C
---------
1 2 3
4 5
int flag;
int lastBallAdded = 0;
int k = numOfBalls/numOfBoxes;
int m = numOfBalls%numOfBoxes;
for(int i = 0; i < numOfBoxes; i++, lastBallAdded+=k+flag) {
flag = i<m;
for(int j=lastBallAdded;j<lastBallAdded + k + flag;j++)
boxes.get(i).add(balls.get(j));
}
This is the reasoning behind this solution:
by the definition of the problem, the algorithm should put k= numOfBalls/numOfBoxes balls in each box, except for the firsts m = numOfBalls%numOfBoxes boxes, where you should put k+1 balls.
You can alternatively write it as
int i;
for(i = 0; i < m; i++) {
//add k+1 balls
}
for(;i<numOfBoxes; i++) {
//add k balls
}
You can distribute (int)n/k balls in each of the first k-1 boxes and the rest in the last box. This will be simplest to code.
With this: boxCount += (i % (numOfBalls/numOfBoxes) == 0 && boxCount < numOfBoxes-1 ? 1 : 0)
int ball = 0;
for( int box = 0; box < x; ++box )
while ( x * (ball+1) <= y * (box+1) )
boxes.get(box).add(balls.get(ball++));
Loop invariant: The left k boxes contain fraction k/x of the balls (rounded).
Ok, new try:
boxCount = ((i * nbrOfBoxes) / nbrOfBalls) + 1;
Note, the index of the balls are numbered from 0 to 4 (as in the for-loop). Remove the + 1 if yo would like the boxCount to be zero based.