From 173a7732712d847e223cb0bb0b105e75a7ff8ebe Mon Sep 17 00:00:00 2001 From: Duan Tao Date: Fri, 7 Dec 2018 00:39:15 +0800 Subject: [PATCH 1/4] 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) } } From ca3172b2cfbded2c948896141b313d15cbfae1a4 Mon Sep 17 00:00:00 2001 From: Duan Tao Date: Fri, 7 Dec 2018 15:59:05 +0800 Subject: [PATCH 2/4] Give food a little bit more weight. --- core/src/com/unciv/logic/automation/Automation.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/com/unciv/logic/automation/Automation.kt b/core/src/com/unciv/logic/automation/Automation.kt index 88a7e59af8..5f54ba0272 100644 --- a/core/src/com/unciv/logic/automation/Automation.kt +++ b/core/src/com/unciv/logic/automation/Automation.kt @@ -35,8 +35,8 @@ class Automation { 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 + if (stats.food <= 2) rank += (stats.food * 1.2f) //food get more value to kepp city growing + else rank += (2.4f + (stats.food - 2) / 2) // 1.2 point for each food up to 2, from there on half a point if (civInfo.gold < 0 && civInfo.getStatsForNextTurn().gold <= 0) rank += stats.gold else rank += stats.gold / 2 From bb12fc7cdb55fd6d59b1bc1220bff4ad3c0153ea Mon Sep 17 00:00:00 2001 From: Duan Tao Date: Sun, 9 Dec 2018 19:05:33 +0800 Subject: [PATCH 3/4] Code style improvement. --- .../com/unciv/logic/city/PopulationManager.kt | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/core/src/com/unciv/logic/city/PopulationManager.kt b/core/src/com/unciv/logic/city/PopulationManager.kt index e4bf30453c..5adbafd730 100644 --- a/core/src/com/unciv/logic/city/PopulationManager.kt +++ b/core/src/com/unciv/logic/city/PopulationManager.kt @@ -84,11 +84,13 @@ class PopulationManager { 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 + .map {it.key} + .maxBy { Automation().rankSpecialist(cityInfo.cityStats.getStatsOfSpecialist(it, policies), cityInfo.civInfo) } var valueBestSpecialist = 0f - if (bestJob != null) - valueBestSpecialist = Automation().rankSpecialist(cityInfo.cityStats.getStatsOfSpecialist(bestJob, policies), cityInfo.civInfo) + if (bestJob != null) { + val specialistStats = cityInfo.cityStats.getStatsOfSpecialist(bestJob, policies) + valueBestSpecialist = Automation().rankSpecialist(specialistStats, cityInfo.civInfo) + } //assign population if (valueBestTile > valueBestSpecialist) { @@ -114,22 +116,22 @@ class PopulationManager { val worstWorkedTile: TileInfo? = cityInfo.workedTiles .asSequence() .map { cityInfo.tileMap[it] } - .minBy { Automation().rankTile(it, cityInfo.civInfo) }!! + .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 + .map {it.key} + .minBy { Automation().rankSpecialist(cityInfo.cityStats.getStatsOfSpecialist(it, policies), cityInfo.civInfo) } 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)) { + || worstJob == null) { cityInfo.workedTiles.remove(worstWorkedTile!!.position) } else { specialists.add(worstJob!!, -1f) From d364f3896c12ed2908aa24bc63de795fc03b0d8d Mon Sep 17 00:00:00 2001 From: Duan Tao Date: Mon, 10 Dec 2018 11:34:30 +0800 Subject: [PATCH 4/4] Allow ai city to re-assign specialists. --- .../src/com/unciv/logic/automation/NextTurnAutomation.kt | 1 + core/src/com/unciv/models/stats/Stats.kt | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/core/src/com/unciv/logic/automation/NextTurnAutomation.kt b/core/src/com/unciv/logic/automation/NextTurnAutomation.kt index b5bc71bf53..3c9066713b 100644 --- a/core/src/com/unciv/logic/automation/NextTurnAutomation.kt +++ b/core/src/com/unciv/logic/automation/NextTurnAutomation.kt @@ -117,6 +117,7 @@ class NextTurnAutomation{ private fun reassignWorkedTiles(civInfo: CivilizationInfo) { for (city in civInfo.cities) { city.workedTiles.clear() + city.population.specialists.clear() (0..city.population.population).forEach { city.population.autoAssignPopulation() } Automation().chooseNextConstruction(city.cityConstructions) if (city.health < city.getMaxHealth()) diff --git a/core/src/com/unciv/models/stats/Stats.kt b/core/src/com/unciv/models/stats/Stats.kt index b69a6d2d3d..a18ec5f7db 100644 --- a/core/src/com/unciv/models/stats/Stats.kt +++ b/core/src/com/unciv/models/stats/Stats.kt @@ -15,6 +15,15 @@ open class Stats() { setStats(hashMap) } + fun clear() { + production = 0f + food = 0f + gold = 0f + science = 0f + culture = 0f + happiness = 0f + } + fun add(other: Stats) { // Doing this through the hashmap is nicer code but is SUPER INEFFICIENT! production += other.production