Allocation and runtime optimization with sequences

This commit is contained in:
Yair Morgenstern 2020-01-04 23:02:57 +02:00
parent 8f231cd6e1
commit 47e998269a
6 changed files with 32 additions and 28 deletions

View File

@ -101,7 +101,7 @@ class Automation {
chosenUnit = militaryUnits.filter { it.unitType== UnitType.Ranged }.maxBy { it.cost }!!
else{ // randomize type of unit and take the most expensive of its kind
val chosenUnitType = militaryUnits.map { it.unitType }.distinct().filterNot{it==UnitType.Scout}.random()
val chosenUnitType = militaryUnits.map { it.unitType }.distinct().filterNot{it==UnitType.Scout}.toList().random()
chosenUnit = militaryUnits.filter { it.unitType==chosenUnitType }.maxBy { it.cost }!!
}
return chosenUnit.name

View File

@ -18,8 +18,10 @@ class ConstructionAutomation(val cityConstructions: CityConstructions){
val cityInfo = cityConstructions.cityInfo
val civInfo = cityInfo.civInfo
val buildableNotWonders = cityConstructions.getBuildableBuildings().filterNot { it.isWonder || it.isNationalWonder }
val buildableWonders = cityConstructions.getBuildableBuildings().filter { it.isWonder || it.isNationalWonder }
val buildableNotWonders = cityConstructions.getBuildableBuildings()
.filterNot { it.isWonder || it.isNationalWonder }
val buildableWonders = cityConstructions.getBuildableBuildings()
.filter { it.isWonder || it.isNationalWonder }
val civUnits = civInfo.getCivUnits()
val militaryUnits = civUnits.filter { !it.type.isCivilian()}.size
@ -118,6 +120,7 @@ class ConstructionAutomation(val cityConstructions: CityConstructions){
private fun addWorkerChoice() {
if(civInfo.getIdleUnits().any { it.name==Constants.worker && it.action== Constants.unitActionAutomation})
return // If we have automated workers who have no work to do then it's silly to construct new workers.
val citiesCountedTowardsWorkers = min(5, cities) // above 5 cities, extra cities won't make us want more workers
if (workers < citiesCountedTowardsWorkers * 0.6f && civUnits.none { it.name==Constants.worker && it.isIdle() }) {
var modifier = citiesCountedTowardsWorkers / (workers + 0.1f)
@ -127,7 +130,8 @@ class ConstructionAutomation(val cityConstructions: CityConstructions){
}
private fun addCultureBuildingChoice() {
val cultureBuilding = buildableNotWonders.filter { it.isStatRelated(Stat.Culture) }.minBy { it.cost }
val cultureBuilding = buildableNotWonders
.filter { it.isStatRelated(Stat.Culture) }.minBy { it.cost }
if (cultureBuilding != null) {
var modifier = 0.5f
if(cityInfo.cityStats.currentCityStats.culture==0f) // It won't grow if we don't help it
@ -149,7 +153,7 @@ class ConstructionAutomation(val cityConstructions: CityConstructions){
}
private fun addWondersChoice() {
if (buildableWonders.isNotEmpty()) {
if (buildableWonders.any()) {
fun getWonderPriority(wonder: Building): Float {
if (preferredVictoryType == VictoryType.Cultural
&& wonder.name in listOf("Sistine Chapel", "Eiffel Tower", "Cristo Redentor", "Neuschwanstein", "Sydney Opera House"))
@ -167,21 +171,20 @@ class ConstructionAutomation(val cityConstructions: CityConstructions){
return 1f
}
val wondersByPriority = buildableWonders
.sortedByDescending { getWonderPriority(it) }
val wonder = wondersByPriority.first()
val highestPriorityWonder = buildableWonders
.maxBy { getWonderPriority(it) }!!
val citiesBuildingWonders = civInfo.cities
.count { it.cityConstructions.isBuildingWonder() }
var modifier = 2f * getWonderPriority(wonder) / (citiesBuildingWonders + 1)
var modifier = 2f * getWonderPriority(highestPriorityWonder) / (citiesBuildingWonders + 1)
if (!cityIsOverAverageProduction) modifier /= 5 // higher production cities will deal with this
addChoice(relativeCostEffectiveness, wonder.name, modifier)
addChoice(relativeCostEffectiveness, highestPriorityWonder.name, modifier)
}
}
private fun addUnitTrainingBuildingChoice() {
val unitTrainingBuilding = buildableNotWonders.filter { it.xpForNewUnits > 0 }
.minBy { it.cost }
val unitTrainingBuilding = buildableNotWonders.asSequence()
.filter { it.xpForNewUnits > 0 }.minBy { it.cost }
if (unitTrainingBuilding != null && (preferredVictoryType != VictoryType.Cultural || isAtWar)) {
var modifier = if (cityIsOverAverageProduction) 0.5f else 0.1f // You shouldn't be cranking out units anytime soon
if (isAtWar) modifier *= 2
@ -192,8 +195,8 @@ class ConstructionAutomation(val cityConstructions: CityConstructions){
}
private fun addDefenceBuildingChoice() {
val defensiveBuilding = buildableNotWonders.filter { it.cityStrength > 0 }
.minBy { it.cost }
val defensiveBuilding = buildableNotWonders.asSequence()
.filter { it.cityStrength > 0 }.minBy { it.cost }
if (defensiveBuilding != null && (isAtWar || preferredVictoryType != VictoryType.Cultural)) {
var modifier = 0.2f
if (isAtWar) modifier = 0.5f
@ -208,7 +211,7 @@ class ConstructionAutomation(val cityConstructions: CityConstructions){
}
private fun addHappinessBuildingChoice() {
val happinessBuilding = buildableNotWonders
val happinessBuilding = buildableNotWonders.asSequence()
.filter { it.isStatRelated(Stat.Happiness)
|| it.uniques.contains("Remove extra unhappiness from annexed cities") }
.minBy { it.cost }
@ -222,7 +225,8 @@ class ConstructionAutomation(val cityConstructions: CityConstructions){
}
private fun addScienceBuildingChoice() {
val scienceBuilding = buildableNotWonders.filter { it.isStatRelated(Stat.Science) || it.name=="Library" } // only stat related in unique
val scienceBuilding = buildableNotWonders.asSequence()
.filter { it.isStatRelated(Stat.Science) || it.name=="Library" } // only stat related in unique
.minBy { it.cost }
if (scienceBuilding != null) {
var modifier = 1.1f
@ -233,7 +237,7 @@ class ConstructionAutomation(val cityConstructions: CityConstructions){
}
private fun addGoldBuildingChoice() {
val goldBuilding = buildableNotWonders.filter { it.isStatRelated(Stat.Gold) }
val goldBuilding = buildableNotWonders.asSequence().filter { it.isStatRelated(Stat.Gold) }
.minBy { it.cost }
if (goldBuilding != null) {
val modifier = if (civInfo.statsForNextTurn.gold < 0) 3f else 1.2f
@ -244,7 +248,7 @@ class ConstructionAutomation(val cityConstructions: CityConstructions){
private fun addProductionBuildingChoice() {
val hasWaterResource = cityInfo.tilesInRange
.any { it.isWater && it.resource!=null && it.position in cityInfo.tiles }
val productionBuilding = buildableNotWonders
val productionBuilding = buildableNotWonders.asSequence()
.filter { it.isStatRelated(Stat.Production)
|| (hasWaterResource && (it.uniques.contains("+1 production and gold from all sea resources worked by the city")
|| it.uniques.contains("+1 production from all sea resources worked by the city")) )
@ -256,7 +260,7 @@ class ConstructionAutomation(val cityConstructions: CityConstructions){
}
private fun addFoodBuildingChoice() {
val foodBuilding = buildableNotWonders.filter { it.isStatRelated(Stat.Food)
val foodBuilding = buildableNotWonders.asSequence().filter { it.isStatRelated(Stat.Food)
|| it.getBaseBuilding(civInfo.gameInfo.ruleSet).name == "Aqueduct" || it.getBaseBuilding(civInfo.gameInfo.ruleSet).name == "Medical Lab"} // only stat related in unique
.minBy { it.cost }
if (foodBuilding != null) {

View File

@ -19,7 +19,7 @@ class SpecificUnitAutomation{
}
fun automateWorkBoats(unit: MapUnit) {
val seaResourcesInCities = unit.civInfo.cities.flatMap { city -> city.getWorkableTiles() }
val seaResourcesInCities = unit.civInfo.cities.asSequence().flatMap { city -> city.getWorkableTiles() }
.filter { hasWorkableSeaResource(it, unit.civInfo) && (unit.movement.canMoveTo(it) || unit.currentTile == it) }
val closestReachableResource = seaResourcesInCities.sortedBy { it.arialDistanceTo(unit.currentTile) }
.firstOrNull { unit.movement.canReach(it) }

View File

@ -6,8 +6,8 @@ import com.unciv.logic.automation.ConstructionAutomation
import com.unciv.logic.civilization.AlertType
import com.unciv.logic.civilization.PopupAlert
import com.unciv.models.ruleset.Building
import com.unciv.models.translations.tr
import com.unciv.models.stats.Stats
import com.unciv.models.translations.tr
import com.unciv.ui.utils.withItem
import com.unciv.ui.utils.withoutItem
import java.util.*
@ -33,11 +33,11 @@ class CityConstructions {
return toReturn
}
internal fun getBuildableBuildings(): List<Building> = cityInfo.getRuleset().buildings.values
.filter { it.isBuildable(this) }
internal fun getBuildableBuildings(): Sequence<Building> = cityInfo.getRuleset().buildings.values
.asSequence().filter { it.isBuildable(this) }
fun getConstructableUnits() = cityInfo.getRuleset().units.values
.filter { it.isBuildable(this) }
.asSequence().filter { it.isBuildable(this) }
fun getStats(): Stats {
val stats = Stats()
@ -109,7 +109,7 @@ class CityConstructions {
throw NotBuildingOrUnitException("$constructionName is not a building or a unit!")
}
internal fun getBuiltBuildings(): List<Building> = builtBuildingObjects
internal fun getBuiltBuildings(): Sequence<Building> = builtBuildingObjects.asSequence()
fun containsBuildingOrEquivalent(building: String): Boolean =
isBuilt(building) || getBuiltBuildings().any{it.replaces==building}

View File

@ -116,7 +116,7 @@ class CityInfo {
fun getCenterTile(): TileInfo = centerTileInfo
fun getTiles(): List<TileInfo> = tiles.map { tileMap[it] }
fun getTiles(): Sequence<TileInfo> = tiles.asSequence().map { tileMap[it] }
fun getWorkableTiles() = getTiles().filter { it in tilesInRange }
fun isCapital() = cityConstructions.isBuilt("Palace")
@ -192,7 +192,7 @@ class CityInfo {
return 0
}
fun getBuildingUniques(): List<String> = cityConstructions.getBuiltBuildings().flatMap { it.uniques }
fun getBuildingUniques(): Sequence<String> = cityConstructions.getBuiltBuildings().flatMap { it.uniques.asSequence() }
fun containsBuildingUnique(unique:String) = cityConstructions.getBuiltBuildings().any { it.uniques.contains(unique) }
fun getGreatPersonMap():HashMap<String,Stats>{

View File

@ -492,7 +492,7 @@ class CivilizationInfo {
val city = NextTurnAutomation().getClosestCities(this, otherCiv).city1
val militaryUnit = city.cityConstructions.getConstructableUnits()
.filter { !it.unitType.isCivilian() && it.unitType.isLandUnit() }
.random()
.toList().random()
placeUnitNearTile(city.location, militaryUnit.name)
addNotification("[${otherCiv.civName}] gave us a [${militaryUnit.name}] as gift near [${city.name}]!", null, Color.GREEN)
}