Files
2026-10-29 00:07:27 +01:00

37 lines
1.2 KiB
Scala

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)