Make changes to AI testing
authorTheSaminator <TheSaminator@users.noreply.github.com>
Fri, 3 Jun 2022 15:27:29 +0000 (11:27 -0400)
committerTheSaminator <TheSaminator@users.noreply.github.com>
Fri, 3 Jun 2022 16:36:03 +0000 (12:36 -0400)
src/commonMain/kotlin/starshipfights/game/ai/ai_optimization.kt
src/commonMain/kotlin/starshipfights/game/ai/util.kt
src/jvmTest/kotlin/starshipfights/game/ai/AITesting.kt

index fd998e57b40ac9a01ef640134be7c64880af7aff..cc410521a59122b50439e9bb5313860f96d26c09 100644 (file)
@@ -244,7 +244,12 @@ fun generateOptimizationInitialState(hostFaction: Faction, guestFaction: Faction
        )
 }
 
-suspend fun performTrials(numTrialsPerPairing: Int, instincts: Set<Instincts>, validBattleSizes: Set<BattleSize> = BattleSize.values().toSet(), validFactions: Set<Faction> = Faction.values().toSet()): Map<Instincts, Int> {
+data class InstinctGamePairing(
+       val host: Instincts,
+       val guest: Instincts
+)
+
+suspend fun performTrials(numTrialsPerPairing: Int, instincts: Set<Instincts>, validBattleSizes: Set<BattleSize> = BattleSize.values().toSet(), validFactions: Set<Faction> = Faction.values().toSet()): Map<InstinctGamePairing, Int> {
        return coroutineScope {
                instincts.associateWith { host ->
                        async {
@@ -258,7 +263,7 @@ suspend fun performTrials(numTrialsPerPairing: Int, instincts: Set<Instincts>, v
                                                                val guestFaction = validFactions.random()
                                                                
                                                                val gameState = generateOptimizationInitialState(hostFaction, guestFaction, BattleInfo(battleSize, BattleBackground.BLUE_BROWN))
-                                                               val winner = withTimeoutOrNull(150_000L) {
+                                                               val winner = withTimeoutOrNull(30_000L * numTrialsPerPairing) {
                                                                        performTestSession(gameState, host, guest)
                                                                }
                                                                
@@ -270,10 +275,25 @@ suspend fun performTrials(numTrialsPerPairing: Int, instincts: Set<Instincts>, v
                                                                        else -> 0
                                                                }
                                                        }
-                                               }.sumOf { it.await() }
+                                               }.map { guest to it.await() }
                                        }
-                               }.sumOf { it.await() }
+                               }.flatMap { it.await() }.toMap()
                        }
-               }.mapValues { (_, it) -> it.await() }
+               }.mapValues { (_, it) -> it.await() }.flatten().mapKeys { (k, _) ->
+                       InstinctGamePairing(k.first, k.second)
+               }
        }
 }
+
+data class InstinctVictoryPairing(
+       val winner: Instincts,
+       val loser: Instincts
+)
+
+fun Map<InstinctGamePairing, Int>.victoriesFor(instincts: Instincts) = filterKeys { (host, _) -> host == instincts }.values.sum() - filterKeys { (_, guest) -> guest == instincts }.values.sum()
+
+fun Map<InstinctGamePairing, Int>.toVictoryMap() = keys.associate { (host, _) -> host to victoriesFor(host) }
+
+fun Map<InstinctGamePairing, Int>.toVictoryPairingMap() = keys.associate { (host, guest) ->
+       InstinctVictoryPairing(host, guest) to ((get(InstinctGamePairing(host, guest)) ?: 0) - (get(InstinctGamePairing(guest, host)) ?: 0))
+}
index 9e121bb0c7796fddb9ce5532a41c33a9b90bf0ef..3f3d42c4ef9dd765a7703b750ea2d1f299340479 100644 (file)
@@ -40,6 +40,13 @@ fun <T : Any> Map<T, Double>.weightedRandomOrNull(random: Random = Random): T? {
        else null
 }
 
