Readability helpers for Map of Sets: add, contains (#10116)

This commit is contained in:
SomeTroglodyte
2023-09-18 08:46:55 +02:00
committed by GitHub
parent 29e32303ec
commit ae19a7bd0a
4 changed files with 32 additions and 16 deletions

View File

@ -31,6 +31,7 @@ import com.unciv.models.stats.Stat
import com.unciv.models.stats.Stats
import com.unciv.models.translations.tr
import com.unciv.ui.components.Fonts
import com.unciv.ui.components.extensions.addToMapOfSets
import com.unciv.ui.components.extensions.withItem
import com.unciv.ui.components.extensions.withoutItem
import com.unciv.ui.screens.civilopediascreen.CivilopediaCategories
@ -39,7 +40,6 @@ import kotlin.math.ceil
import kotlin.math.min
import kotlin.math.roundToInt
/**
* City constructions manager.
*
@ -604,7 +604,7 @@ class CityConstructions : IsPartOfGameInfoSerialization {
for (city in citiesThatApply) {
if (city.cityConstructions.containsBuildingOrEquivalent(freeBuilding.name)) continue
city.cityConstructions.addBuilding(freeBuilding)
freeBuildingsProvidedFromThisCity.getOrPut(city.id) { hashSetOf() }.add(freeBuilding.name)
freeBuildingsProvidedFromThisCity.addToMapOfSets(city.id, freeBuilding.name)
}
}
@ -612,7 +612,7 @@ class CityConstructions : IsPartOfGameInfoSerialization {
for (unique in city.civ.getMatchingUniques(UniqueType.GainFreeBuildings, stateForConditionals = StateForConditionals(city.civ, city))) {
val freeBuilding = city.civ.getEquivalentBuilding(unique.params[0])
if (city.matchesFilter(unique.params[1])) {
freeBuildingsProvidedFromThisCity.getOrPut(city.id) { hashSetOf() }.add(freeBuilding.name)
freeBuildingsProvidedFromThisCity.addToMapOfSets(city.id, freeBuilding.name)
if (!isBuilt(freeBuilding.name))
addBuilding(freeBuilding)
}

View File

@ -8,6 +8,8 @@ import com.unciv.models.ruleset.INonPerpetualConstruction
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.ruleset.unit.BaseUnit
import com.unciv.models.stats.Stat
import com.unciv.ui.components.extensions.addToMapOfSets
import com.unciv.ui.components.extensions.contains
import com.unciv.ui.components.extensions.yieldAllNotNull
class CivConstructions : IsPartOfGameInfoSerialization {
@ -88,8 +90,7 @@ class CivConstructions : IsPartOfGameInfoSerialization {
getFreeBuildingNamesSequence(cityId).contains(buildingName)
private fun addFreeBuilding(cityId: String, building: String) {
freeBuildings.getOrPut(cityId) { hashSetOf() }
.add(civInfo.getEquivalentBuilding(building).name)
freeBuildings.addToMapOfSets(cityId, civInfo.getEquivalentBuilding(building).name)
}
private fun addFreeStatsBuildings() {
@ -105,12 +106,12 @@ class CivConstructions : IsPartOfGameInfoSerialization {
private fun addFreeStatBuildings(stat: Stat, amount: Int) {
for (city in civInfo.cities.take(amount)) {
if (freeStatBuildingsProvided[stat.name]?.contains(city.id) == true) continue
if (freeStatBuildingsProvided.contains(stat.name, city.id)) continue
if (!city.cityConstructions.hasBuildableStatBuildings(stat)) continue
val builtBuilding = city.cityConstructions.addCheapestBuildableStatBuilding(stat)
if (builtBuilding != null) {
freeStatBuildingsProvided.getOrPut(stat.name) { hashSetOf() }.add(city.id)
freeStatBuildingsProvided.addToMapOfSets(stat.name, city.id)
addFreeBuilding(city.id, builtBuilding)
}
}
@ -130,12 +131,12 @@ class CivConstructions : IsPartOfGameInfoSerialization {
private fun addFreeBuildings(building: Building, amount: Int) {
for (city in civInfo.cities.take(amount)) {
if (freeSpecificBuildingsProvided[building.name]?.contains(city.id) == true
if (freeSpecificBuildingsProvided.contains(building.name, city.id)
|| city.cityConstructions.containsBuildingOrEquivalent(building.name)) continue
building.postBuildEvent(city.cityConstructions)
freeSpecificBuildingsProvided.getOrPut(building.name) { hashSetOf() }.add(city.id)
freeSpecificBuildingsProvided.addToMapOfSets(building.name, city.id)
addFreeBuilding(city.id, building.name)
}
}

View File

@ -15,6 +15,8 @@ import com.unciv.models.ruleset.tile.TerrainType
import com.unciv.models.ruleset.unique.UniqueMap
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.ruleset.unit.BaseUnit
import com.unciv.ui.components.extensions.addToMapOfSets
import com.unciv.ui.components.extensions.contains
import java.lang.Integer.max
import java.util.concurrent.ConcurrentHashMap
import kotlin.math.abs
@ -92,7 +94,7 @@ class TileMap(initialCapacity: Int = 10) : IsPartOfGameInfoSerialization {
get() = tileList
@Transient
val startingLocationsByNation = HashMap<String,HashSet<Tile>>()
val startingLocationsByNation = HashMap<String, HashSet<Tile>>()
@Transient
/** Continent ID to Continent size */
@ -646,8 +648,7 @@ class TileMap(initialCapacity: Int = 10) : IsPartOfGameInfoSerialization {
return translateStartingLocationsFromMap()
startingLocationsByNation.clear()
for ((position, nationName) in startingLocations) {
val nationSet = startingLocationsByNation[nationName] ?: hashSetOf<Tile>().also { startingLocationsByNation[nationName] = it }
nationSet.add(get(position))
startingLocationsByNation.addToMapOfSets(nationName, get(position))
}
}
@ -670,16 +671,15 @@ class TileMap(initialCapacity: Int = 10) : IsPartOfGameInfoSerialization {
/** Adds a starting position, maintaining the transients
* @return true if the starting position was not already stored as per [Collection]'s add */
fun addStartingLocation(nationName: String, tile: Tile): Boolean {
if (startingLocationsByNation[nationName]?.contains(tile) == true) return false
if (startingLocationsByNation.contains(nationName, tile)) return false
startingLocations.add(StartingLocation(tile.position, nationName))
val nationSet = startingLocationsByNation[nationName] ?: hashSetOf<Tile>().also { startingLocationsByNation[nationName] = it }
return nationSet.add(tile)
return startingLocationsByNation.addToMapOfSets(nationName, tile)
}
/** Removes a starting position, maintaining the transients
* @return true if the starting position was removed as per [Collection]'s remove */
fun removeStartingLocation(nationName: String, tile: Tile): Boolean {
if (startingLocationsByNation[nationName]?.contains(tile) != true) return false
if (startingLocationsByNation.contains(nationName, tile)) return false
startingLocations.remove(StartingLocation(tile.position, nationName))
return startingLocationsByNation[nationName]!!.remove(tile)
// we do not clean up an empty startingLocationsByNation[nationName] set - not worth it

View File

@ -83,3 +83,18 @@ suspend fun <T> SequenceScope<T>.yieldAllNotNull(elements: Iterable<T?>?) {
if (elements == null) return
for (element in elements) yieldIfNotNull(element)
}
/**
* Simplifies adding to a map of sets where the map entry where the new element belongs is not
* guaranteed to be already present in the map (sparse map).
*
* @param key The key identifying the Set to add [element] to
* @param element The new element to be added to the Set for [key]
* @return `false` if the element was already present, `true` if it was new (same as `Set.add()`)
*/
fun <KT, ET> HashMap<KT, HashSet<ET>>.addToMapOfSets(key: KT, element: ET) =
getOrPut(key) { hashSetOf() }.add(element)
/** Simplifies testing whether in a sparse map of sets the [element] exists for [key]. */
fun <KT, ET> HashMap<KT, HashSet<ET>>.contains(key: KT, element: ET) =
get(key)?.contains(element) == true