type int32 = number;
export class XorShift {
static MIN_INTEGER: int32 = 0;
static MAX_INTEGER: int32 = (2 ** 32 - 1) | 0;
private _inc: int32;
private _seed: int32;
constructor(seed: number, inc: number) {
this._seed = seed | 0;
this._inc = inc | 0;
}
static new_random() {
return XorShift.from_seed(random_int(2 ** 10, 2 ** 31));
}
static from_seed(seed: number) {
return new XorShift(seed | 0, seed | 0);
}
get seed() {
return this._seed;
}
get inc() {
return this._inc;
}
reseed(seed: number) {
this._seed = seed | 0;
this._inc = seed;
}
clone() {
return new XorShift(this._seed, this._inc);
}
next(): int32 {
let t = this._seed;
t ^= (t | 0) << 13;
t ^= (t | 0) << 25;
t ^= (t | 0) << 9;
this._inc = (this._inc + 1368297235087925) | 0;
t = Math.abs((t + this._inc) | 0);
this._seed = t;
return t;
}
random() {
return 2 ** -31 * this.next();
}
random_integer(min: number, max: number) {
return min + Math.floor(this.random() * (max - min));
}
random_choice(xs: A[]): A | null {
if (xs.length === 0) {
return null;
} else {
const choice = this.random_integer(0, xs.length);
return xs[choice];
}
}
random_choice_mut(xs: A[]): A | null {
if (xs.length === 0) {
return null;
} else {
const choice = this.random_integer(0, xs.length);
const result = xs[choice];
xs.splice(choice, 1);
return result;
}
}
random_choice_many(size: number, xs: A[]): A[] {
const result = [];
const candidates = xs.slice();
while (result.length < size) {
const entry = this.random_choice_mut(candidates);
if (entry == null) {
return result;
} else {
result.push(entry);
}
}
return result;
}
random_weighted_choice(xs: [number, A][]): A | null {
if (xs.length === 0) {
return null;
} else {
let total = 0;
for (const [x, _] of xs) {
total += x;
}
const sorted_xs = xs.sort(([x1, _1], [x2, _2]) => x2 - x1);
let choice = this.random_integer(0, total);
for (const [score, item] of sorted_xs) {
if (choice <= score) {
return item;
} else {
choice -= score;
}
}
}
throw new Error(`internal: weighted choice picked none`);
}
}
function random_int(min: number, max: number) {
return min + Math.floor(Math.random() * (max - min));
}