From 173a7732712d847e223cb0bb0b105e75a7ff8ebe Mon Sep 17 00:00:00 2001 From: Duan Tao Date: Fri, 7 Dec 2018 00:39:15 +0800 Subject: [PATCH] Allow auto assign population to specialists. --- .../com/unciv/logic/automation/Automation.kt | 22 ++++++- .../com/unciv/logic/city/PopulationManager.kt | 62 +++++++++++++++---- 2 files changed, 68 insertions(+), 16 deletions(-) diff --git a/core/src/com/unciv/logic/automation/Automation.kt b/core/src/com/unciv/logic/automation/Automation.kt index 5da866a8bc..88a7e59af8 100644 --- a/core/src/com/unciv/logic/automation/Automation.kt +++ b/core/src/com/unciv/logic/automation/Automation.kt @@ -4,18 +4,36 @@ import com.badlogic.gdx.graphics.Color import com.unciv.logic.battle.CityCombatant import com.unciv.logic.city.CityConstructions import com.unciv.logic.city.CityInfo +import com.unciv.logic.city.CityStats import com.unciv.logic.civilization.CivilizationInfo import com.unciv.logic.map.TileInfo import com.unciv.models.gamebasics.unit.BaseUnit import com.unciv.models.gamebasics.unit.UnitType +import com.unciv.models.stats.Stat +import com.unciv.models.stats.Stats import com.unciv.ui.utils.getRandom import kotlin.math.max import kotlin.math.sqrt class Automation { - internal fun rankTile(tile: TileInfo, civInfo: CivilizationInfo): Float { + internal fun rankTile(tile: TileInfo?, civInfo: CivilizationInfo): Float { + if (tile == null) return 0.0f val stats = tile.getTileStats(null, civInfo) + var rank = rankStatsValue(stats, civInfo) + if (tile.improvement == null) rank += 0.5f // improvement potential! + if (tile.hasViewableResource(civInfo)) rank += 1.0f + return rank + } + + internal fun rankSpecialist(stats: Stats?, civInfo: CivilizationInfo): Float { + if (stats == null) return 0.0f + var rank = rankStatsValue(stats, civInfo) + rank += 0.3f //GPP bonus + return rank + } + + fun rankStatsValue(stats: Stats, civInfo: CivilizationInfo): Float { var rank = 0.0f if (stats.food <= 2) rank += stats.food else rank += (2 + (stats.food - 2) / 2) // 1 point for each food up to 2, from there on half a point @@ -26,8 +44,6 @@ class Automation { rank += stats.production rank += stats.science rank += stats.culture - if (tile.improvement == null) rank += 0.5f // improvement potential! - if (tile.hasViewableResource(civInfo)) rank += 1.0f return rank } diff --git a/core/src/com/unciv/logic/city/PopulationManager.kt b/core/src/com/unciv/logic/city/PopulationManager.kt index b0d4ba6b61..e4bf30453c 100644 --- a/core/src/com/unciv/logic/city/PopulationManager.kt +++ b/core/src/com/unciv/logic/city/PopulationManager.kt @@ -3,6 +3,7 @@ package com.unciv.logic.city import com.badlogic.gdx.graphics.Color import com.unciv.logic.automation.Automation import com.unciv.logic.map.TileInfo +import com.unciv.models.stats.Stat import com.unciv.models.stats.Stats import com.unciv.ui.utils.getRandom import kotlin.math.roundToInt @@ -70,12 +71,34 @@ class PopulationManager { internal fun autoAssignPopulation() { if(getFreePopulation()==0) return - val toWork: TileInfo? = cityInfo.getTiles() + + //evaluate tiles + val bestTile: TileInfo? = cityInfo.getTiles() .filter { it.arialDistanceTo(cityInfo.getCenterTile()) <= 3 } .filterNot { cityInfo.workedTiles.contains(it.position) || cityInfo.location==it.position} .maxBy { Automation().rankTile(it,cityInfo.civInfo) } - if (toWork != null) // This is when we've run out of tiles! - cityInfo.workedTiles.add(toWork.position) + val valueBestTile = Automation().rankTile(bestTile, cityInfo.civInfo) + + //evaluate specialists + val maxSpecialistsMap = getMaxSpecialists().toHashMap() + val policies = cityInfo.civInfo.policies.adoptedPolicies + val bestJob: Stat? = specialists.toHashMap() + .filter {maxSpecialistsMap.containsKey(it.key) && it.value < maxSpecialistsMap[it.key]!!} + .maxBy { Automation().rankSpecialist(cityInfo.cityStats.getStatsOfSpecialist(it.key, policies), cityInfo.civInfo) } + ?.key + var valueBestSpecialist = 0f + if (bestJob != null) + valueBestSpecialist = Automation().rankSpecialist(cityInfo.cityStats.getStatsOfSpecialist(bestJob, policies), cityInfo.civInfo) + + //assign population + if (valueBestTile > valueBestSpecialist) { + if (bestTile != null) + cityInfo.workedTiles.add(bestTile.position) + } else { + if (bestJob != null) { + specialists.add(bestJob, 1f) + } + } } fun unassignExtraPopulation() { @@ -87,16 +110,29 @@ class PopulationManager { } while (getFreePopulation()<0) { - if(getNumberOfSpecialists()>0){ - val specialistTypeToUnassign = specialists.toHashMap().filter { it.value>0 }.map { it.key }.getRandom() - specialists.add(specialistTypeToUnassign,-1f) - } - else { - val lowestRankedWorkedTile = cityInfo.workedTiles - .asSequence() - .map { cityInfo.tileMap[it] } - .minBy { Automation().rankTile(it, cityInfo.civInfo) }!! - cityInfo.workedTiles.remove(lowestRankedWorkedTile.position) + //evaluate tiles + val worstWorkedTile: TileInfo? = cityInfo.workedTiles + .asSequence() + .map { cityInfo.tileMap[it] } + .minBy { Automation().rankTile(it, cityInfo.civInfo) }!! + val valueWorstTile = Automation().rankTile(worstWorkedTile, cityInfo.civInfo) + + //evaluate specialists + val policies = cityInfo.civInfo.policies.adoptedPolicies + val worstJob: Stat? = specialists.toHashMap() + .filter { it.value > 0 } + .minBy { Automation().rankSpecialist(cityInfo.cityStats.getStatsOfSpecialist(it.key, policies), cityInfo.civInfo) } + ?.key + var valueWorstSpecialist = 0f + if (worstJob != null) + valueWorstSpecialist = Automation().rankSpecialist(cityInfo.cityStats.getStatsOfSpecialist(worstJob, policies), cityInfo.civInfo) + + //un-assign population + if ((valueWorstTile < valueWorstSpecialist && worstWorkedTile != null) + || (getNumberOfSpecialists() == 0)) { + cityInfo.workedTiles.remove(worstWorkedTile!!.position) + } else { + specialists.add(worstJob!!, -1f) } }