import { RandomSym } from "@effect/core/io/Random/definition" export class LiveRandom implements Random { readonly [RandomSym]: RandomSym = RandomSym readonly PRNG: PCGRandom constructor(readonly seed: number) { this.PRNG = new PCGRandom(seed) } get next(): Effect { return Effect.sync(this.PRNG.number()) } get nextBoolean(): Effect { return this.next.map((n) => n > 0.5) } get nextInt(): Effect { return Effect.sync(this.PRNG.integer(0)) } nextRange(low: number, high: number): Effect { return this.next.map((n) => (high - low) * n + low) } nextIntBetween(low: number, high: number): Effect { return Effect.sync(() => this.PRNG.integer(high - low) + low) } shuffle(collection: Collection): Effect> { return shuffleWith(collection, (n) => this.nextIntBetween(0, n)) } } function shuffleWith( collection: Collection, nextIntBounded: (n: number) => Effect ): Effect> { return Effect.suspendSucceed(() => { return Do(($) => { const buffer = $(Effect.sync(() => { const buffer: Array = [] for (const element of collection) { buffer.push(element) } return buffer })) const swap = (i1: number, i2: number) => Effect.sync(() => { const tmp = buffer[i1]! buffer[i1] = buffer[i2]! buffer[i2] = tmp return buffer }) const ns: Array = [] for (let i = buffer.length; i >= 2; i = i - 1) { ns.push(i) } $(Effect.forEachDiscard(ns, (n) => nextIntBounded(n).flatMap((k) => swap(n - 1, k)))) return buffer }) }) } /** * @tsplus static effect/core/io/Random.Ops default */ export const defaultRandom = new LiveRandom((Math.random() * 4294967296) >>> 0) /** * @tsplus static effect/core/io/Random.Ops live */ export const live = Layer.fromValue(Random.Tag, defaultRandom)