import kotlin.math.exp
import kotlin.math.pow
import kotlin.math.roundToInt
+import kotlin.random.Random
val jsonSerializer = Json {
classDiscriminator = "\$ktClass"
style = "font-style: italic"
block()
}
+
+fun Random.nextIrwinHallInteger(max: Int): Int {
+ require(max > 0) { "Random.nextIrwinHallInteger must take positive max parameter, got $max!" }
+ return (1 until max).sumOf { (0..1).random(this) }
+}
+
+fun Random.nextDiminishingInteger(max: Int, increaseChance: Double = 0.5): Int {
+ require(max > 0) { "Random.nextDiminishingInteger must take positive max parameter, got $max!" }
+
+ var curr = 0
+ while (curr + 1 < max && nextDouble() < increaseChance)
+ curr++
+ return curr
+}
+
+fun <T> Iterable<T>.repeatForever(): Sequence<T> = sequence {
+ while (true)
+ yieldAll(this@repeatForever)
+}
}
fun generateNPCFleet(owner: FactionFlavor, rank: AdmiralRank): Map<Id<Ship>, Ship> {
- val battleSize = BattleSize.values().filter { rank >= it.minRank }.associateWith { 100.0 / it.numPoints }.weightedRandom()
+ val battleSize = BattleSize.values().filter { rank.maxShipTier >= it.maxTier }.associateWith { 100.0 / it.numPoints }.weightedRandom()
val possibleShips = ShipType.values().filter { it.faction == owner.shipSource && it.weightClass.tier <= battleSize.maxTier }
val maxPoints = battleSize.numPoints
import net.starshipfights.data.admiralty.AdmiralNames
import net.starshipfights.data.invoke
import net.starshipfights.data.space.generateFleetName
-import net.starshipfights.game.AdmiralRank
-import net.starshipfights.game.FactionFlavor
+import net.starshipfights.game.*
import kotlin.random.Random
fun StarClusterView.testPostProcess(): StarClusterView {
- val flavors = FactionFlavor.values().toList().shuffled()
- val ownerFlavors = sequence {
- while (true)
- for (flavor in flavors)
- yield(flavor)
- }.take(systems.size).toList()
+ val ownerFlavors = FactionFlavor.values()
+ .toList()
+ .shuffled()
+ .repeatForever()
+ .take(systems.size)
+ .toList()
val ownedSystems = (systems.toList().shuffled() zip ownerFlavors).associate { (systemWithId, flavor) ->
val (systemId, system) = systemWithId
- val numOfFleets = (0..1).random() + (0..1).random() + (0..1).random()
+ val numOfFleets = 3 - Random.nextDiminishingInteger(4)
if (numOfFleets == 0)
return@associate systemId to system
val fleets = (1..numOfFleets).associate { _ ->
- val admiralRank = AdmiralRank.values().random()
+ val admiralRank = AdmiralRank.values()[Random.nextIrwinHallInteger(AdmiralRank.values().size)]
val admiralIsFemale = flavor == FactionFlavor.FELINAE_FELICES || Random.nextBoolean()
val admiralFleet = generateNPCFleet(flavor, admiralRank)
fun generateFleet(admiral: Admiral, flavor: FactionFlavor = FactionFlavor.defaultForFaction(admiral.faction)): List<ShipInDrydock> = ShipWeightClass.values()
.flatMap { swc ->
- val shipTypes = ShipType.values().filter { st ->
+ ShipType.values().filter { st ->
st.weightClass == swc && st.faction == admiral.faction
- }.shuffled()
-
- if (shipTypes.isEmpty())
- emptyList()
- else
- (0 until ((admiral.rank.maxShipTier.ordinal - swc.tier.ordinal + 1) * 2).coerceAtLeast(0)).map { i ->
- shipTypes[i % shipTypes.size]
- }
+ }.shuffled().takeIf { it.isNotEmpty() }?.let { shipTypes ->
+ val wcCount = (admiral.rank.maxShipTier.ordinal - swc.tier.ordinal + 1) * 2
+
+ shipTypes.repeatForever().take(wcCount).toList()
+ }.orEmpty()
}
.let { shipTypes ->
val now = Instant.now().minusMillis(100L)