我試圖用Java編寫的Diamond-Square algorithm生成一個隨機地圖,但不能找出執行...鑽石廣場算法
任何人只要有一些Java代碼(或其他語言),所以我可以檢查如何製作循環將不勝感激!
謝謝!
我試圖用Java編寫的Diamond-Square algorithm生成一個隨機地圖,但不能找出執行...鑽石廣場算法
任何人只要有一些Java代碼(或其他語言),所以我可以檢查如何製作循環將不勝感激!
謝謝!
這是一個有趣的生成值的算法。下面是我根據this page in the references from the wikipedia article給出的解釋創建的實現。它會創建「球形值」(包裹在所有邊緣)。註釋中有註釋,說明如何將其更改爲在邊緣生成新值而不是纏繞(儘管在這些情況下邊緣平均值的含義並不真正)。
//size of grid to generate, note this must be a
//value 2^n+1
final int DATA_SIZE = 9;
//an initial seed value for the corners of the data
final double SEED = 1000.0;
double[][] data = new double[DATA_SIZE][DATA_SIZE];
//seed the data
data[0][0] = data[0][DATA_SIZE-1] = data[DATA_SIZE-1][0] =
data[DATA_SIZE-1][DATA_SIZE-1] = SEED;
double h = 500.0;//the range (-h -> +h) for the average offset
Random r = new Random();//for the new value in range of h
//side length is distance of a single square side
//or distance of diagonal in diamond
for(int sideLength = DATA_SIZE-1;
//side length must be >= 2 so we always have
//a new value (if its 1 we overwrite existing values
//on the last iteration)
sideLength >= 2;
//each iteration we are looking at smaller squares
//diamonds, and we decrease the variation of the offset
sideLength /=2, h/= 2.0){
//half the length of the side of a square
//or distance from diamond center to one corner
//(just to make calcs below a little clearer)
int halfSide = sideLength/2;
//generate the new square values
for(int x=0;x<DATA_SIZE-1;x+=sideLength){
for(int y=0;y<DATA_SIZE-1;y+=sideLength){
//x, y is upper left corner of square
//calculate average of existing corners
double avg = data[x][y] + //top left
data[x+sideLength][y] +//top right
data[x][y+sideLength] + //lower left
data[x+sideLength][y+sideLength];//lower right
avg /= 4.0;
//center is average plus random offset
data[x+halfSide][y+halfSide] =
//We calculate random value in range of 2h
//and then subtract h so the end value is
//in the range (-h, +h)
avg + (r.nextDouble()*2*h) - h;
}
}
//generate the diamond values
//since the diamonds are staggered we only move x
//by half side
//NOTE: if the data shouldn't wrap then x < DATA_SIZE
//to generate the far edge values
for(int x=0;x<DATA_SIZE-1;x+=halfSide){
//and y is x offset by half a side, but moved by
//the full side length
//NOTE: if the data shouldn't wrap then y < DATA_SIZE
//to generate the far edge values
for(int y=(x+halfSide)%sideLength;y<DATA_SIZE-1;y+=sideLength){
//x, y is center of diamond
//note we must use mod and add DATA_SIZE for subtraction
//so that we can wrap around the array to find the corners
double avg =
data[(x-halfSide+DATA_SIZE)%DATA_SIZE][y] + //left of center
data[(x+halfSide)%DATA_SIZE][y] + //right of center
data[x][(y+halfSide)%DATA_SIZE] + //below center
data[x][(y-halfSide+DATA_SIZE)%DATA_SIZE]; //above center
avg /= 4.0;
//new value = average plus random offset
//We calculate random value in range of 2h
//and then subtract h so the end value is
//in the range (-h, +h)
avg = avg + (r.nextDouble()*2*h) - h;
//update value for center of diamond
data[x][y] = avg;
//wrap values on the edges, remove
//this and adjust loop condition above
//for non-wrapping values.
if(x == 0) data[DATA_SIZE-1][y] = avg;
if(y == 0) data[x][DATA_SIZE-1] = avg;
}
}
}
//print out the data
for(double[] row : data){
for(double d : row){
System.out.printf("%8.3f ", d);
}
System.out.println();
}
我將不得不爲了定製目的和一般知識而多學習一點,但它很有用! 順便說一句,謝謝你的時間。 – 2010-05-06 04:00:59
當您使用大量迭代時,是否會遇到尖峯和低谷? – 2012-10-17 13:14:57
「包裹在所有邊緣」不是一個球體。這是一個環形。你做了一個麪糰堅果,而不是地球。在你去的北方,地球的周長較小。甜甜圈沒有。 - 不消除幾何,它是*方式*更容易,但它不是任何度量標準的球體。 – Tatarize 2013-03-20 10:48:24
看看這個演示與Processing完成:
http://www.intelegance.net/code/diamondsquare.shtml
而且,這裏有一個粗略的算法中另一個頁面寫出:
http://www.javaworld.com/javaworld/jw-08-1998/jw-08-step.html?page=2
最後,稍微正式的文件:
http://www.student.math.uwaterloo.ca/~pmat370/PROJECTS/2006/Keith_Stanger_Fractal_Landscapes.pdf
享受!
感謝這些網站的info.some我已經檢查過,但實現算法的代碼對我來說有點太神祕。你能用僞碼解釋循環是如何工作的嗎?我一直在考慮創建一個基於輸入值的函數來執行正方形和菱形步驟,並將其放入一個以正方形塊掃描整個網格的循環中。但是這會帶來問題,因爲只有主角具有固定的高度值。 – 2010-05-05 03:22:31
M. Jessup的答案似乎略有誤差。他在那裏:
double avg = data[(x-halfSide+DATA_SIZE)%DATA_SIZE][y] + //left of center data[(x+halfSide)%DATA_SIZE][y] + //right of center data[x][(y+halfSide)%DATA_SIZE] + //below center data[x][(y-halfSide+DATA_SIZE)%DATA_SIZE]; //above center
它應改爲閱讀:
double avg = data[(x-halfSide+DATA_SIZE-1)%(DATA_SIZE-1)][y] + //left of center data[(x+halfSide)%(DATA_SIZE-1)][y] + //right of center data[x][(y+halfSide)%(DATA_SIZE-1)] + //below center data[x][(y-halfSide+DATA_SIZE-1)%(DATA_SIZE-1)]; //above center
否則,從錯誤的地點(可未初始化)讀取。
修復後的結果看起來好多了。沒有它,價值觀會被擠壓到邊緣。 – JavadocMD 2010-12-29 00:58:28
對於任何人來說,這裏是由M. Jessup提供的算法,包含在一個接受種子的類中(以允許重現結果),一個用於指定維數的n值(維度爲2^n + 1) ,並將結果作爲標準化的浮點數組公開。它也適用於算法的第二部分應用。
import java.util.Random;
public class DiamondSquare {
public float[][] data;
public int width;
public int height;
public DiamondSquare(long mseed, int n) {
//size of grid to generate, note this must be a
//value 2^n+1
int DATA_SIZE = (1 << n) + 1;
width = DATA_SIZE;
height = DATA_SIZE;
//an initial seed value for the corners of the data
final float SEED = 1000.0f;
data = new float[DATA_SIZE][DATA_SIZE];
//seed the data
data[0][0] = data[0][DATA_SIZE-1] = data[DATA_SIZE-1][0] =
data[DATA_SIZE-1][DATA_SIZE-1] = SEED;
float valmin = Float.MAX_VALUE;
float valmax = Float.MIN_VALUE;
float h = 500.0f;//the range (-h -> +h) for the average offset
Random r = new Random(mseed);//for the new value in range of h
//side length is distance of a single square side
//or distance of diagonal in diamond
for(int sideLength = DATA_SIZE-1;
//side length must be >= 2 so we always have
//a new value (if its 1 we overwrite existing values
//on the last iteration)
sideLength >= 2;
//each iteration we are looking at smaller squares
//diamonds, and we decrease the variation of the offset
sideLength /=2, h/= 2.0){
//half the length of the side of a square
//or distance from diamond center to one corner
//(just to make calcs below a little clearer)
int halfSide = sideLength/2;
//generate the new square values
for(int x=0;x<DATA_SIZE-1;x+=sideLength){
for(int y=0;y<DATA_SIZE-1;y+=sideLength){
//x, y is upper left corner of square
//calculate average of existing corners
float avg = data[x][y] + //top left
data[x+sideLength][y] +//top right
data[x][y+sideLength] + //lower left
data[x+sideLength][y+sideLength];//lower right
avg /= 4.0;
//center is average plus random offset
data[x+halfSide][y+halfSide] =
//We calculate random value in range of 2h
//and then subtract h so the end value is
//in the range (-h, +h)
avg + (r.nextFloat()*2*h) - h;
valmax = Math.max(valmax, data[x+halfSide][y+halfSide]);
valmin = Math.min(valmin, data[x+halfSide][y+halfSide]);
}
}
//generate the diamond values
//since the diamonds are staggered we only move x
//by half side
//NOTE: if the data shouldn't wrap then x < DATA_SIZE
//to generate the far edge values
for(int x=0;x<DATA_SIZE-1;x+=halfSide){
//and y is x offset by half a side, but moved by
//the full side length
//NOTE: if the data shouldn't wrap then y < DATA_SIZE
//to generate the far edge values
for(int y=(x+halfSide)%sideLength;y<DATA_SIZE-1;y+=sideLength){
//x, y is center of diamond
//note we must use mod and add DATA_SIZE for subtraction
//so that we can wrap around the array to find the corners
float avg =
data[(x-halfSide+DATA_SIZE-1)%(DATA_SIZE-1)][y] + //left of center
data[(x+halfSide)%(DATA_SIZE-1)][y] + //right of center
data[x][(y+halfSide)%(DATA_SIZE-1)] + //below center
data[x][(y-halfSide+DATA_SIZE-1)%(DATA_SIZE-1)]; //above center
avg /= 4.0;
//new value = average plus random offset
//We calculate random value in range of 2h
//and then subtract h so the end value is
//in the range (-h, +h)
avg = avg + (r.nextFloat()*2*h) - h;
//update value for center of diamond
data[x][y] = avg;
valmax = Math.max(valmax, avg);
valmin = Math.min(valmin, avg);
//wrap values on the edges, remove
//this and adjust loop condition above
//for non-wrapping values.
if(x == 0) data[DATA_SIZE-1][y] = avg;
if(y == 0) data[x][DATA_SIZE-1] = avg;
}
}
}
for(int i=0; i<width; i++) {
for(int j=0; j<height; j++) {
data[i][j] = (data[i][j] - valmin)/(valmax - valmin);
}
}
}
}
+1 - 有趣的算法! – 2010-11-26 15:08:56