Pos Random

4,167
68
693
Народ! Помогите придумать рандом, зависящий от координат блока (x, y и z).
Задача: чтобы в каждом блоке мира выдавал рандомное, но постоянное значение в заданных приделах.
Пробовал тупо перемножать координаты по типу:
Код:
(Math.max(1, Math.abs(pos.getX())) * Math.max(1, Math.abs(pos.getY())) * Math.max(1, Math.abs(pos.getZ()))) % диапазон
Более менее работает, если диапазон равен 7-ми или 9-ти, например. Однако, если нужно получить 0 или 1, то есть диапазон равен 2, уже сложнее... На чётной высоте, естественно, выдаёт стабильно 0.
То есть метода должна быть посложнее обычного перемножения...

Может быть, в ваниле уже есть нечто подобное?
Смотрел код из рендера кувшинки... Она же как раз поворачивается под разными углами.
Однако, в битовых операциях я не силён и как его перенастроить под заданный диапазон, не очень понимаю.
Вод код: 
Код:
long l = (long)(x * 3129871L) ^ (long)z * 116129781L ^ (long)y;
l = l * l * 42317861L + l * 11L;
int i1 = (int)(l >> 16 & 3L);


Возможно, можно придумать что-нибудь проще и быстрее.
Спасибо за ответы )
 
Что-то я не понял. Рандомное, но постоянное... Сам понял хоть, что сказал? Тоже самое, что константа, но не константа.
Можешь по-конкретнее разъяснить, что ты хочешь?
 
Ты же ротиворечишь законам природы! "Рандум, зависящий от положения блоков". Не рандум, а рандумище!
 
Heitem написал(а):
Ты же ротиворечишь законам природы! "Рандум, зависящий от положения блоков". Не рандум, а рандумище!

Пойду на пикабу выложу новый мемасик с нагиевым :D
 
Код:
int i1 = (int)(l >> 16 & 3L);
& 3L - это маска. Отсекает все ненужные биты.

Код:
int i1 = Math.abs(l % диапазон));


& работает в разы быстрее, чем %. Но диапазоны задавать крайне неудобно. Можно только n^2 - 1. Но т.к. у них диапазон там 0...3, то они микрооптимизировали.
 
Это мультипликативная хэш-функция. Можешь погуглить, возможно найдешь другие аналогичные функции.
Еще могу предложить использовать CRC.
Например:
Код:
ByteBuffer buf = ByteBuffer.allocate(9);
CRC32 crc32 = new CRC32();
buf.putInt(0, x);
buf.putInt(4, y);
buf.putInt(5, z);
crc32.update(buf);
System.out.println(crc32.getValue());
 
Да, спасибо... Как преобразовать допёр... Но ситуация, на самом деле аналогичная )
Только при диапазоне 2 теперь всё время выдаёт 0. Если ставлю хотя бы 3, уже начинает работать...
...
В общем, сделал вот так:
Код:
int i1 = (int)Math.abs((l % (seed + 3)) % seed);

Но, как я понимаю, таким методом можно использовать и моё первое перемножение координат...


О! А что такое CRC32?


Эм... И куда тут писать диапазон? .allocate(9); ?
 
На википедии более-менее адекватно это объясняется.
Если кратко, то это функция вычисляющая по массиву байт некоторое число, зависящее от каждого байта и их порядка.
И я ошибся с порядком байт, правильно так:
Код:
ByteBuffer buf = ByteBuffer.allocate(9); // создание ByteBuffer из 9 байт. int занимает 4 байта, но высоту можно хранить в одном байте, поэтому требуется всего 9 байт.
CRC32 crc32 = new CRC32();
buf.putInt(0, x); // Запись четырех байт x, 0 - смещение в буффере.
buf.put(4, (byte)y); // Запись одного байта y, 4 - смещение в буффере.
buf.putInt(5, z);
crc32.update(buf);
System.out.println(crc32.getValue());
Результат вычислений 32-разрядное число от 0 до 4294967295. Соответственно можно так же взять остаток от деления или битовую маску.
Также совсем не обязательно каждый раз создавать новые экземпляры ByteBuffer и CRC32, достаточно их сбросить: buf.clear(); и crc32.reset();
 
Ну да... И так тоже работает...
Хотя, здесь опять беда с диапазоном "2" (((
Код:
Random r = new Random(pos.getX() + pos.getY() + pos.getZ());
 System.out.println(r.nextInt(2));
Всегда выдаёт единицу...
Диапазоны 3 и 4 не пробовал, но 5 фурычит...

А теперь вопрос: что из этого будет работать быстрее? Создание каждый раз рандома или ByteBuffer-а (увы, придётся создавать их каждый раз, так как всё это мне нужно проворачивать в апдейте блока) или же операции с long как в примере из рендера кувшинки и деление с остатком?
 
Мог бы использовать и майнкравтовкое.
Я не проверял, но должно работать.

Код:
int i1 = Math.abs((l >> 16) % (long) диапазон));

С Random мне кажется вообще какой-то мутный вариант.
 
При использовании CRC32 не нужно каждый раз создавать новый ByteBuffer, достаточно лишь его сбросить.
Теоретически вариант с CRC32 мог бы быть быстрее всех остальных, т.к. у современных процессоров есть инструкция для расчета CRC (которая возможно в java.util.zip.CRC32 не используется), но из-за вызова множества методов наверняка будет медленнее.
И не обязательно использовать java.util.zip.CRC32, можно написать свой вариант. Мне больше нравится CRC, т.к. хотя бы математическое обоснование понятно.

Скорее всего вариант с Random(seed) самый медленный, java.util.zip.CRC32 немного быстрее.
 
Если б я его ещё сам понимал, может и написал бы свой вариант.
Ну да ладно... Спасибо всем.
Всё-таки остановлюсь на кувшинке... Раз уж она в ваниле уже используется.
Всё равно, что её, что CRC нужно делить...
 
Назад
Сверху