This is a PRNG, built on Jacob Rus' implementation and modified slightly for a user-friendly API.
See here for source: https://observablehq.com/@jrus/permuted-congruential-generator
import PCGR from './pcgr.js';
const random = PCGR();
// get random values between 0 (inclusive) and 1 (exclusive)
const a = random.next();
// reset state to a deterministic 64-bit seed
random.seed(mySeed);
// or, reset state to a non-deterministic browser-random seed
random.seed(null);
// continue generating random values...
const b = random.next();
If you have a hash with 64 bits or more, you can use this to get a seed from it.
Note: This takes the first 64 bits of the hash; maybe another solution would somehow use more bits in the hash.
// example hash, e.g. Ethereum token ID
const hash = '0xa7d8d9ef8d8ce8992df33d8b8cf4aebabd5bd270';
// Generate RNG
const seed = getStateFromHash(hash);
const random = PCGR(seed);
console.log(random.next());
// Take lower 64 bits from a 0x-prefixed hash and return 64 bit integer
function getStateFromHash(hash) {
// get bytes, let's assume the hash is at least 64bit long
const nBytes = 8;
const bytes = [];
for (let j = 0; j < nBytes; j++) {
const e0 = 2 + 2 * j;
bytes.push(parseInt(hash.slice(e0, e0 + 2), 16));
}
// Get a 64-bit integer stored in 4-element uint16array from the 8 bytes
const uint16 = new Uint16Array(4);
const dv = new DataView(uint16.buffer);
for (let i = 0; i < nBytes; i++) {
dv.setUint8(i, bytes[i % bytes.length]);
}
return uint16;
}
I've added another solution to use the entire hash (so that any small change in the string produces a new PRNG). This is done by hashing the decimal bytes to two different unsigned 32-bit integers, and then combining them into a 64 bit seed.
See x_hash.js
.