+fun <T, U, V> Map<T, Map<U, V>>.flatten(): Map<Pair<T, U>, V> =
+       toList().flatMap { (k, v) ->
+               v.map { (l, w) ->
+                       (k to l) to w
+               }
+       }.toMap()
+
 fun <T, U> Map<T, Set<U>>.transpose(): Map<U, Set<T>> =
        flatMap { (k, v) -> v.map { it to k } }
                .groupBy(Pair<U, T>::first, Pair<U, T>::second)
index 67433e499522f84cc5db7da11cf5349336391f8d..bf6287eda4982c07796bfcdb6927837eb4b343f1 100644 (file)
@@ -70,10 +70,14 @@ object AITesting {
                
                val allowedFactions = allowedFactionChoices[allowedFactionIndex]
                
-               val instinctSuccessRate = runBlocking {
+               val instinctPairingSuccessRate = runBlocking {
                        performTrials(numTrials, instinctVectors, allowedBattleSizes, allowedFactions)
                }
                
+               val instinctVictories = instinctPairingSuccessRate.toVictoryPairingMap()
+               
+               val instinctSuccessRate = instinctPairingSuccessRate.toVictoryMap()
+               
                val indexedInstincts = instinctSuccessRate
                        .toList()
                        .sortedBy { (_, v) -> v }
@@ -94,8 +98,8 @@ object AITesting {
                                p { +"Battle Sizes Allowed: ${allowedBattleSizes.singleOrNull()?.displayName ?: "All"}" }
                                p { +"Factions Allowed: ${allowedFactions.singleOrNull()?.polityName ?: "All"}" }
                                h2 { +"Instincts Vectors and Battle Results" }
+                               val cellStyle = "border: 1px solid rgba(0, 0, 0, 0.6)"
                                table {
-                                       val cellStyle = "border: 1px solid rgba(0, 0, 0, 0.6)"
                                        thead {
                                                tr {
                                                        th(scope = ThScope.row) {
@@ -104,18 +108,17 @@ object AITesting {
                                                        }
                                                        th(scope = ThScope.col) {
                                                                style = cellStyle
-                                                               +"Battles Won as Host"
+                                                               +"Battles Won"
                                                        }
-                                                       allInstincts.forEach {
+                                                       for (it in allInstincts)
                                                                th(scope = ThScope.col) {
                                                                        style = cellStyle
                                                                        +it.key
                                                                }
-                                                       }
                                                }
                                        }
                                        tbody {
-                                               indexedInstincts.forEach { (i, pair) ->
+                                               for ((i, pair) in indexedInstincts) {
                                                        val (instincts, successRate) = pair
                                                        tr {
                                                                th(scope = ThScope.row) {
@@ -126,16 +129,44 @@ object AITesting {
                                                                        style = cellStyle
                                                                        +"$successRate"
                                                                }
-                                                               allInstincts.forEach { key ->
+                                                               for (key in allInstincts)
                                                                        td {
                                                                                style = cellStyle
                                                                                +"${instincts[key]}"
                                                                        }
-                                                               }
                                                        }
                                                }
                                        }
                                }
+                               h2 { +"Instincts Pairing Battle Results" }
+                               table {
+                                       tr {
+                                               th {
+                                                       style = cellStyle
+                                                       +"Winner \\ Loser"
+                                               }
+                                               for ((i, _) in indexedInstincts)
+                                                       th(scope = ThScope.col) {
+                                                               style = cellStyle
+                                                               +"Instincts $i"
+                                                       }
+                                       }
+                                       for ((i, v) in indexedInstincts)
+                                               tr {
+                                                       th(scope = ThScope.row) {
+                                                               style = cellStyle
+                                                               +"Instincts $i"
+                                                       }
+                                                       for ((_, w) in indexedInstincts)
+                                                               td {
+                                                                       val pairing = InstinctVictoryPairing(v.first, w.first)
+                                                                       val victories = instinctVictories[pairing] ?: 0
+                                                                       
+                                                                       style = cellStyle
+                                                                       +"$victories"
+                                                               }
+                                               }
+                               }
                        }
                }