From c39ae32626faafc888944ec2649d3956319981a9 Mon Sep 17 00:00:00 2001 From: David North Date: Mon, 7 Oct 2024 21:29:50 +0100 Subject: [PATCH] Adds additional scaladocs to the Dice class, and comments to Dice tests --- .../scala/indigo/gameengine/GameEngine.scala | 2 +- .../scala/indigo/gameengine/GameLoop.scala | 7 ++- .../main/scala/indigo/shared/dice/Dice.scala | 52 ++++++++++++++++++- .../scala/indigo/shared/dice/DiceTests.scala | 32 +++++++----- 4 files changed, 75 insertions(+), 18 deletions(-) diff --git a/indigo/indigo/src/main/scala/indigo/gameengine/GameEngine.scala b/indigo/indigo/src/main/scala/indigo/gameengine/GameEngine.scala index c00de6e1c..a1a1fec5d 100644 --- a/indigo/indigo/src/main/scala/indigo/gameengine/GameEngine.scala +++ b/indigo/indigo/src/main/scala/indigo/gameengine/GameEngine.scala @@ -178,7 +178,7 @@ final class GameEngine[StartUpData, GameModel, ViewModel]( audioPlayer.addAudioAssets(accumulatedAssetCollection.sounds) - val time = if (firstRun) 0 else gameLoopInstance.runningTimeReference + val time = (if (firstRun) 0 else gameLoopInstance.runningTimeReference) + gameLoopInstance.initialSeed if (firstRun) platform = new Platform(parentElement, gameConfig, globalEventStream, dynamicText) diff --git a/indigo/indigo/src/main/scala/indigo/gameengine/GameLoop.scala b/indigo/indigo/src/main/scala/indigo/gameengine/GameLoop.scala index 1818eb420..5d52e021c 100644 --- a/indigo/indigo/src/main/scala/indigo/gameengine/GameLoop.scala +++ b/indigo/indigo/src/main/scala/indigo/gameengine/GameLoop.scala @@ -21,8 +21,11 @@ import indigo.shared.time.Millis import indigo.shared.time.Seconds import scala.collection.mutable +import scala.scalajs.js.Date import scala.scalajs.js.JSConverters._ +val initialDate = new Date() + final class GameLoop[StartUpData, GameModel, ViewModel]( rebuildGameLoop: AssetCollection => Unit, boundaryLocator: BoundaryLocator, @@ -35,7 +38,7 @@ final class GameLoop[StartUpData, GameModel, ViewModel]( startFrameLocked: Boolean, renderer: => Renderer ): - + val initialSeed = initialDate.valueOf() @SuppressWarnings(Array("scalafix:DisableSyntax.var")) private var _gameModelState: GameModel = initialModel @SuppressWarnings(Array("scalafix:DisableSyntax.var")) @@ -131,7 +134,7 @@ final class GameLoop[StartUpData, GameModel, ViewModel]( gameTime, events, _inputState, - Dice.fromSeconds(gameTime.running), + Dice.fromSeconds(gameTime.running + initialSeed), boundaryLocator, renderer ) diff --git a/indigo/indigo/src/main/scala/indigo/shared/dice/Dice.scala b/indigo/indigo/src/main/scala/indigo/shared/dice/Dice.scala index 8342c546f..62bea348c 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/dice/Dice.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/dice/Dice.scala @@ -168,33 +168,81 @@ object Dice: val r: Random = new Random(seed) - def roll: Int = roll(sides) + /** Roll an Int from 1 to the number of sides on the dice (inclusive) + * + * @return + */ + def roll: Int = + roll(sides) + + /** Roll an Int from 1 to the specified number of sides (inclusive) + * + * @param sides + * @return + */ def roll(sides: Int): Int = r.nextInt(sanitise(sides)) + 1 + /** Roll an Int from 0 to the number of sides on the dice (exclusive) + * + * @return + */ def rollFromZero: Int = - roll - 1 + rollFromZero(sides) + /** Roll an Int from 0 to the specified number of sides (exclusive) + * + * @param sides + * @return + */ def rollFromZero(sides: Int): Int = roll(sides) - 1 + /** Roll an Int from the range provided (inclusive) + * + * @param from + * @param to + * @return + */ def rollRange(from: Int, to: Int): Int = val f = Math.min(from, to) val t = Math.max(from, to) roll(t - f + 1) + f - 1 + /** Produces a random Float from 0.0 to 1.0 + * + * @return + */ def rollFloat: Float = r.nextFloat() + /** Produces a random Double from 0.0 to 1.0 + * + * @return + */ def rollDouble: Double = r.nextDouble() + /** Produces a random alphanumeric string of the specified length + * + * @param length + * @return + */ def rollAlphaNumeric(length: Int): String = r.alphanumeric.take(length).mkString + /** Produces a random alphanumeric string 16 characters long + * + * @return + */ def rollAlphaNumeric: String = rollAlphaNumeric(16) + /** Shuffles a list of values into a random order + * + * @param items + * @return + */ def shuffle[A](items: List[A]): List[A] = r.shuffle(items) } diff --git a/indigo/indigo/src/test/scala/indigo/shared/dice/DiceTests.scala b/indigo/indigo/src/test/scala/indigo/shared/dice/DiceTests.scala index 923c72a4d..af134a9ac 100644 --- a/indigo/indigo/src/test/scala/indigo/shared/dice/DiceTests.scala +++ b/indigo/indigo/src/test/scala/indigo/shared/dice/DiceTests.scala @@ -62,9 +62,10 @@ class DiceTests extends munit.FunSuite { } test("all dice rolls have an approximately uniform distribution") { - val diceSides = 64 - val numRuns = 200_000_000 - val dice = Dice.diceSidesN(diceSides, 0) + val diceSides = 63 + val numRuns = 200_000_000 + val dice = Dice.diceSidesN(diceSides, 0) + val expectedDistribution = 1.0 / diceSides val generatedNums = Array .range(0, numRuns) @@ -73,11 +74,12 @@ class DiceTests extends munit.FunSuite { acc.updated(roll, acc.getOrElse(roll, 0) + 1) } + // Ensure that we have the right numbers generated (they should all have been created) assertEquals(generatedNums.size, diceSides) assertEquals(generatedNums.head._1, 1) assertEquals(generatedNums.last._1, diceSides) - val expectedDistribution = 1.0 / diceSides + // Check the even distribution of the generated numbers generatedNums.foreach { case (num, count) => val distribution = count.toDouble / numRuns assert( @@ -88,10 +90,11 @@ class DiceTests extends munit.FunSuite { } test("all dice rolls in rollRange have an approximately uniform distribution") { - val diceSides = 64 - val halfSides = diceSides / 2 - val numRuns = 200_000_000 - val dice = Dice.diceSidesN(diceSides, 0) + val diceSides = 63 + val halfSides = Math.floor(diceSides / 2.0).toInt + val numRuns = 200_000_000 + val dice = Dice.diceSidesN(diceSides, 0) + val expectedDistribution = 1.0 / halfSides val generatedNums = Array .range(0, numRuns) @@ -100,11 +103,12 @@ class DiceTests extends munit.FunSuite { acc.updated(roll, acc.getOrElse(roll, 0) + 1) } - assertEquals(generatedNums.size, halfSides + 1) + // Ensure that we have the right numbers generated (only numbers from just before half way through the number of sides should have een created) + assertEquals(generatedNums.size, (diceSides - halfSides) + 1) assertEquals(generatedNums.head._1, halfSides) assertEquals(generatedNums.last._1, diceSides) - val expectedDistribution = 1.0 / halfSides + // Check the even distribution of the generated numbers generatedNums.foreach { case (num, count) => val distribution = count.toDouble / numRuns assert( @@ -115,8 +119,9 @@ class DiceTests extends munit.FunSuite { } test("all dice rolls in rollRange(1, 4) have an approximately uniform distribution") { - val numRuns = 200_000_000 - val dice = Dice.diceSidesN(4, 0) + val numRuns = 200_000_000 + val dice = Dice.diceSidesN(4, 0) + val expectedDistribution = 0.25 val generatedNums = Array .range(0, numRuns) @@ -125,11 +130,12 @@ class DiceTests extends munit.FunSuite { acc.updated(roll, acc.getOrElse(roll, 0) + 1) } + // Ensure that we have the right numbers generated (they should all have been created) assertEquals(generatedNums.size, 4) assertEquals(generatedNums.head._1, 1) assertEquals(generatedNums.last._1, 4) - val expectedDistribution = 0.25 + // Check the even distribution of the generated numbers generatedNums.foreach { case (num, count) => val distribution = count.toDouble / numRuns assert(