Simulation: Save Stat support (#12663)

* Changes

* Default to not using avgStat

* Make print a float

* Make statTurns a list
rename sumStat
better summation for popsum

* Fix potential nullpointer

* Add .add()

* And another place to use .add()
This commit is contained in:
itanasi 2024-12-16 00:54:32 -08:00 committed by GitHub
parent 7918123a79
commit 2963d47295
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 34 additions and 6 deletions

View File

@ -6,6 +6,7 @@ class MutableInt(var value: Int = 0) {
fun inc() { ++value } fun inc() { ++value }
fun get(): Int { return value } fun get(): Int { return value }
fun set(newValue: Int) { value = newValue } fun set(newValue: Int) { value = newValue }
fun add(addend: Int) { value += addend }
override fun toString(): String { override fun toString(): String {
return value.tr() return value.tr()

View File

@ -20,7 +20,8 @@ class Simulation(
private val newGameInfo: GameInfo, private val newGameInfo: GameInfo,
val simulationsPerThread: Int = 1, val simulationsPerThread: Int = 1,
private val threadsNumber: Int = 1, private val threadsNumber: Int = 1,
private val maxTurns: Int = 500 private val maxTurns: Int = 500,
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 }
@ -28,6 +29,7 @@ class Simulation(
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>()
var sumStat = mutableMapOf<String, MutableMap<Int, MutableInt>>()
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
@ -40,6 +42,8 @@ class Simulation(
init{ init{
for (civ in civilizations) { for (civ in civilizations) {
this.numWins[civ] = MutableInt(0) this.numWins[civ] = MutableInt(0)
for (turn in statTurns)
this.sumStat.getOrPut(civ) { mutableMapOf() }[turn] = 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)
@ -60,12 +64,23 @@ class Simulation(
jobs.add(launch(CoroutineName("simulation-${threadId}")) { jobs.add(launch(CoroutineName("simulation-${threadId}")) {
repeat(simulationsPerThread) { repeat(simulationsPerThread) {
val gameInfo = GameStarter.startNewGame(GameSetupInfo(newGameInfo)) val gameInfo = GameStarter.startNewGame(GameSetupInfo(newGameInfo))
gameInfo.simulateMaxTurns = maxTurns
gameInfo.simulateUntilWin = true gameInfo.simulateUntilWin = true
gameInfo.nextTurn() for (turn in statTurns) {
gameInfo.simulateMaxTurns = turn
gameInfo.nextTurn()
val step = SimulationStep(gameInfo)
if (step.victoryType != null)
break
saveStat(gameInfo)
}
// check if Victory
var step = SimulationStep(gameInfo)
if (step.victoryType == null) {
gameInfo.simulateMaxTurns = maxTurns
gameInfo.nextTurn()
}
val step = SimulationStep(gameInfo) step = SimulationStep(gameInfo) // final game state
println("First: ${gameInfo.civilizations.first().civName}")
if (step.victoryType != null) { if (step.victoryType != null) {
step.winner = step.currentPlayer step.winner = step.currentPlayer
@ -94,6 +109,16 @@ class Simulation(
println("Simulation step ($stepCounter/$maxSimulations)") println("Simulation step ($stepCounter/$maxSimulations)")
} }
@Synchronized
fun saveStat(gameInfo: GameInfo) {
val turn = gameInfo.turns
for (civ in gameInfo.civilizations.filter { it.civName != Constants.spectator }) {
val popsum = civ.cities.sumOf { it.population.population }
//println("$civ $popsum")
sumStat[civ.civName]!![turn]!!.add(popsum)
}
}
@Synchronized @Synchronized
fun print(){ fun print(){
getStats() getStats()
@ -109,7 +134,7 @@ class Simulation(
if (it.winner != null) { if (it.winner != null) {
numWins[it.winner!!]!!.inc() numWins[it.winner!!]!!.inc()
winRateByVictory[it.winner!!]!![it.victoryType]!!.inc() winRateByVictory[it.winner!!]!![it.victoryType]!!.inc()
winTurnByVictory[it.winner!!]!![it.victoryType]!!.set(winTurnByVictory[it.winner!!]!![it.victoryType]!!.get() + it.turns) winTurnByVictory[it.winner!!]!![it.victoryType]!!.add(it.turns)
} }
} }
totalTurns = steps.sumOf { it.turns } totalTurns = steps.sumOf { it.turns }
@ -151,6 +176,8 @@ class Simulation(
outString += "$victory: $winsTurns " outString += "$victory: $winsTurns "
} }
outString += "avg turns\n" outString += "avg turns\n"
for (turn in statTurns)
outString += "avgStat (@$turn): ${sumStat[civ]!![turn]!!.value.toFloat()/numSteps}\n"
} }
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"