У меня возникли трудности с алгоритмом смещения средней точки с использованием Haxe. Я реализую это, следуя шагам, описанным здесь.
Сначала создайте массив, представляющий пустую карту. Вы начинаете с присвоения четырем углам случайного значения.
В этом квадрате создайте среднюю точку, усредняя четыре угла и добавляя небольшую «ошибку» или случайное значение. Затем создайте середины 4 сторон, усредняя два угла, между которыми находится каждый. После этих действий у вас останется 4 квадрата. Повторите шаги:
Создайте среднюю точку, усредняя четыре угла и добавляя небольшую «ошибку».
Создайте среднюю точку каждой стороны, усредняя два угла, между которыми находится каждая точка.
На каждой итерации уменьшайте диапазон ГСЧ. Таким образом, исходные несколько точек могут иметь довольно большие вариации, но более поздние точки получают только крошечные корректировки. Это обеспечивает правильное количество деталей в изображении.
Вот функция, которую я написал для выполнения этих шагов и последующей нормализации значений:
public static function generateFloatMatrix(Columns:Int, Rows:Int, RangeModifier:Float = 0.65):Array<Array<Float>>
{
//Blank 2D Array
var matrix:Array<Array<Float>> = InitFloatMatrix(Columns, Rows);
var range:Float = 1;
//Set Values for all four corners
matrix[0][0] = Math.random() * range;
matrix[Rows-1][0] = Math.random() * range;
matrix[0][Columns-1] = Math.random() * range;
matrix[Rows - 1][Columns - 1] = Math.random() * range;
//Calculates the amount of segments in base 2
var length = Math.sqrt((Columns * Columns) + (Rows * Rows));
var power:Int = Std.int(Math.pow(2, Math.ceil(Math.log(length) / Math.log(2))));
//Stores largest calculated value for normalization
var max:Float = 0;
var width:Int = Std.int(Columns);
var height:Int = Std.int(Rows);
var i:Int = 1;
while (i < power)
{
//Segment Size
width = Std.int(Columns / i);
height = Std.int(Rows / i);
for (y in 0...i)
{
for (x in 0...i)
{
//Top Left Coordinates per segment
var left = width * x;
var top = height * y;
//Find Midpoint
var xMid = Math.ceil(left + (width / 2));
var yMid = Math.ceil(top + (height / 2));
//Make sure right and bottom do not go out of bounds
var right:Int = (left + width < Columns ? left + width : Columns - 1);
var bottom:Int = (top + height < Rows ? top + height : Rows - 1);
//Sets midpoint value to average of all four corners.
matrix[yMid][xMid] =
(matrix[top][left] +
matrix[bottom][left] +
matrix[bottom][right] +
matrix[top][right]) / 4;
//trace ("Top: " + top + " - Left: " + left + " - Bottom: " + bottom + " - Right: " + right);
//Adds random value to midpoint
matrix[yMid][xMid] += Math.random() * range;
//Set side values to average of adjacent corners
matrix[top][xMid] = (matrix[top][left] + matrix[top][right]) / 2;
matrix[bottom][xMid] = (matrix[bottom][left] + matrix[bottom][right]) / 2;
matrix[yMid][left] = (matrix[top][left] + matrix[bottom][left]) / 2;
matrix[yMid][right] = (matrix[top][right] + matrix[bottom][right]) / 2;
max = Math.max(matrix[top][left], max);
}
}
//Reduces range
range *= RangeModifier;
i *= 2;
}
//Normalizes all values in matrix
for (y in 0...Rows)
{
for (x in 0...Columns)
{
matrix[y][x] /= max;
}
}
return matrix;
}
Это изображения, которые он создает, если я использую каждое значение для рендеринга каждого пикселя с указанной координатой. Все пиксели, отображаемые белым цветом, имеют значение 0, а черные — значение 1.