caro5 / shared /random.ts
Pedro de Carvalho
Add shared checks
ea1fe68
Raw
History Blame Contribute Delete
1.15 kB
export class SeededRandom {
private state: number
constructor(seed: number) {
this.state = seed >>> 0
if (this.state === 0) this.state = 0x6d2b79f5
}
next(): number {
this.state += 0x6d2b79f5
let t = this.state
t = Math.imul(t ^ (t >>> 15), t | 1)
t ^= t + Math.imul(t ^ (t >>> 7), t | 61)
return ((t ^ (t >>> 14)) >>> 0) / 4294967296
}
int(maxExclusive: number): number {
return Math.floor(this.next() * maxExclusive)
}
pick<T>(items: readonly T[]): T {
if (items.length === 0) throw new Error('Cannot pick from an empty list')
return items[this.int(items.length)]
}
fork(offset: number): SeededRandom {
return new SeededRandom((this.state + Math.imul(offset + 1, 0x9e3779b9)) >>> 0)
}
}
export function weightedIndex(weights: readonly number[], rng: SeededRandom): number {
const total = weights.reduce((sum, w) => sum + Math.max(0, w), 0)
if (total <= 0) return rng.int(weights.length)
let needle = rng.next() * total
for (let i = 0; i < weights.length; i++) {
needle -= Math.max(0, weights[i])
if (needle <= 0) return i
}
return weights.length - 1
}