0

I'm trying to filter from the following enum to select one of the values based on a random chance.

enum class rewardType(var chance : Float, var tier : Int) {
    TIER_1(60.0F,0),
    TIER_2(45.0F,1),
    TIER_3(20.0F,2),
    TIER_4(10.0F,3),
    TIER_5(2.0F,4),
    TIER_6(1.0F,5)
}

At the moment I'm selecting a value using this code.

val (tier, tierChance) = rewardType.values().filter { it.chance.passRandom() }
    .map { Pair(it.chance, it.tier) }

There are my random utility functions also

val random = ThreadLocalRandom.current()!!

fun randomChance(value: Float) = random.nextFloat() * value

fun Float.passRandom() = randomChance(100F) < this

At the moment the majority of the time it will accurately select one of the tier values with no issue. However around %15 of the time I will get an IndexArrayOutOfBounds.

I know that this is because the chances in the enum are spread to far apart(Because if I add more values to the enum, the chances aren't spread out as much as they are, then this Exception doesn't occur).

How do I fix this error? or Is there a better way of doing this?

Feel free to answer using Java

3 Answers3

2

It seems that when your randomChance(100F) returns a float greater than 60F, no RewardType gets selected (or I misunderstood something - I don't know Kotlin, really; please verify this).

Besides, it seems you're selecting it.chance as tier, and it.tier as tierChance in val (tier, tierChance) & Pair(it.chance, it.tier).

Tomasz Linkowski
  • 4,386
  • 23
  • 38
0

This seems to be the problem:

filter{ it.chance.passRandom()   }
.map  { Pair(it.chance, it.tier) }

If filter is empty, maybe when randomChance(100F) returns a float greater than 60F as pointed out by Tomasz Linkowski, calling .map will result to IndexArrayOutOfBounds

Please verify.

Brian T.
  • 66
  • 4
0

I appreciate all of your guys contribution by commenting. However I came up with a solution myself which I've tested and is very accurate according to the values in the enum.

    fun tier() : Int {
    for (tier in rewardType.values().reversed()) {
        if(tier.chance.passRandom())
            return tier.tier
    }
    return 0
}