Обычный случайный порядок может быть реализован так же, как
- случайное выпадение предметов на некотором расстоянии
- поднимая их слева направо
Мы можем настроить шаг опускания, опускать каждый элемент не во весь диапазон, а в какое-то скользящее окно. Пусть N
будет количеством элементов в массиве, ширина окна будет w
, и мы будем перемещать его на каждом шаге на off
. Тогда off*(N-1) + w
будет общей шириной диапазона.
Вот функция, которая искажает позиции элементов, но не полностью случайным образом.
function weak_shuffle($a, $strength) {
$len = count($a);
if ($len <= 1) return $a;
$out = array();
$M = mt_getrandmax();
$w = round($M / ($strength + 1)); // width of the sliding window
$off = ($M - $w) / ($len - 1); // offset of that window for each step.
for ($i = 0; $i < $len; $i++) {
do {
$idx = intval($off * $i + mt_rand(0, $w));
} while(array_key_exists($idx, $out));
$out[$idx] = $a[$i];
}
ksort($out);
return array_values($out);
}
$strength = 0
~ обычный случайный порядок.
$strength = 0.25
~ желаемый результат (40,5%, 25,5%, 22%, 12% для elephant
)
$strength = 1
первый элемент никогда не будет после последнего.
$strength >= 3
массив фактически никогда не перемешивается
Площадка для тестирования:
$animals = array( 'elephant', 'dog', 'cat', 'mouse' );
$pos = array(0,0,0,0);
for ($iter = 0; $iter < 100000; $iter++) {
$shuffled = weak_shuffle($animals, 0.25);
$idx = array_search('elephant', $shuffled);
$pos[$idx]++;
}
print_r($pos);