diff --git a/core/src/com/unciv/UnCivGame.kt b/core/src/com/unciv/UnCivGame.kt index 8e3379c103..bc977334e4 100644 --- a/core/src/com/unciv/UnCivGame.kt +++ b/core/src/com/unciv/UnCivGame.kt @@ -17,7 +17,7 @@ class UnCivGame : Game() { * This exists so that when debugging we can see the entire map. * Remember to turn this to false before commit and upload! */ - val viewEntireMapForDebug = false + val viewEntireMapForDebug = true lateinit var worldScreen: WorldScreen @@ -27,11 +27,11 @@ class UnCivGame : Game() { GameBasics.run { } // just to initialize the GameBasics settings = GameSaver().getGeneralSettings() if (GameSaver().getSave("Autosave").exists()) { -// try { + try { loadGame("Autosave") -// } catch (ex: Exception) { // silent fail if we can't read the autosave -// startNewGame() -// } + } catch (ex: Exception) { // silent fail if we can't read the autosave + startNewGame() + } } else startNewGame() // screen=LanguagePickerScreen() disabled because of people's negative reviews =( } diff --git a/core/src/com/unciv/logic/automation/WorkerAutomation.kt b/core/src/com/unciv/logic/automation/WorkerAutomation.kt index 4e97f131b7..8858ac52da 100644 --- a/core/src/com/unciv/logic/automation/WorkerAutomation.kt +++ b/core/src/com/unciv/logic/automation/WorkerAutomation.kt @@ -1,7 +1,7 @@ package com.unciv.logic.automation -import com.unciv.logic.HexMath import com.unciv.logic.civilization.CivilizationInfo +import com.unciv.logic.map.BFS import com.unciv.logic.map.MapUnit import com.unciv.logic.map.RoadStatus import com.unciv.logic.map.TileInfo @@ -40,37 +40,48 @@ class WorkerAutomation(val unit: MapUnit) { if(tile.improvementInProgress!=null) return // we're working! } + + fun tryConnectingCities():Boolean{ // returns whether we actually did anything - val cityThatNeedsConnecting = unit.civInfo.cities.filter { it.population.population>3 && !it.isCapital() + val citiesThatNeedConnecting = unit.civInfo.cities.filter { it.population.population>3 && !it.isCapital() && !it.cityStats.isConnectedToCapital(RoadStatus.Road) } - .minBy { HexMath().getDistance(it.location, unit.getTile().position) } - if(cityThatNeedsConnecting==null) return false// do nothing. + if(citiesThatNeedConnecting.isEmpty()) return false // do nothing. - val closestConnectedCity = unit.civInfo.cities.filter { it.isCapital() || it.cityStats.isConnectedToCapital(RoadStatus.Road) } - .minBy { HexMath().getDistance(cityThatNeedsConnecting.location,it.location) }!! + val citiesThatNeedConnectingBfs = citiesThatNeedConnecting + .map { city -> BFS(city.getCenterTile()){it.isLand() && unit.canPassThrough(it)} } + .toMutableList() - val pathToClosestCity = unit.civInfo.gameInfo.tileMap - .getShortestPathBetweenTwoTiles(cityThatNeedsConnecting.getCenterTile(), - closestConnectedCity.getCenterTile()) - .filter { it.roadStatus==RoadStatus.None} + val connectedCities = unit.civInfo.cities.filter { it.isCapital() || it.cityStats.isConnectedToCapital(RoadStatus.Road) } + .map { it.getCenterTile() } - val unitTile = unit.getTile() - if(unitTile in pathToClosestCity){ - if(unitTile.improvementInProgress==null) - unitTile.startWorkingOnImprovement(GameBasics.TileImprovements["Road"]!!,unit.civInfo) - return true + + while(citiesThatNeedConnectingBfs.any()){ + for(bfs in citiesThatNeedConnectingBfs.toList()){ + bfs.nextStep() + if(bfs.tilesToCheck.isEmpty()){ // can't get to any connected city from here + citiesThatNeedConnectingBfs.remove(bfs) + continue + } + for(city in connectedCities) + if(bfs.tilesToCheck.contains(city)) { // we have a winner! + val pathToCity = bfs.getPathTo(city) + val roadableTiles = pathToCity.filter { it.roadStatus==RoadStatus.None } + val tileToConstructRoadOn :TileInfo + if(unit.currentTile in roadableTiles) tileToConstructRoadOn = unit.currentTile + else{ + val reachableTiles = roadableTiles.filter { unit.canMoveTo(it)&& unit.movementAlgs().canReach(it)} + if(!reachableTiles.any()) continue + tileToConstructRoadOn = roadableTiles.minBy { unit.movementAlgs().getShortestPath(it).size }!! + } + unit.movementAlgs().headTowards(tileToConstructRoadOn) + if(unit.currentMovement>0 && unit.currentTile==tileToConstructRoadOn + && unit.currentTile.improvementInProgress!="Road") + tileToConstructRoadOn.startWorkingOnImprovement(GameBasics.TileImprovements["Road"]!!,unit.civInfo) + return true + } + } } - - val closestTileInPathWithNoRoad = pathToClosestCity - .filter { unit.canMoveTo(it)} - .sortedByDescending { HexMath().getDistance(unit.getTile().position, it.position) } - .firstOrNull { unit.movementAlgs().canReach(it) } - - if(closestTileInPathWithNoRoad==null) return false - unit.movementAlgs().headTowards(closestTileInPathWithNoRoad) - if(unit.currentMovement>0 && unit.getTile()==closestTileInPathWithNoRoad) - closestTileInPathWithNoRoad.startWorkingOnImprovement(GameBasics.TileImprovements["Road"]!!,unit.civInfo) - return true + return false } /** diff --git a/core/src/com/unciv/logic/city/CityStats.kt b/core/src/com/unciv/logic/city/CityStats.kt index c6d0065f52..53b04590af 100644 --- a/core/src/com/unciv/logic/city/CityStats.kt +++ b/core/src/com/unciv/logic/city/CityStats.kt @@ -1,11 +1,10 @@ package com.unciv.logic.city +import com.unciv.logic.map.BFS import com.unciv.logic.map.RoadStatus -import com.unciv.logic.map.TileInfo import com.unciv.models.gamebasics.Building import com.unciv.models.gamebasics.GameBasics 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 @@ -224,24 +223,33 @@ class CityStats { fun isConnectedToCapital(roadType: RoadStatus): Boolean { if (cityInfo.civInfo.cities.count() < 2) return false// first city! - val capitalTile = cityInfo.civInfo.getCapital().getCenterTile() - val tilesReached = HashSet() - var tilesToCheck: List = listOf(cityInfo.getCenterTile()) - while (tilesToCheck.isNotEmpty()) { - val newTiles = tilesToCheck - .flatMap { it.neighbors }.distinct() - .filter { - !tilesReached.contains(it) - && !tilesToCheck.contains(it) - && (roadType !== RoadStatus.Road || it.roadStatus !== RoadStatus.None) - && (roadType !== RoadStatus.Railroad || it.roadStatus === roadType) - } - if (newTiles.contains(capitalTile)) return true - tilesReached.addAll(tilesToCheck) - tilesToCheck = newTiles - } - return false + val capitalTile = cityInfo.civInfo.getCapital().getCenterTile() + val BFS = + if(roadType==RoadStatus.Road) BFS(capitalTile){it.roadStatus!=RoadStatus.None} + else BFS(capitalTile){it.roadStatus == roadType} + + val cityTile = cityInfo.getCenterTile() + BFS.stepUntilDestination(cityTile) + return BFS.tilesReached.containsKey(cityTile) + +// val tilesReached = HashSet() +// var tilesToCheck: List = listOf(cityInfo.getCenterTile()) +// while (tilesToCheck.isNotEmpty()) { +// val newTiles = tilesToCheck +// .flatMap { it.neighbors }.distinct() +// .filter { +// !tilesReached.contains(it) +// && !tilesToCheck.contains(it) +// && (roadType !== RoadStatus.Road || it.roadStatus !== RoadStatus.None) +// && (roadType !== RoadStatus.Railroad || it.roadStatus === roadType) +// } +// +// if (newTiles.contains(capitalTile)) return true +// tilesReached.addAll(tilesToCheck) +// tilesToCheck = newTiles +// } +// return false } //endregion diff --git a/core/src/com/unciv/logic/map/BFS.kt b/core/src/com/unciv/logic/map/BFS.kt new file mode 100644 index 0000000000..926669cdc9 --- /dev/null +++ b/core/src/com/unciv/logic/map/BFS.kt @@ -0,0 +1,42 @@ +package com.unciv.logic.map + +/** + * Defines intermediate steps of a breadth-first search, for use in either get shortest path or get onnected tiles. + */ +class BFS(val startingPoint: TileInfo, val predicate : (TileInfo) -> Boolean){ + var tilesToCheck = ArrayList() + val tilesReached = HashMap() // each tile reached points to its parent tile, where we got to it from + + init{ + tilesToCheck.add(startingPoint) + tilesReached.put(startingPoint,startingPoint) + } + + fun stepUntilDestination(destination: TileInfo){ + while(!tilesReached.containsKey(destination) && tilesToCheck.isNotEmpty()) + nextStep() + } + + fun nextStep(){ + val newTilesToCheck = ArrayList() + for(tileInfo in tilesToCheck){ + val fitNeighbors = tileInfo.neighbors.asSequence() + .filter(predicate) + .filter{!tilesReached.containsKey(it)}.toList() + fitNeighbors.forEach { tilesReached[it] = tileInfo } + newTilesToCheck.addAll(fitNeighbors) + } + tilesToCheck = newTilesToCheck + } + + fun getPathTo(destination: TileInfo): ArrayList { + val path = ArrayList() + path.add(destination) + var currentNode = destination + while(currentNode != startingPoint){ + currentNode = tilesReached[currentNode]!! + path.add(currentNode) + } + return path + } +} \ No newline at end of file diff --git a/core/src/com/unciv/logic/map/TileMap.kt b/core/src/com/unciv/logic/map/TileMap.kt index 172ef5f9cb..1cd04dae6e 100644 --- a/core/src/com/unciv/logic/map/TileMap.kt +++ b/core/src/com/unciv/logic/map/TileMap.kt @@ -130,5 +130,4 @@ class TileMap { return path } - } \ No newline at end of file