Fixed settler automation performance problem - now actually viable for phone use

All kinds of other small performance-boosting bits and bobs
This commit is contained in:
Yair Morgenstern 2018-04-26 23:43:36 +03:00
parent f4af9f7d80
commit 8268c0c561
13 changed files with 31 additions and 30 deletions

View File

@ -22,22 +22,22 @@ class Automation {
var rank = 0.0f var rank = 0.0f
if (stats.food <= 2) rank += stats.food if (stats.food <= 2) rank += stats.food
else rank += (2 + (stats.food - 2) / 2f) // 1 point for each food up to 2, from there on half a point else rank += (2 + (stats.food - 2) / 2f) // 1 point for each food up to 2, from there on half a point
rank += (stats.gold / 2) rank += stats.gold / 2
rank += stats.production rank += stats.production
rank += stats.science rank += stats.science
rank += stats.culture rank += stats.culture
if (tile.improvement == null) rank += 0.5f // improvement potential! if (tile.improvement == null) rank += 0.5f // improvement potential!
if (tile.resource != null) rank += 1.0f if (tile.hasViewableResource(civInfo)) rank += 1.0f
return rank return rank
} }
fun rankTileAsCityCenter(tileInfo: TileInfo, civInfo: CivilizationInfo): Float { fun rankTileAsCityCenter(tileInfo: TileInfo, civInfo: CivilizationInfo, nearbyTileRankings: Map<TileInfo, Float>): Float {
val bestTilesFromOuterLayer = tileInfo.tileMap.getTilesAtDistance(tileInfo.position,2) val bestTilesFromOuterLayer = tileInfo.tileMap.getTilesAtDistance(tileInfo.position,2)
.sortedByDescending { rankTile(it,civInfo) }.take(2) .sortedByDescending { nearbyTileRankings[it] }.take(2)
val top5Tiles = tileInfo.neighbors.union(bestTilesFromOuterLayer) val top5Tiles = tileInfo.neighbors.union(bestTilesFromOuterLayer)
.sortedByDescending { rankTile(it,civInfo) } .sortedByDescending { nearbyTileRankings[it] }
.take(5) .take(5)
return top5Tiles.map { rankTile(it,civInfo) }.sum() return top5Tiles.map { nearbyTileRankings[it]!! }.sum()
} }
fun automateCivMoves(civInfo: CivilizationInfo) { fun automateCivMoves(civInfo: CivilizationInfo) {
@ -113,7 +113,7 @@ class Automation {
// if there is an attackable unit in the vicinity, attack! // if there is an attackable unit in the vicinity, attack!
val attackableTiles = unit.civInfo.getViewableTiles() val attackableTiles = unit.civInfo.getViewableTiles()
.filter { it.unit != null && it.unit!!.owner != unit.civInfo.civName && !it.isCityCenter }.toHashSet() .filter { it.unit != null && it.unit!!.owner != unit.civInfo.civName && !it.isCityCenter() }.toHashSet()
val distanceToTiles = unit.getDistanceToTiles() val distanceToTiles = unit.getDistanceToTiles()
val unitTileToAttack = distanceToTiles.keys.firstOrNull { attackableTiles.contains(it) } val unitTileToAttack = distanceToTiles.keys.firstOrNull { attackableTiles.contains(it) }
@ -170,10 +170,12 @@ class Automation {
// find best city location within 5 tiles // find best city location within 5 tiles
val tilesNearCities = unit.civInfo.gameInfo.civilizations.flatMap { it.cities } val tilesNearCities = unit.civInfo.gameInfo.civilizations.flatMap { it.cities }
.flatMap { it.getCenterTile().getTilesInDistance(2) } .flatMap { it.getCenterTile().getTilesInDistance(2) }
// This is to improve performance - instead of ranking each tile in the area up to 19 times, do it once.
val nearbyTileRankings = unit.getTile().getTilesInDistance(7).associateBy ( {it},{rankTile(it,unit.civInfo) })
val bestCityLocation = unit.getTile().getTilesInDistance(5) val bestCityLocation = unit.getTile().getTilesInDistance(5)
.minus(tilesNearCities) .minus(tilesNearCities)
.sortedByDescending { rankTileAsCityCenter(it, unit.civInfo) } .maxBy { rankTileAsCityCenter(it, unit.civInfo, nearbyTileRankings) }!!
.first()
if (unit.getTile() == bestCityLocation) if (unit.getTile() == bestCityLocation)
UnitActions().getUnitActions(unit, UnCivGame.Current.worldScreen!!).first { it.name == "Found city" }.action() UnitActions().getUnitActions(unit, UnCivGame.Current.worldScreen!!).first { it.name == "Found city" }.action()

View File

@ -30,8 +30,8 @@ public class WorkerAutomation(){
.filter { .filter {
(it.unit == null || it == currentTile) (it.unit == null || it == currentTile)
&& it.improvement == null && it.improvement == null
&& (it.getCity()==null || it.getCity()!!.civInfo == civInfo) // don't work tiles belonging to another civ
&& it.canBuildImprovement(chooseImprovement(it), civInfo) && it.canBuildImprovement(chooseImprovement(it), civInfo)
&& {val city=it.getCity(); city==null || it.getCity()?.civInfo == civInfo}() // don't work tiles belonging to another civ
&& UnitMovementAlgorithms(currentTile.tileMap) // the tile is actually reachable - more difficult than it seems! && UnitMovementAlgorithms(currentTile.tileMap) // the tile is actually reachable - more difficult than it seems!
.getShortestPath(currentTile.position, it.position, 2f, 2, civInfo).isNotEmpty() .getShortestPath(currentTile.position, it.position, 2f, 2, civInfo).isNotEmpty()
} }

View File

@ -9,7 +9,7 @@ class CityExpansionManager {
var cultureStored: Int = 0 var cultureStored: Int = 0
fun reset() { fun reset() {
cityInfo.tiles = ArrayList(cityInfo.getCenterTile().getTilesInDistance(1).map { it.position }) cityInfo.tiles = cityInfo.getCenterTile().getTilesInDistance(1).map { it.position }.toHashSet()
} }
// This one has conflicting sources - // This one has conflicting sources -

View File

@ -23,8 +23,8 @@ class CityInfo {
var expansion = CityExpansionManager() var expansion = CityExpansionManager()
var cityStats = CityStats() var cityStats = CityStats()
var tiles = ArrayList<Vector2>() var tiles = HashSet<Vector2>()
var workedTiles = ArrayList<Vector2>() var workedTiles = HashSet<Vector2>()
internal val tileMap: TileMap internal val tileMap: TileMap
@ -42,7 +42,7 @@ class CityInfo {
for (tileInfo in getTilesInRange().filter { it.resource != null }) { for (tileInfo in getTilesInRange().filter { it.resource != null }) {
val resource = tileInfo.tileResource val resource = tileInfo.tileResource
if (resource.improvement == tileInfo.improvement || tileInfo.isCityCenter) if (resource.improvement == tileInfo.improvement || tileInfo.isCityCenter())
cityResources.add(resource, 1) cityResources.add(resource, 1)
} }

View File

@ -74,7 +74,7 @@ class CivilizationInfo {
private fun getTransportationUpkeep(): Int { private fun getTransportationUpkeep(): Int {
var transportationUpkeep = 0 var transportationUpkeep = 0
for (it in gameInfo.tileMap.values.filterNot { it.isCityCenter }) { for (it in gameInfo.tileMap.values.filterNot { it.isCityCenter() }) {
when(it.roadStatus) { when(it.roadStatus) {
RoadStatus.Road -> transportationUpkeep += 1 RoadStatus.Road -> transportationUpkeep += 1
RoadStatus.Railroad -> transportationUpkeep += 2 RoadStatus.Railroad -> transportationUpkeep += 2

View File

@ -62,7 +62,7 @@ class TechManager {
.filter { it.resource == revealedResource.name && civInfo == it.getOwner() }) { .filter { it.resource == revealedResource.name && civInfo == it.getOwner() }) {
val closestCityTile = tileInfo.getTilesInDistance(4) val closestCityTile = tileInfo.getTilesInDistance(4)
.firstOrNull { it.isCityCenter } .firstOrNull { it.isCityCenter() }
if (closestCityTile != null) { if (closestCityTile != null) {
civInfo.addNotification( civInfo.addNotification(
revealedResource.name + " revealed near " + closestCityTile.getCity()!!.name, tileInfo.position) revealedResource.name + " revealed near " + closestCityTile.getCity()!!.name, tileInfo.position)

View File

@ -113,7 +113,7 @@ class MapUnit {
private fun heal(){ private fun heal(){
val tile = getTile() val tile = getTile()
health += when{ health += when{
tile.isCityCenter -> 20 tile.isCityCenter() -> 20
tile.getOwner()?.civName == owner -> 15 // home territory tile.getOwner()?.civName == owner -> 15 // home territory
tile.getOwner() == null -> 10 // no man's land (neutral) tile.getOwner() == null -> 10 // no man's land (neutral)
else -> 5 // enemy territory else -> 5 // enemy territory

View File

@ -32,8 +32,7 @@ class TileInfo {
val tileResource: TileResource val tileResource: TileResource
get() = if (resource == null) throw Exception("No resource exists for this tile!") else GameBasics.TileResources[resource!!]!! get() = if (resource == null) throw Exception("No resource exists for this tile!") else GameBasics.TileResources[resource!!]!!
val isCityCenter: Boolean fun isCityCenter(): Boolean = getCity()?.location == position
get() = getCity() != null && position == getCity()!!.location
val tileImprovement: TileImprovement? val tileImprovement: TileImprovement?
get() = if (improvement == null) null else GameBasics.TileImprovements[improvement!!] get() = if (improvement == null) null else GameBasics.TileImprovements[improvement!!]
@ -101,7 +100,7 @@ class TileInfo {
stats.add(improvement) // again, for the double effect stats.add(improvement) // again, for the double effect
} }
if (isCityCenter) { if (isCityCenter()) {
if (stats.food < 2) stats.food = 2f if (stats.food < 2) stats.food = 2f
if (stats.production < 1) stats.production = 1f if (stats.production < 1) stats.production = 1f
} }
@ -118,7 +117,7 @@ class TileInfo {
} }
fun canBuildImprovement(improvement: TileImprovement, civInfo: CivilizationInfo): Boolean { fun canBuildImprovement(improvement: TileImprovement, civInfo: CivilizationInfo): Boolean {
if (isCityCenter || improvement.name == this.improvement) return false if (isCityCenter() || improvement.name == this.improvement) return false
val topTerrain = if (terrainFeature == null) getBaseTerrain() else getTerrainFeature() val topTerrain = if (terrainFeature == null) getBaseTerrain() else getTerrainFeature()
if (improvement.techRequired != null && !civInfo.tech.isResearched(improvement.techRequired!!)) return false if (improvement.techRequired != null && !civInfo.tech.isResearched(improvement.techRequired!!)) return false
if (improvement.terrainsCanBeBuiltOn.contains(topTerrain!!.name)) return true if (improvement.terrainsCanBeBuiltOn.contains(topTerrain!!.name)) return true
@ -141,14 +140,14 @@ class TileInfo {
override fun toString(): String { override fun toString(): String {
val SB = StringBuilder() val SB = StringBuilder()
if (isCityCenter) { if (isCityCenter()) {
val city = getCity()!! val city = getCity()!!
SB.appendln(city.name+ ",\r\n" + city.cityConstructions.getProductionForTileInfo()) SB.appendln(city.name+ ",\r\n" + city.cityConstructions.getProductionForTileInfo())
} }
SB.appendln(this.baseTerrain) SB.appendln(this.baseTerrain)
if (terrainFeature != null) SB.appendln(terrainFeature!!) if (terrainFeature != null) SB.appendln(terrainFeature!!)
if (hasViewableResource(tileMap.gameInfo.getPlayerCivilization())) SB.appendln(resource!!) if (hasViewableResource(tileMap.gameInfo.getPlayerCivilization())) SB.appendln(resource!!)
if (roadStatus !== RoadStatus.None && !isCityCenter) SB.appendln(roadStatus) if (roadStatus !== RoadStatus.None && !isCityCenter()) SB.appendln(roadStatus)
if (improvement != null) SB.appendln(improvement!!) if (improvement != null) SB.appendln(improvement!!)
if (improvementInProgress != null) SB.appendln("$improvementInProgress in ${this.turnsToImprovement} turns") if (improvementInProgress != null) SB.appendln("$improvementInProgress in ${this.turnsToImprovement} turns")
if (unit != null && UnCivGame.Current.gameInfo.getPlayerCivilization().getViewableTiles().contains(this)){ if (unit != null && UnCivGame.Current.gameInfo.getPlayerCivilization().getViewableTiles().contains(this)){

View File

@ -16,7 +16,7 @@ class UnitMovementAlgorithms(val tileMap: TileMap){
val updatedTiles = ArrayList<TileInfo>() val updatedTiles = ArrayList<TileInfo>()
for (tileToCheck in tilesToCheck) for (tileToCheck in tilesToCheck)
for (maybeUpdatedTile in tileToCheck.neighbors) { for (maybeUpdatedTile in tileToCheck.neighbors) {
if(maybeUpdatedTile.getOwner() != null && maybeUpdatedTile.getOwner() != civInfo && maybeUpdatedTile.isCityCenter) if(maybeUpdatedTile.getOwner() != null && maybeUpdatedTile.getOwner() != civInfo && maybeUpdatedTile.isCityCenter())
continue // Enemy city, can't move through it! continue // Enemy city, can't move through it!
var distanceBetweenTiles = maybeUpdatedTile.lastTerrain.movementCost.toFloat() // no road var distanceBetweenTiles = maybeUpdatedTile.lastTerrain.movementCost.toFloat() // no road

View File

@ -163,7 +163,7 @@ class CityScreen(internal val city: CityInfo) : CameraStageBaseScreen() {
if (tileInfo.getCity()!=city) { if (tileInfo.getCity()!=city) {
group.setColor(0f, 0f, 0f, 0.3f) group.setColor(0f, 0f, 0f, 0.3f)
group.yieldGroup.isVisible = false group.yieldGroup.isVisible = false
} else if (!tileInfo.isCityCenter) { } else if (!tileInfo.isCityCenter()) {
group.addPopulationIcon() group.addPopulationIcon()
group.populationImage!!.addClickListener { group.populationImage!!.addClickListener {
if (!tileInfo.isWorked() && cityInfo.population.getFreePopulation() > 0) if (!tileInfo.isWorked() && cityInfo.population.getFreePopulation() > 0)

View File

@ -55,7 +55,7 @@ class WorldTileGroup(tileInfo: TileInfo) : TileGroup(tileInfo) {
if (tileInfo.isWorked() && city!!.civInfo.isPlayerCivilization() && populationImage == null) if (tileInfo.isWorked() && city!!.civInfo.isPlayerCivilization() && populationImage == null)
addPopulationIcon() addPopulationIcon()
if (city != null && tileInfo.isCityCenter) { if (city != null && tileInfo.isCityCenter()) {
if (cityButton == null) { if (cityButton == null) {
cityButton = Table() cityButton = Table()
cityButton!!.background = ImageGetter.getDrawable("skin/civTableBackground.png") cityButton!!.background = ImageGetter.getDrawable("skin/civTableBackground.png")

View File

@ -31,7 +31,7 @@ class BattleTable(val worldScreen: WorldScreen): Table() {
val selectedTile = worldScreen.tileMapHolder.selectedTile!! val selectedTile = worldScreen.tileMapHolder.selectedTile!!
val defender: ICombatant val defender: ICombatant
if (attacker.getCivilization().exploredTiles.contains(selectedTile.position) if (attacker.getCivilization().exploredTiles.contains(selectedTile.position)
&& selectedTile.isCityCenter && selectedTile.getOwner() != worldScreen.civInfo) && selectedTile.isCityCenter() && selectedTile.getOwner() != worldScreen.civInfo)
defender = CityCombatant(selectedTile.getCity()!!) defender = CityCombatant(selectedTile.getCity()!!)
else if (selectedTile.unit != null else if (selectedTile.unit != null
&& selectedTile.unit!!.owner != worldScreen.civInfo.civName // enemy unit on selected tile, && selectedTile.unit!!.owner != worldScreen.civInfo.civName // enemy unit on selected tile,

View File

@ -66,7 +66,7 @@ class UnitActions {
worldScreen.update() worldScreen.update()
}, },
unit.currentMovement != 0f && unit.currentMovement != 0f &&
!tile.getTilesInDistance(2).any { it.isCityCenter }) !tile.getTilesInDistance(2).any { it.isCityCenter() })
} }
if (unit.name == "Worker") { if (unit.name == "Worker") {
@ -76,7 +76,7 @@ class UnitActions {
actionList += UnitAction(improvementButtonText, actionList += UnitAction(improvementButtonText,
{ worldScreen.game.screen = ImprovementPickerScreen(tile) }, { worldScreen.game.screen = ImprovementPickerScreen(tile) },
unit.currentMovement != 0f && unit.currentMovement != 0f &&
!tile.isCityCenter || GameBasics.TileImprovements.values.any { tile.canBuildImprovement(it, unit.civInfo) }) !tile.isCityCenter() || GameBasics.TileImprovements.values.any { tile.canBuildImprovement(it, unit.civInfo) })
if("automation" == unit.action){ if("automation" == unit.action){
actionList += UnitAction("Stop automation", actionList += UnitAction("Stop automation",
@ -123,7 +123,7 @@ class UnitActions {
tile.unit = null // destroy! tile.unit = null // destroy!
}, },
unit.currentMovement != 0f && unit.currentMovement != 0f &&
tile.isCityCenter && tile.isCityCenter() &&
tile.getCity()!!.cityConstructions.getCurrentConstruction() is Building && tile.getCity()!!.cityConstructions.getCurrentConstruction() is Building &&
(tile.getCity()!!.cityConstructions.getCurrentConstruction() as Building).isWonder) (tile.getCity()!!.cityConstructions.getCurrentConstruction() as Building).isWonder)