* * *

Природные симуляции в Javascript

Природные симуляции не повторяют природу один в один, они создают достаточно убедительную визуализацию.

Рандомизация

Случайное блуждание - путь из последовательности случайных шагов в каком-нибудь математическом пространстве.

Опишем класс объекта, который будет случайно блуждать. Поместим его в центр экрана.

var Walker = function() {
    this.x = width/2;
    this.y = height/2;
};

Дадим ему два метода.

Этот будет рисовать точку там, где находится наш объект: Walker.prototype.display = function() { stroke(0, 0, 0); point(this.x, this.y); };

А этот будет отвечать за то, куда идти. Генерируется случайное число, и в зависимости от числа выбирается направление движения. Но это неудобно, и объект не может перемещаться по диагонали:

Walker.prototype.walk = function() {
var choice = floor(random(4));
if (choice === 0) {
    this.x++;
} else if (choice === 1) {
    this.x--;
} else if (choice === 2) {
    this.y++;
} else {
    this.y--;
} 

};

Лучше написать так:

Walker.prototype.walk = function() {
var stepx = random(-1, 1);
var stepy = random(-1, 1);
this.x += stepx;
this.y += stepy;
};

Теперь создадим сам объект:

var w = new Walker();

Чтобы он что-то делал, вызовем методы w.walk и w.display внутри функции draw().

Вероятность, с которой Walker выберет то или иное направление, одинакова. Например, если есть 4 варианта направлений, шанс будет 1 к 4 (25%), независимо от направления.

Есть несколько способов, с помощью которых можно управлять вероятностью.

Можно создать массив с числами, некоторые из которых повторяются, и генерировать события, используя их. С таким массивом вероятность вытянуть чисто 1 будет 40%, число 2 - всего 20%(потому что двоек в массиве меньше) и число 3 - 40%:

stuff[0] = 1;
stuff[1] = 1;
stuff[2] = 2;
stuff[3] = 3;
stuff[4] = 3;

Можно сгенерировать случайное число, и делать что-то только если число попало в указанный диапазон.

var prob = 0.10;
var r = random(1);

if (r < prob) {
    ...
} else {
    ...
}

Можно выбирать между несколькими вариантами направлений.

var num = random(1);

if (num < 0.6) {
    ...
} else if (num < 0.7) {
    ...
} else {
    ...
}

Для нескольких вариантов можно рассчитать вероятность.

    0              60   70      100
|---------------|====|++++++++|
              60%  10%      30%
(0+60)          (60+10)       (70+30)
n < 0.6         n > 0.6       n > 0.6
                n < 0.7       n > 0.7

Нормальное распределение (распределение Гаусса или Гаусса-Лапласа)

см. Нормальное распределение — Википедия

Стандартное отклонение показывает, как распределены значения относительно среднего в выборке.

Сначала нужно посчитать отклонение(разницу между значением и средним(чтобы найти среднее значение, нужно всё сложить, и поделить на количество)) для каждого отдельного значения, и возвести это число в квадрат. Далее нужно найти среднее из получившихся чисел(сложить отдельные отклонения и поделить на количество значений). Узнав квадратный корень из этого числа, получим стандартное отклонение.

Создадим переменную, которая будет “генерировать” случайное число от 0 до 1.

var generator = new Random(1);

Вызовем функцию, которая использует нормальное распределение со средним значением 0 и стандартным отклонением 1:

var num = generator.nextGaussian();

Чтобы использовать свои значения, можно создать для стандартного отклонения и среднего свои переменные:

var standardDeviation = 60;
var mean = 200;
var x = standardDeviation * num + mean;

Шум Перлина

Кен Перлин создал эту функцию во время работы над фильмом Трон в начале 80-х, для генерации текстур.

В ProcessingJS есть встроенная функция для шума Перлина:

noise()

Функция принимает не минимальное и максимальное значение, как random(), а время(но это только удобная метафора), и возвращает значение между 0 и единицей.

var t = 0;

var draw = function() {
    var n = noise(t);
    println(n);
    t += 0.01; // Move forward in time
};

Чем быстрее растёт t, тем плавнее получится шум.

Чтобы использовать шум, его можно сохранить в переменную и с помощью map() масштабировать на другие размеры.

var n = noise(t);
var x = map(n, 0, 1, 0, width);

Шум в двухмерном пространстве

Если визуализировать шум в двухмерном пространстве, получится что-то похожее на облака. Чтобы это сделать, нужно использовать вложенный цикл с отдельными от счётчика переменными для шума. (использовать в шуме значения типа 1, 2, 3 не получится, будет ничего не видно, поэтому нужно использовать отдельную переменную, которая будет увеличиваться медленно, на 0.01 например).

Не стоит увлекаться готовыми алгоритмами для рандомизации и использовать их для всего подряд, как простое решение. Шум Перлина это всего лишь инструмент и нужно пользоваться им осознанно.

(ещё не всё!)

Источники

Advanced JS: Natural Simulations | Computer programming | Khan Academy