Merge pull request #312 from ninjatao/auto_specialist

Allow auto assign population to specialists.
This commit is contained in:
yairm210
2018-12-10 10:52:57 +02:00
committed by GitHub
4 changed files with 82 additions and 18 deletions

View File

@ -4,21 +4,39 @@ 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
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
@ -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
}

View File

@ -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())

View File

@ -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,36 @@ 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]!!}
.map {it.key}
.maxBy { Automation().rankSpecialist(cityInfo.cityStats.getStatsOfSpecialist(it, policies), cityInfo.civInfo) }
var valueBestSpecialist = 0f
if (bestJob != null) {
val specialistStats = cityInfo.cityStats.getStatsOfSpecialist(bestJob, policies)
valueBestSpecialist = Automation().rankSpecialist(specialistStats, 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 +112,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 }
.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)
|| worstJob == null) {
cityInfo.workedTiles.remove(worstWorkedTile!!.position)
} else {
specialists.add(worstJob!!, -1f)
}
}

View File

@ -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