Как сделать?
…
Как сделать в QSP генератор псевдослучайных чисел?
“Нормально никак не сделать… Можно конечно, написать высокоуровневые преобразования в двоичное представление, а потом ещё всякие там XOR’ы, да shift’ы туда-сюда. Правда это может не потянуть вычислительный бюджет конкретной задачи…”
А, если еще сделать так, что RNG не последовательный (да ещё сохраняет ключ для следующей генерации), а например принимает еще 2 произволных аргумента, и мы можем сразу взять 100500-е значение?
“Ну, тогда можно написать высокоуровневые преобразования для двойной точности, к ним в догонку полиноминалы для тригонометрии, а потом как например в некоторых шейдерах - cosine (относительно скоростные) мумбо-юмбо, там ведь как раз-таки координаты пикселей используются. Но с вычислительным бюджетом проблем только прибавится…”
Ну раз так, тогда хочу всё то же самое, но без высокоуровневых костылей и изоленты.
“Иди-ка ты на *** с такими замашками!”
Цена вопроса:
- RNG, промежуточные ключи генерации нафиг не должны быть (их ведь ещё складывать куда-то надо).
- У нас есть только математика QSP +*[mod] (только хардкор, только так)
- Числа 32-битные, знаковые целые (однако, минимальное отрицательное, похоже прикрыто! уже что-то)
- Скорость максимальная (Вообще это отдельная тема, но сегодня пощадим нейроны).
- Значит, пермутатация будет нихрена не “косиновая” как в пиксельных шейдерах обычно делают…
- а ещё скажем твёрдое “нет” XOR-shift’ам и прочим “мурмурам”…
Теперь, если приглядеться: Умножение-то с переполнением! Как впрочим и сложение. Остаток от деления - тоже в наличии. А про простые числа даже в лесу слышали.
Так, есть ли в природе такой метод для QSP, или нет (без высокоуровневых преобразований)?
Есть как минимум один!
Только перед этим примем вынужденное условие: метод не подходит для научного, промышленного, военного применения.
Т.е. не будем исползовать в качестве решения в профессиональной криптографии, квантовой физике, разработке вооружений и всего такого прочего, однако нам с избытком хватит для компьютерных игр.
Плюсом является скорость - примерно 28 “обычных” QSP операций.
Используется как: number = func(”f_rng_2d”, seed, min, max, x, y)
if (args[3] = 0): args[3] = 13763
if (args[4] = 0): args[4] = 10613
args[0] += args[3] * args[3] * args[4]
args[0] *= args[4] * args[4] * args[3]
args[0] += args[4]
args[0] = (args[0] * 16807) mod 127773
args[0] += args[3]
if (args[0] < 0): args[0] += 2147483647
args[0] = ((args[0] mod 127773) * 16807) mod 127773
args[0] = (args[0] * 16807) mod 127773
result = args[1] + ((max(args[1], args[2]) - args[1] + 1) * (args[0] - 1) / 127772)
Ниже прикреплён файл с примером.
_test_rng_2d.rar
seed - произволная величина, условно “карта” генерации.
min, max - как и в rand() и с тем же умыслом.
x, y - дополнительные числовые аргументы.
При одном и том же сиде, для одних и тех же x и y, результат (очевидно, ведь в этом и весь смысл) гарантирован.
При изменении сида даже на единицу - avalanche effect гарантируется.
Для турбо-мудрых: Существут проблема “хорошего” сида, очень похожая на ту, что есть в XOR-shift алгоритмах. Однако в масштабах компьютерных игр, никто ничего не заметит (впрочем как и в случае с XOR-shift). Так же поскольку ВСЯ пермутация производится в 32-битных величинах (!), не стоит использовать экстремальные (в бинарном аспекте) значения x и y. Но всё работает достаточно хорошо, и границу (в десятеричном выражении) я бы обозначил на десятках миллонов. При больших значениях (миллиард), могут начать проявляться паттерны.
Из-за очень высокой скорости алгоритма, можно использовать полученную псевдо-случайную величину как сид для повторных генераций, иммитируя реально космически-гигантские объемы данных. Вообще я ничего не написал про применение, считая что все кому надо и так знают. Для тек кто не понял - пример: карта выдуманной случайно сгенерированной галактики (но по размеру приблеженной к реальной) в компьютерной игре может занимать… одно число (сид). Или как записать квадриллион случайно сгенерированных свойств… опять-таки одним числом (сидом), а потом еще и разом получить любое из них. Теперь вы видите, как “они это делают”.
Все дело в распределении результатов - оно ни на бит не случайное(!), но НАСТОЛЬКО приближенно к нему, что без статистичеких метов анализа, никто и никогда не поймет. Вот именно в этом и есть вся суть ВСЕХ подобных алгоритмов.
(Злой Механик)
Сделал по старинке через раздел, убрал loop. Скажите, получается я еще и массив неправильно прописал? Мне нужен капитальный массив с координатами и типом объекта, а плеер мне пишет про ошибку синтаксиса.
! Общая генерация границ мира
max_X[1]=24 & !допустим это максимальные границы карты №1
max_Y[1]=24
x_a=1
y_a=1
!Случайное наполнение
y_a=1
:loopY
x_a=1
:loopX
type_sym=rand(1,5)
if type_sym=1: $x[x_a,y_a,map,'символ']='<font color="gray">.</font>' & $x[x_a,y_a,map,'описание']='камушки' & $x[x_a,y_a,map,'тип']='поверхность'
if type_sym=2: $x[x_a,y_a,map,'символ']='<font color=rgb(80,50,50)>.</font>' & $x[x_a,y_a,map,'описание']='пол' & $x[x_a,y_a,map,'тип']='поверхность'
if type_sym=3: $x[x_a,y_a,map,'символ']='<font color="green">ш</font>' & $x[x_a,y_a,map,'описание']='куст' & $x[x_a,y_a,map,'тип']='поверхность'
if type_sym=4: $x[x_a,y_a,map,'символ']='Т' & $x[x_a,y_a,map,'описание']='дерево' & $x[x_a,y_a,map,'тип']='стена'
if type_sym=5: $x[x_a,y_a,map,'символ']='.' & $x[x_a,y_a,map,'описание']='пол' & $x[x_a,y_a,map,'тип']='поверхность'
if x_a<=max_X[1]: x_a+=1 and jump'loopX'
if y_a<=max_Y[1]: y_a+=1 and jump'loopY'
ByltrcДамир Белялов,
Индекс исправь - [x_a,y_a,map,’символ’] -> [’<<x_a>>,<<y_a>>,<<map>>, символ’]
Привет! Спасибо массив перестал вылетать. К сожалению, карта из символов не прорисовывается. То ли массив не записывается, то ли я неграмотно его записал, опечатался, но я снова облажался, увы. Может у вас взор незамыленный, сможете найти, почему не прогружается рандомное наполнение мира. У меня из-за этой поганой сетки стоит проект весь((
Основные локации связанные с проблемой это boot ($scr_map_draw), gen_world, travel - на ней по идее должна была нарисоваться карта для игрока.
project.zip
Дамир Белялов,
x y у тебя где задается? У тебя они равны 0, а для значений меньше единицы массив не заполнен.
задается в локации gen_world в цикле, в начале процесса x_a=1 потом в цикле при x_a<maxX[1] переменная x_a+=1 и снова цикл выполняется
Дамир Белялов,
Ты для отрисовки карты используешь переменную x, а не x_a.
Придётся все-таки заменять? Я думал воспользуюсь временно при генерации переменной x_a, а персонаж когда будет перемещаться то буду использовать x.
Дамир Белялов,
Нет, это разные переменные для разных целей.
Можешь в дискорд зайти? а то мы весь форум зафлудим.
У тебя x_a для генерации, а x - для отрисовки от центра карты, как я понял. Но центр у тебя сейчас не указан и является нолем. У тебя не существует значений масиива для значения 0 и меньше. А ты просишь рисовать 0, -1, -2.
центр в отрисовке показан символом @, но на самом деле координата должна быть сгенерирована, у меня вся карта по идее 24 на 24 сгенерирована.
Дамир Белялов,
$x[’<<x-2>>,<<y-2>>,<<map>>, символ’]
Вот твоя переменная для отрисовки тайла. У тебя x=0, y=0
$x[’<<-2>>,<<-2>>,<<map>>, символ’]
Вот что получает плеер.
Где у тебя значение тайла для этого элемента массива?
локация ‘Office’ действие “Выйти” при выполнении действия x=12 y=12
Дамир Белялов,
Отбой тревоги), это я напрямик в локу защел. У тебя в генераторе map не задан, т.е. 0, а в параметрах ты просишь 1, либо в генератор добавь map=1 либо при переходе на карту map=0.
Дамир Белялов,
Никак. Либо таблица, либо выбор одноразмерных символов, либо вместо символов - картинки одинакового размера.
