Home > Software engineering >  Pseudo Randomness in Kotlin and/or Java
Pseudo Randomness in Kotlin and/or Java

Time:11-23

I am developing a game where the main mechanic of it involves randomness. This randomness needs to be repeatable with a "seed" that way other players could use the same seed as another player and get the same results. Here I have created some simple code that generates 10 random numbers on two different function calls, given the seed "123". As expected, the results are the same each time.

fun random() {
    val random = Random(seed = 123)
    for (x in 1..10) {
        println(random.nextDouble())
    }
}

fun main() {
    println("First time")
    random()
    println("Second time")
    random()
}

/** Results **/
0.9454258822238865
0.5018059782116884
0.5130601792560605
0.018549629644654342
0.9999394563830194
0.3556915641038113
0.678745227934038
0.5852996710723596
0.27536007063951506
0.5666654953957303

Let's say now I want to get the 5th number in this sequence without having to call random.nextDouble 5 times. Maybe I want to tell the players given their seed when they could expect some event to happen, or how long until it happens.

In this example, 5 times wouldn't be that bad, but in the game players could generate random doubles from here thousands of times, this process would take forever to reverse engineer by brute force. So given x times, what would the value generated from random.nextDouble be when starting at a specified seed?

Any help is appreciate on this, thank you.

CodePudding user response:

Instead of calling nextDouble() on the same Random instance get each random number in the sequence, why not just use a whole new Random object and increment the seed?

For example:

import kotlin.random.Random

class RandomNumberGenerator(private val seed: Int) {
    private var counter: Int = 0

    fun nextRandom(): Double {
        return randomLookingAhead(1)
            .also { counter   }
    }
    
    fun randomLookingAhead(numberOfStepsAhead: Int): Double {
        return Random(seed   counter   numberOfStepsAhead).nextDouble()
    }

}

fun main(args: Array<String>) {
    testGenerator(22, 5, 21)
    testGenerator(212, 9, 291)
    testGenerator(113, 52, 211)
}

fun testGenerator(seed: Int, stepsBefore: Int, stepsLookingAhead: Int) {
    val generator = RandomNumberGenerator(seed)
    for (i in 1..stepsBefore)
        generator.nextRandom()
    println("Predicting $stepsLookingAhead steps ahead: ${generator.randomLookingAhead(stepsLookingAhead)}")
    for (i in 1 until stepsLookingAhead)
        generator.nextRandom()
    println("Random after going through $stepsLookingAhead steps: ${generator.nextRandom()}")
}

Playground: https://pl.kotl.in/KZ0_5Y6hQ

Generates:

Predicting 21 steps ahead: 0.9939169328812599
Random after going through 21 steps: 0.9939169328812599
Predicting 291 steps ahead: 0.4408283313079112
Random after going through 291 steps: 0.4408283313079112
Predicting 211 steps ahead: 0.5762401874139372
Random after going through 211 steps: 0.5762401874139372
  • Related