package snake /** * m04 random: a tiny "state monad" for randomness. A Random[A] is a function seed => (A, nextSeed), * so every draw is a pure function and the seed is passed along explicitly instead of hidden. * Seeds and values are unsigned 32-bit numbers kept in a Long. */ final case class Random[A](run: Long => (A, Long)): def map[B](f: A => B): Random[B] = Random { seed => val (a, next) = run(seed) (f(a), next) } def flatMap[B](f: A => Random[B]): Random[B] = Random { seed => val (a, next) = run(seed) f(a).run(next) } object Random: def pure[A](a: A): Random[A] = Random(seed => (a, seed)) // The mulberry32 arithmetic is done in Int: `*` wraps like 32-bit multiplication and `>>>` is unsigned. // `& 0xFFFFFFFFL` turns the result back into an unsigned value held in a Long. lazy val nextUint32: Random[Long] = Random { seed => val s = seed.toInt + 0x6d2b79f5 val t1 = (s ^ (s >>> 15)) * (s | 1) val t2 = t1 ^ (t1 + (t1 ^ (t1 >>> 7)) * (t1 | 61)) val value = t2 ^ (t2 >>> 14) (value.toLong & 0xffffffffL, s.toLong & 0xffffffffL) } def intBelow(n: Int): Random[Int] = nextUint32.map(v => (v % n).toInt)