AI now more focused on improving small cities to big ones

This commit is contained in:
Yair Morgenstern 2019-08-27 14:39:54 +03:00
parent 6769c30ebe
commit 22a8a85426
5 changed files with 56 additions and 23 deletions

View File

@ -6,9 +6,9 @@ import com.badlogic.gdx.Input
import com.unciv.logic.GameInfo import com.unciv.logic.GameInfo
import com.unciv.logic.GameSaver import com.unciv.logic.GameSaver
import com.unciv.logic.GameStarter import com.unciv.logic.GameStarter
import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.metadata.GameParameters import com.unciv.models.metadata.GameParameters
import com.unciv.models.metadata.GameSettings import com.unciv.models.metadata.GameSettings
import com.unciv.models.gamebasics.GameBasics
import com.unciv.ui.LanguagePickerScreen import com.unciv.ui.LanguagePickerScreen
import com.unciv.ui.utils.ImageGetter import com.unciv.ui.utils.ImageGetter
import com.unciv.ui.worldscreen.WorldScreen import com.unciv.ui.worldscreen.WorldScreen

View File

@ -66,9 +66,9 @@ class GameSaver {
val newAutosaveFilename = saveFilesFolder + File.separator + "Autosave-${gameInfo.currentPlayer}-${gameInfoClone.turns}" val newAutosaveFilename = saveFilesFolder + File.separator + "Autosave-${gameInfo.currentPlayer}-${gameInfoClone.turns}"
getSave("Autosave").copyTo(Gdx.files.local(newAutosaveFilename)) getSave("Autosave").copyTo(Gdx.files.local(newAutosaveFilename))
val autosaves = getSaves().filter { it.startsWith("Autosave") } fun getAutosaves(): List<String> { return getSaves().filter { it.startsWith("Autosave") } }
while(autosaves.size>10){ while(getAutosaves().size>10){
val saveToDelete = autosaves.minBy { getSave(it).lastModified() }!! val saveToDelete = getAutosaves().minBy { getSave(it).lastModified() }!!
deleteSave(saveToDelete) deleteSave(saveToDelete)
} }

View File

@ -14,7 +14,7 @@ import kotlin.math.sqrt
class Automation { class Automation {
internal fun rankTile(tile: TileInfo?, civInfo: CivilizationInfo): Float { internal fun rankTile(tile: TileInfo?, civInfo: CivilizationInfo): Float {
if (tile == null) return 0.0f if (tile == null) return 0f
val stats = tile.getTileStats(null, civInfo) val stats = tile.getTileStats(null, civInfo)
var rank = rankStatsValue(stats, civInfo) var rank = rankStatsValue(stats, civInfo)
if (tile.improvement == null) rank += 0.5f // improvement potential! if (tile.improvement == null) rank += 0.5f // improvement potential!
@ -22,9 +22,37 @@ class Automation {
return rank return rank
} }
internal fun rankSpecialist(stats: Stats?, civInfo: CivilizationInfo): Float { fun rankTileForCityWork(tile:TileInfo, city: CityInfo): Float {
if (stats == null) return 0.0f val stats = tile.getTileStats(city, city.civInfo)
var rank = rankStatsValue(stats, civInfo) return rankStatsForCityWork(stats, city)
}
private fun rankStatsForCityWork(stats: Stats, city: CityInfo): Float {
var rank = 0f
if(city.population.population < 5){
// "small city" - we care more about food and less about global problems like gold science and culture
rank += stats.food * 1.2f
rank += stats.production
rank += stats.science/2
rank += stats.culture/2
rank += stats.gold / 5 // it's barely worth anything at this points
}
else{
if (stats.food <= 2) rank += (stats.food * 1.2f) //food get more value to keep 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 (city.civInfo.gold < 0 && city.civInfo.statsForNextTurn.gold <= 0) rank += stats.gold // we have a global problem
else rank += stats.gold / 3 // 3 gold is worse than 2 production
rank += stats.production
rank += stats.science
rank += stats.culture
}
return rank
}
internal fun rankSpecialist(stats: Stats, cityInfo: CityInfo): Float {
var rank = rankStatsForCityWork(stats, cityInfo)
rank += 0.3f //GPP bonus rank += 0.3f //GPP bonus
return rank return rank
} }

View File

@ -80,8 +80,9 @@ class PopulationManager {
val bestTile: TileInfo? = cityInfo.getTiles() val bestTile: TileInfo? = cityInfo.getTiles()
.filter { it.arialDistanceTo(cityInfo.getCenterTile()) <= 3 } .filter { it.arialDistanceTo(cityInfo.getCenterTile()) <= 3 }
.filterNot { cityInfo.workedTiles.contains(it.position) || cityInfo.location==it.position} .filterNot { cityInfo.workedTiles.contains(it.position) || cityInfo.location==it.position}
.maxBy { Automation().rankTile(it,cityInfo.civInfo) } .maxBy { Automation().rankTileForCityWork(it,cityInfo) }
val valueBestTile = Automation().rankTile(bestTile, cityInfo.civInfo) val valueBestTile = if(bestTile==null) 0f
else Automation().rankTileForCityWork(bestTile, cityInfo)
//evaluate specialists //evaluate specialists
val maxSpecialistsMap = getMaxSpecialists().toHashMap() val maxSpecialistsMap = getMaxSpecialists().toHashMap()
@ -89,11 +90,11 @@ class PopulationManager {
val bestJob: Stat? = specialists.toHashMap() val bestJob: Stat? = specialists.toHashMap()
.filter {maxSpecialistsMap.containsKey(it.key) && it.value < maxSpecialistsMap[it.key]!!} .filter {maxSpecialistsMap.containsKey(it.key) && it.value < maxSpecialistsMap[it.key]!!}
.map {it.key} .map {it.key}
.maxBy { Automation().rankSpecialist(cityInfo.cityStats.getStatsOfSpecialist(it, policies), cityInfo.civInfo) } .maxBy { Automation().rankSpecialist(cityInfo.cityStats.getStatsOfSpecialist(it, policies), cityInfo) }
var valueBestSpecialist = 0f var valueBestSpecialist = 0f
if (bestJob != null) { if (bestJob != null) {
val specialistStats = cityInfo.cityStats.getStatsOfSpecialist(bestJob, policies) val specialistStats = cityInfo.cityStats.getStatsOfSpecialist(bestJob, policies)
valueBestSpecialist = Automation().rankSpecialist(specialistStats, cityInfo.civInfo) valueBestSpecialist = Automation().rankSpecialist(specialistStats, cityInfo)
} }
//assign population //assign population
@ -117,24 +118,28 @@ class PopulationManager {
while (getFreePopulation()<0) { while (getFreePopulation()<0) {
//evaluate tiles //evaluate tiles
val worstWorkedTile: TileInfo? = cityInfo.workedTiles val worstWorkedTile: TileInfo? = if(cityInfo.workedTiles.isEmpty()) null
.asSequence() else {
.map { cityInfo.tileMap[it] } cityInfo.workedTiles.asSequence()
.minBy {Automation().rankTile(it, cityInfo.civInfo)} .map { cityInfo.tileMap[it] }
val valueWorstTile = Automation().rankTile(worstWorkedTile, cityInfo.civInfo) .minBy { Automation().rankTileForCityWork(it, cityInfo) }!!
}
val valueWorstTile = if(worstWorkedTile==null) 0f
else Automation().rankTileForCityWork(worstWorkedTile, cityInfo)
//evaluate specialists //evaluate specialists
val policies = cityInfo.civInfo.policies.adoptedPolicies val policies = cityInfo.civInfo.policies.adoptedPolicies
val worstJob: Stat? = specialists.toHashMap() val worstJob: Stat? = specialists.toHashMap()
.filter { it.value > 0 } .filter { it.value > 0 }
.map {it.key} .map {it.key}
.minBy { Automation().rankSpecialist(cityInfo.cityStats.getStatsOfSpecialist(it, policies), cityInfo.civInfo) } .minBy { Automation().rankSpecialist(cityInfo.cityStats.getStatsOfSpecialist(it, policies), cityInfo) }
var valueWorstSpecialist = 0f var valueWorstSpecialist = 0f
if (worstJob != null) if (worstJob != null)
valueWorstSpecialist = Automation().rankSpecialist(cityInfo.cityStats.getStatsOfSpecialist(worstJob, policies), cityInfo.civInfo) valueWorstSpecialist = Automation().rankSpecialist(cityInfo.cityStats.getStatsOfSpecialist(worstJob, policies), cityInfo)
//un-assign population //un-assign population
if ((valueWorstTile < valueWorstSpecialist && worstWorkedTile != null) if ((worstWorkedTile != null && valueWorstTile < valueWorstSpecialist)
|| worstJob == null) { || worstJob == null) {
cityInfo.workedTiles = cityInfo.workedTiles.withoutItem(worstWorkedTile!!.position) cityInfo.workedTiles = cityInfo.workedTiles.withoutItem(worstWorkedTile!!.position)
} else { } else {

View File

@ -89,7 +89,7 @@ open class TileInfo {
// This is for performance - since we access the neighbors of a tile ALL THE TIME, // This is for performance - since we access the neighbors of a tile ALL THE TIME,
// and the neighbors of a tile never change, it's much more CPU efficient to save the list once and for all! // and the neighbors of a tile never change, it's much more efficient to save the list once and for all!
@Transient private var internalNeighbors : List<TileInfo>?=null @Transient private var internalNeighbors : List<TileInfo>?=null
val neighbors: List<TileInfo> val neighbors: List<TileInfo>
get(){ get(){
@ -99,9 +99,9 @@ open class TileInfo {
} }
fun getHeight(): Int { fun getHeight(): Int {
if (baseTerrain==Constants.mountain) return 4 if (baseTerrain == Constants.mountain) return 4
if (baseTerrain == Constants.hill) return 2 if (baseTerrain == Constants.hill) return 2
if (terrainFeature==Constants.forest || terrainFeature==Constants.jungle) return 1 if (terrainFeature == Constants.forest || terrainFeature == Constants.jungle) return 1
return 0 return 0
} }