mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-24 03:53:12 -04:00
Simulation: New Stats (#13821)
* Changes adding new stats * Refactor in to functions * Flag prints * Fix crash with minor Civs
This commit is contained in:
parent
57eb2b33f3
commit
126c1953c5
@ -25,12 +25,16 @@ class Simulation(
|
|||||||
private val statTurns: List<Int> = listOf()
|
private val statTurns: List<Int> = listOf()
|
||||||
) {
|
) {
|
||||||
private val maxSimulations = threadsNumber * simulationsPerThread
|
private val maxSimulations = threadsNumber * simulationsPerThread
|
||||||
val civilizations = newGameInfo.civilizations.filter { it.civName != Constants.spectator }.map { it.civName }
|
//val civilizations = newGameInfo.civilizations.filter { it.civName != Constants.spectator }.map { it.civName }
|
||||||
private val majorCivs = newGameInfo.civilizations.filter { it.civName != Constants.spectator }.filter { it.isMajorCiv() }.size
|
private val majorCivs = newGameInfo.civilizations.filter { it.civName != Constants.spectator }.filter { it.isMajorCiv() }.map { it.civName }
|
||||||
|
private val numMajorCivs = newGameInfo.civilizations.filter { it.civName != Constants.spectator }.filter { it.isMajorCiv() }.size
|
||||||
private var startTime: Long = 0
|
private var startTime: Long = 0
|
||||||
var steps = ArrayList<SimulationStep>()
|
var steps = ArrayList<SimulationStep>()
|
||||||
var numWins = mutableMapOf<String, MutableInt>()
|
var numWins = mutableMapOf<String, MutableInt>()
|
||||||
private var summaryStats = HashMap<String, HashMap<Int, HashMap<Stat, MutableInt>>>() // [civ][turn][stat]=value
|
private var summaryStatsPop = HashMap<String, HashMap<Int, HashMap<Stat, MutableInt>>>() // [civ][turn][stat]=value
|
||||||
|
private var summaryStatsProd = HashMap<String, HashMap<Int, HashMap<Stat, MutableInt>>>() // [civ][turn][stat]=value
|
||||||
|
private var summaryStatsCities = HashMap<String, HashMap<Int, HashMap<Stat, MutableInt>>>() // [civ][turn][stat]=value
|
||||||
|
private var summaryStatsAvgPop = HashMap<String, HashMap<Int, HashMap<Stat, MutableInt>>>() // [civ][turn][stat]=value
|
||||||
private var winRateByVictory = HashMap<String, MutableMap<String, MutableInt>>()
|
private var winRateByVictory = HashMap<String, MutableMap<String, MutableInt>>()
|
||||||
private var winTurnByVictory = HashMap<String, MutableMap<String, MutableInt>>()
|
private var winTurnByVictory = HashMap<String, MutableMap<String, MutableInt>>()
|
||||||
private var avgSpeed = 0f
|
private var avgSpeed = 0f
|
||||||
@ -42,18 +46,15 @@ class Simulation(
|
|||||||
SUM,
|
SUM,
|
||||||
NUM
|
NUM
|
||||||
}
|
}
|
||||||
|
// print flags
|
||||||
|
private val printPop = true
|
||||||
|
private val printProd = false
|
||||||
|
private val printCityCnt = false
|
||||||
|
private val printAvgCityPop = false
|
||||||
|
|
||||||
init{
|
init{
|
||||||
for (civ in civilizations) {
|
for (civ in majorCivs) {
|
||||||
this.numWins[civ] = MutableInt(0)
|
this.numWins[civ] = MutableInt(0)
|
||||||
for (turn in statTurns) {
|
|
||||||
this.summaryStats.getOrPut(civ) { hashMapOf() }.getOrPut(turn){hashMapOf()}[Stat.SUM] = MutableInt(0)
|
|
||||||
this.summaryStats.getOrPut(civ) { hashMapOf() }.getOrPut(turn){hashMapOf()}[Stat.NUM] = MutableInt(0)
|
|
||||||
}
|
|
||||||
val turn = -1 // end of game
|
|
||||||
this.summaryStats.getOrPut(civ) { hashMapOf() }.getOrPut(turn){hashMapOf()}[Stat.SUM] = MutableInt(0)
|
|
||||||
this.summaryStats.getOrPut(civ) { hashMapOf() }.getOrPut(turn){hashMapOf()}[Stat.NUM] = MutableInt(0)
|
|
||||||
winRateByVictory[civ] = mutableMapOf()
|
winRateByVictory[civ] = mutableMapOf()
|
||||||
for (victory in UncivGame.Current.gameInfo!!.ruleset.victories.keys)
|
for (victory in UncivGame.Current.gameInfo!!.ruleset.victories.keys)
|
||||||
winRateByVictory[civ]!![victory] = MutableInt(0)
|
winRateByVictory[civ]!![victory] = MutableInt(0)
|
||||||
@ -61,6 +62,24 @@ class Simulation(
|
|||||||
for (victory in UncivGame.Current.gameInfo!!.ruleset.victories.keys)
|
for (victory in UncivGame.Current.gameInfo!!.ruleset.victories.keys)
|
||||||
winTurnByVictory[civ]!![victory] = MutableInt(0)
|
winTurnByVictory[civ]!![victory] = MutableInt(0)
|
||||||
}
|
}
|
||||||
|
initHash(summaryStatsPop)
|
||||||
|
initHash(summaryStatsProd)
|
||||||
|
initHash(summaryStatsCities)
|
||||||
|
initHash(summaryStatsAvgPop)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need to initialize the values
|
||||||
|
// Later will iterate with flatMap
|
||||||
|
private fun initHash(summary: HashMap<String, HashMap<Int, HashMap<Stat, MutableInt>>>) {
|
||||||
|
for (civ in majorCivs) {
|
||||||
|
for (turn in statTurns) {
|
||||||
|
summary.getOrPut(civ) { hashMapOf() }.getOrPut(turn){hashMapOf()}[Stat.SUM] = MutableInt(0)
|
||||||
|
summary.getOrPut(civ) { hashMapOf() }.getOrPut(turn){hashMapOf()}[Stat.NUM] = MutableInt(0)
|
||||||
|
}
|
||||||
|
val turn = -1 // end of game
|
||||||
|
summary.getOrPut(civ) { hashMapOf() }.getOrPut(turn){hashMapOf()}[Stat.SUM] = MutableInt(0)
|
||||||
|
summary.getOrPut(civ) { hashMapOf() }.getOrPut(turn){hashMapOf()}[Stat.NUM] = MutableInt(0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun start() = runBlocking {
|
fun start() = runBlocking {
|
||||||
@ -136,13 +155,32 @@ class Simulation(
|
|||||||
getStats()
|
getStats()
|
||||||
println(text())
|
println(text())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun summaryStatSet(summaryHash: HashMap<String, HashMap<Int, HashMap<Stat, MutableInt>>>,
|
||||||
|
civ: String, turn: Int, stat: MutableMap<String, MutableMap<Int, MutableInt>>) {
|
||||||
|
if (stat[civ]!![turn]!!.value != -1) {
|
||||||
|
summaryHash[civ]!![turn]!![Stat.SUM]!!.add(stat[civ]!![turn]!!.value)
|
||||||
|
summaryHash[civ]!![turn]!![Stat.NUM]!!.inc()
|
||||||
|
//println("civ ${civ} @ ${turn} value ${stat[civ]!![turn]!!.value}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun getStats() {
|
private fun getStats() {
|
||||||
// win Rate
|
// win Rate
|
||||||
numWins.values.forEach { it.value = 0 }
|
numWins.values.forEach { it.value = 0 }
|
||||||
winRateByVictory.flatMap { it.value.values }.forEach { it.value = 0 }
|
winRateByVictory.flatMap { it.value.values }.forEach { it.value = 0 }
|
||||||
winTurnByVictory.flatMap { it.value.values }.forEach { it.value = 0 }
|
winTurnByVictory.flatMap { it.value.values }.forEach { it.value = 0 }
|
||||||
summaryStats.flatMap { it.value.values }.forEach {
|
// reset to 0
|
||||||
|
summaryStatsPop.flatMap { it.value.values }.forEach {
|
||||||
|
it.values.forEach { it.value = 0 }
|
||||||
|
}
|
||||||
|
summaryStatsProd.flatMap { it.value.values }.forEach {
|
||||||
|
it.values.forEach { it.value = 0 }
|
||||||
|
}
|
||||||
|
summaryStatsCities.flatMap { it.value.values }.forEach {
|
||||||
|
it.values.forEach { it.value = 0 }
|
||||||
|
}
|
||||||
|
summaryStatsAvgPop.flatMap { it.value.values }.forEach {
|
||||||
it.values.forEach { it.value = 0 }
|
it.values.forEach { it.value = 0 }
|
||||||
}
|
}
|
||||||
steps.forEach {
|
steps.forEach {
|
||||||
@ -151,17 +189,22 @@ class Simulation(
|
|||||||
winRateByVictory[it.winner!!]!![it.victoryType]!!.inc()
|
winRateByVictory[it.winner!!]!![it.victoryType]!!.inc()
|
||||||
winTurnByVictory[it.winner!!]!![it.victoryType]!!.add(it.turns)
|
winTurnByVictory[it.winner!!]!![it.victoryType]!!.add(it.turns)
|
||||||
}
|
}
|
||||||
for (civ in civilizations) {
|
for (civ in majorCivs) {
|
||||||
for (turn in statTurns) {
|
for (turn in statTurns) {
|
||||||
if (it.turnStats[civ]!![turn]!!.value != -1) {
|
summaryStatSet(summaryStatsPop, civ, turn, it.turnStatsPop)
|
||||||
summaryStats[civ]!![turn]!![Stat.SUM]!!.add(it.turnStats[civ]!![turn]!!.value)
|
summaryStatSet(summaryStatsProd, civ, turn, it.turnStatsProd)
|
||||||
summaryStats[civ]!![turn]!![Stat.NUM]!!.inc()
|
summaryStatSet(summaryStatsCities, civ, turn, it.turnStatsCities)
|
||||||
//println("civ ${civ} @ ${turn} value ${it.turnStats[civ]!![turn]!!.value} avg ${summaryStats[civ]!![turn]!!["avg"]!!.value} numAvg ${summaryStats[civ]!![turn]!!["numAvg"]!!.value}")
|
if (it.turnStatsPop[civ]!![turn]!!.value != -1 && it.turnStatsCities[civ]!![turn]!!.value != -1) {
|
||||||
|
summaryStatsAvgPop[civ]!![turn]!![Stat.SUM]!!.add(it.turnStatsPop[civ]!![turn]!!.value/it.turnStatsCities[civ]!![turn]!!.value)
|
||||||
|
summaryStatsAvgPop[civ]!![turn]!![Stat.NUM]!!.inc()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val turn = -1 // end of game
|
val turn = -1 // end of game
|
||||||
summaryStats[civ]!![turn]!![Stat.SUM]!!.add(it.turnStats[civ]!![turn]!!.value)
|
summaryStatSet(summaryStatsPop, civ, turn, it.turnStatsPop)
|
||||||
summaryStats[civ]!![turn]!![Stat.NUM]!!.inc()
|
summaryStatSet(summaryStatsProd, civ, turn, it.turnStatsProd)
|
||||||
|
summaryStatSet(summaryStatsCities, civ, turn, it.turnStatsCities)
|
||||||
|
summaryStatsAvgPop[civ]!![turn]!![Stat.SUM]!!.add(it.turnStatsPop[civ]!![turn]!!.value/it.turnStatsCities[civ]!![turn]!!.value)
|
||||||
|
summaryStatsAvgPop[civ]!![turn]!![Stat.NUM]!!.inc()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
totalTurns = steps.sumOf { it.turns }
|
totalTurns = steps.sumOf { it.turns }
|
||||||
@ -169,13 +212,20 @@ class Simulation(
|
|||||||
avgSpeed = totalTurns.toFloat() / totalDuration.inWholeSeconds
|
avgSpeed = totalTurns.toFloat() / totalDuration.inWholeSeconds
|
||||||
avgDuration = totalDuration / steps.size
|
avgDuration = totalDuration / steps.size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper text formatter
|
||||||
|
private fun summaryStatsText(summaryStats: HashMap<Stat, MutableInt>,
|
||||||
|
turn: Int, statStr: String): String {
|
||||||
|
val turnStr = if(turn == -1) "END" else turn
|
||||||
|
return "@$turnStr: $statStr avg=${summaryStats[Stat.SUM]!!.value.toFloat() / summaryStats[Stat.NUM]!!.value.toFloat()} cnt=${summaryStats[Stat.NUM]!!.value}\n"
|
||||||
|
}
|
||||||
|
|
||||||
fun text(): String {
|
fun text(): String {
|
||||||
var outString = ""
|
var outString = ""
|
||||||
for (civ in civilizations) {
|
for (civ in majorCivs) {
|
||||||
|
|
||||||
val numSteps = max(steps.size, 1)
|
val numSteps = max(steps.size, 1)
|
||||||
val expWinRate = 1f / majorCivs
|
val expWinRate = 1f / numMajorCivs
|
||||||
if (numWins[civ]!!.value == 0) continue
|
if (numWins[civ]!!.value == 0) continue
|
||||||
val winRate = String.format("%.1f", numWins[civ]!!.value * 100f / numSteps)
|
val winRate = String.format("%.1f", numWins[civ]!!.value * 100f / numSteps)
|
||||||
|
|
||||||
@ -204,12 +254,24 @@ class Simulation(
|
|||||||
}
|
}
|
||||||
outString += "avg turns\n"
|
outString += "avg turns\n"
|
||||||
for (turn in statTurns) {
|
for (turn in statTurns) {
|
||||||
val turnStats = summaryStats[civ]!![turn]!!
|
if(printPop)
|
||||||
outString += "@$turn: popsum avg=${turnStats[Stat.SUM]!!.value.toFloat() / turnStats[Stat.NUM]!!.value.toFloat()} cnt=${turnStats[Stat.NUM]!!.value}\n"
|
outString += summaryStatsText(summaryStatsPop[civ]!![turn]!!, turn, "popSum")
|
||||||
|
if(printProd)
|
||||||
|
outString += summaryStatsText(summaryStatsProd[civ]!![turn]!!, turn, "prodSum")
|
||||||
|
if(printCityCnt)
|
||||||
|
outString += summaryStatsText(summaryStatsCities[civ]!![turn]!!, turn, "cityCount")
|
||||||
|
if(printAvgCityPop)
|
||||||
|
outString += summaryStatsText(summaryStatsAvgPop[civ]!![turn]!!, turn, "avgCityPop")
|
||||||
}
|
}
|
||||||
val turn = -1 // end of match
|
val turn = -1 // end of match
|
||||||
val turnStats = summaryStats[civ]!![turn]!!
|
if(printPop)
|
||||||
outString += "@END: popsum avg=${turnStats[Stat.SUM]!!.value.toFloat()/turnStats[Stat.NUM]!!.value.toFloat()} cnt=${turnStats[Stat.NUM]!!.value}\n"
|
outString += summaryStatsText(summaryStatsPop[civ]!![turn]!!, turn, "popSum")
|
||||||
|
if(printProd)
|
||||||
|
outString += summaryStatsText(summaryStatsProd[civ]!![turn]!!, turn, "prodSum")
|
||||||
|
if(printCityCnt)
|
||||||
|
outString += summaryStatsText(summaryStatsCities[civ]!![turn]!!, turn, "cityCount")
|
||||||
|
if(printAvgCityPop)
|
||||||
|
outString += summaryStatsText(summaryStatsAvgPop[civ]!![turn]!!, turn, "avgCityPop")
|
||||||
}
|
}
|
||||||
outString += "\nAverage speed: %.1f turns/s \n".format(avgSpeed)
|
outString += "\nAverage speed: %.1f turns/s \n".format(avgSpeed)
|
||||||
outString += "Average game duration: $avgDuration\n"
|
outString += "Average game duration: $avgDuration\n"
|
||||||
|
@ -2,6 +2,7 @@ package com.unciv.logic.simulation
|
|||||||
|
|
||||||
import com.unciv.Constants
|
import com.unciv.Constants
|
||||||
import com.unciv.logic.GameInfo
|
import com.unciv.logic.GameInfo
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
class SimulationStep (gameInfo: GameInfo, statTurns: List<Int> = listOf()) {
|
class SimulationStep (gameInfo: GameInfo, statTurns: List<Int> = listOf()) {
|
||||||
val civilizations = gameInfo.civilizations.filter { it.civName != Constants.spectator }.map { it.civName }
|
val civilizations = gameInfo.civilizations.filter { it.civName != Constants.spectator }.map { it.civName }
|
||||||
@ -9,13 +10,20 @@ class SimulationStep (gameInfo: GameInfo, statTurns: List<Int> = listOf()) {
|
|||||||
var victoryType = gameInfo.getCurrentPlayerCivilization().victoryManager.getVictoryTypeAchieved()
|
var victoryType = gameInfo.getCurrentPlayerCivilization().victoryManager.getVictoryTypeAchieved()
|
||||||
var winner: String? = null
|
var winner: String? = null
|
||||||
var currentPlayer = gameInfo.currentPlayer
|
var currentPlayer = gameInfo.currentPlayer
|
||||||
val turnStats = mutableMapOf<String, MutableMap<Int, MutableInt>>() // [civ][turn][stat]
|
val turnStatsPop = mutableMapOf<String, MutableMap<Int, MutableInt>>() // [civ][turn][stat]
|
||||||
|
val turnStatsProd = mutableMapOf<String, MutableMap<Int, MutableInt>>() // [civ][turn][stat]
|
||||||
|
val turnStatsCities = mutableMapOf<String, MutableMap<Int, MutableInt>>() // [civ][turn][stat]
|
||||||
|
|
||||||
init {
|
init {
|
||||||
for (civ in civilizations) {
|
for (civ in civilizations) {
|
||||||
for (turn in statTurns)
|
for (turn in statTurns) {
|
||||||
this.turnStats.getOrPut(civ) { mutableMapOf() }[turn] = MutableInt(-1)
|
this.turnStatsPop.getOrPut(civ) { mutableMapOf() }[turn] = MutableInt(-1)
|
||||||
this.turnStats.getOrPut(civ) { mutableMapOf() }[-1] = MutableInt(-1) // end of game
|
this.turnStatsProd.getOrPut(civ) { mutableMapOf() }[turn] = MutableInt(-1)
|
||||||
|
this.turnStatsCities.getOrPut(civ) { mutableMapOf() }[turn] = MutableInt(-1)
|
||||||
|
}
|
||||||
|
this.turnStatsPop.getOrPut(civ) { mutableMapOf() }[-1] = MutableInt(-1) // end of game
|
||||||
|
this.turnStatsProd.getOrPut(civ) { mutableMapOf() }[-1] = MutableInt(-1) // end of game
|
||||||
|
this.turnStatsCities.getOrPut(civ) { mutableMapOf() }[-1] = MutableInt(-1) // end of game
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -26,7 +34,13 @@ class SimulationStep (gameInfo: GameInfo, statTurns: List<Int> = listOf()) {
|
|||||||
for (civ in gameInfo.civilizations.filter { it.civName != Constants.spectator }) {
|
for (civ in gameInfo.civilizations.filter { it.civName != Constants.spectator }) {
|
||||||
val popsum = civ.cities.sumOf { it.population.population }
|
val popsum = civ.cities.sumOf { it.population.population }
|
||||||
//println("$civ $popsum")
|
//println("$civ $popsum")
|
||||||
turnStats[civ.civName]!![turn]!!.set(popsum)
|
turnStatsPop[civ.civName]!![turn]!!.set(popsum)
|
||||||
|
val prodsum = civ.cities.sumOf { it.cityStats.currentCityStats.production.roundToInt() }
|
||||||
|
//println("$civ $prodsum")
|
||||||
|
turnStatsProd[civ.civName]!![turn]!!.set(prodsum)
|
||||||
|
val cityCnt = civ.cities.count()
|
||||||
|
//println("$civ $cityCnt")
|
||||||
|
turnStatsCities[civ.civName]!![turn]!!.set(cityCnt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user