From d11cb4779b31b23bef28c20798e919d137e453de Mon Sep 17 00:00:00 2001 From: Duan Tao Date: Mon, 21 Jan 2019 19:36:27 +0800 Subject: [PATCH 1/4] AIs trade techs. Also modified AI tech choose strategy. --- core/src/com/unciv/logic/GameInfo.kt | 10 ++--- .../logic/automation/NextTurnAutomation.kt | 41 +++++++++++++++++-- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/core/src/com/unciv/logic/GameInfo.kt b/core/src/com/unciv/logic/GameInfo.kt index 0a55b340d3..e8c8e18796 100644 --- a/core/src/com/unciv/logic/GameInfo.kt +++ b/core/src/com/unciv/logic/GameInfo.kt @@ -58,11 +58,11 @@ class GameInfo { while(thisPlayer.playerType==PlayerType.AI){ NextTurnAutomation().automateCivMoves(thisPlayer) - if (thisPlayer.tech.techsToResearch.isEmpty()) { // should belong in automation? yes/no? - val researchableTechs = GameBasics.Technologies.values - .filter { !thisPlayer.tech.isResearched(it.name) && thisPlayer.tech.canBeResearched(it.name) } - thisPlayer.tech.techsToResearch.add(researchableTechs.minBy { it.cost }!!.name) - } + // if (thisPlayer.tech.techsToResearch.isEmpty()) { // should belong in automation? yes/no? + // val researchableTechs = GameBasics.Technologies.values + // .filter { !thisPlayer.tech.isResearched(it.name) && thisPlayer.tech.canBeResearched(it.name) } + // thisPlayer.tech.techsToResearch.add(researchableTechs.minBy { it.cost }!!.name) + // } switchTurn() } diff --git a/core/src/com/unciv/logic/automation/NextTurnAutomation.kt b/core/src/com/unciv/logic/automation/NextTurnAutomation.kt index a8beadae50..26ce5b11ef 100644 --- a/core/src/com/unciv/logic/automation/NextTurnAutomation.kt +++ b/core/src/com/unciv/logic/automation/NextTurnAutomation.kt @@ -2,16 +2,19 @@ package com.unciv.logic.automation import com.unciv.logic.city.CityInfo import com.unciv.logic.civilization.CivilizationInfo +import com.unciv.logic.civilization.PlayerType import com.unciv.logic.map.MapUnit import com.unciv.logic.trade.TradeLogic import com.unciv.logic.trade.TradeType import com.unciv.models.gamebasics.GameBasics +import com.unciv.models.gamebasics.tech.Technology import com.unciv.ui.utils.getRandom import kotlin.math.min class NextTurnAutomation{ fun automateCivMoves(civInfo: CivilizationInfo) { + exchangeTechs(civInfo) chooseTechToResearch(civInfo) adoptPolicy(civInfo) exchangeLuxuries(civInfo) @@ -22,11 +25,43 @@ class NextTurnAutomation{ trainSettler(civInfo) } + private fun exchangeTechs(civInfo: CivilizationInfo) { + for (otherCiv in civInfo.diplomacy.values.map { it.otherCiv() }.filter { it.playerType == PlayerType.AI }.sortedBy { it.tech.techsResearched.size }) { + val tradeLogic = TradeLogic(civInfo, otherCiv) + val ourTradableTechs = tradeLogic.ourAvailableOffers + .filter { it.type == TradeType.Technology } + val theirTradableTechs = tradeLogic.theirAvailableOffers + .filter { it.type == TradeType.Technology } + + for (ourOffer in ourTradableTechs) { + val theirOfferList = theirTradableTechs.filter{ + tradeLogic.evaluateOffer(ourOffer, false) >= tradeLogic.evaluateOffer(it, false) + && !tradeLogic.currentTrade.theirOffers.contains(it) } + if (theirOfferList.isNotEmpty()) { + tradeLogic.currentTrade.ourOffers.add(ourOffer) + tradeLogic.currentTrade.theirOffers.add(theirOfferList.getRandom()) + } + } + + if (tradeLogic.currentTrade.theirOffers.isNotEmpty()) { + tradeLogic.acceptTrade() + } + } + } + private fun chooseTechToResearch(civInfo: CivilizationInfo) { if (civInfo.tech.techsToResearch.isEmpty()) { - val researchableTechs = GameBasics.Technologies.values.filter { civInfo.tech.canBeResearched(it.name) } - val techToResearch = researchableTechs.groupBy { it.cost }.minBy { it.key }!!.value.getRandom() - civInfo.tech.techsResearched.add(techToResearch.name) + val researchableTechs = GameBasics.Technologies.values.filter { !civInfo.tech.isResearched(it.name) && civInfo.tech.canBeResearched(it.name) } + val techsGroups = researchableTechs.groupBy { it.cost } + val costs = techsGroups.keys.sorted() + + val tech: Technology + if (techsGroups[costs[0]]!!.size == 1 || costs.size == 1) { + tech = techsGroups[costs[0]]!!.getRandom() + } else { + tech = (techsGroups[costs[0]]!! + techsGroups[costs[1]]!!).getRandom() + } + civInfo.tech.techsToResearch.add(tech.name) } } From 53c0bbb0a3c88df9fcaeda1ec00db59755d6ded9 Mon Sep 17 00:00:00 2001 From: Duan Tao Date: Tue, 22 Jan 2019 13:08:17 +0800 Subject: [PATCH 2/4] AI exchange techs strategy change. --- .../logic/automation/NextTurnAutomation.kt | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/core/src/com/unciv/logic/automation/NextTurnAutomation.kt b/core/src/com/unciv/logic/automation/NextTurnAutomation.kt index 26ce5b11ef..aebc99c513 100644 --- a/core/src/com/unciv/logic/automation/NextTurnAutomation.kt +++ b/core/src/com/unciv/logic/automation/NextTurnAutomation.kt @@ -5,9 +5,11 @@ import com.unciv.logic.civilization.CivilizationInfo import com.unciv.logic.civilization.PlayerType import com.unciv.logic.map.MapUnit import com.unciv.logic.trade.TradeLogic +import com.unciv.logic.trade.TradeOffer import com.unciv.logic.trade.TradeType import com.unciv.models.gamebasics.GameBasics import com.unciv.models.gamebasics.tech.Technology +import com.unciv.models.gamebasics.tr import com.unciv.ui.utils.getRandom import kotlin.math.min @@ -26,20 +28,35 @@ class NextTurnAutomation{ } private fun exchangeTechs(civInfo: CivilizationInfo) { - for (otherCiv in civInfo.diplomacy.values.map { it.otherCiv() }.filter { it.playerType == PlayerType.AI }.sortedBy { it.tech.techsResearched.size }) { + val otherCivList = civInfo.diplomacy.values.map { it.otherCiv() }. + filter { it.playerType == PlayerType.AI && !it.isBarbarianCivilization() }. + sortedBy { it.tech.techsResearched.size } + + for (otherCiv in otherCivList) { val tradeLogic = TradeLogic(civInfo, otherCiv) + var ourGold = tradeLogic.ourAvailableOffers.first { it.type == TradeType.Gold }.amount val ourTradableTechs = tradeLogic.ourAvailableOffers .filter { it.type == TradeType.Technology } val theirTradableTechs = tradeLogic.theirAvailableOffers .filter { it.type == TradeType.Technology } - for (ourOffer in ourTradableTechs) { - val theirOfferList = theirTradableTechs.filter{ - tradeLogic.evaluateOffer(ourOffer, false) >= tradeLogic.evaluateOffer(it, false) - && !tradeLogic.currentTrade.theirOffers.contains(it) } - if (theirOfferList.isNotEmpty()) { - tradeLogic.currentTrade.ourOffers.add(ourOffer) - tradeLogic.currentTrade.theirOffers.add(theirOfferList.getRandom()) + for (theirOffer in theirTradableTechs) { + val theirValue = tradeLogic.evaluateOffer(theirOffer, false) + val ourOfferList = ourTradableTechs.filter{ + tradeLogic.evaluateOffer(it, false) == theirValue + && !tradeLogic.currentTrade.ourOffers.contains(it) } + + if (ourOfferList.isNotEmpty()) { + tradeLogic.currentTrade.ourOffers.add(ourOfferList.getRandom()) + tradeLogic.currentTrade.theirOffers.add(theirOffer) + } else { + //try to buy tech with money, not spending more than 1/3 of treasury + if (ourGold / 3 >= theirValue) + { + tradeLogic.currentTrade.ourOffers.add(TradeOffer("Gold".tr(), TradeType.Gold, 0, theirValue)) + tradeLogic.currentTrade.theirOffers.add(theirOffer) + ourGold -= theirValue + } } } From fa8c948c049c8ea9256681bc316fb185317ca335 Mon Sep 17 00:00:00 2001 From: Duan Tao Date: Tue, 22 Jan 2019 15:05:32 +0800 Subject: [PATCH 3/4] Allow ai to spend money for building & unit. --- .../src/com/unciv/logic/city/CityConstructions.kt | 15 ++++++++++++++- .../com/unciv/ui/cityscreen/ConstructionsTable.kt | 5 ++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/core/src/com/unciv/logic/city/CityConstructions.kt b/core/src/com/unciv/logic/city/CityConstructions.kt index 46f6d6e39c..36af78cf8d 100644 --- a/core/src/com/unciv/logic/city/CityConstructions.kt +++ b/core/src/com/unciv/logic/city/CityConstructions.kt @@ -2,6 +2,7 @@ package com.unciv.logic.city import com.badlogic.gdx.graphics.Color import com.unciv.logic.automation.Automation +import com.unciv.logic.civilization.PlayerType import com.unciv.models.gamebasics.Building import com.unciv.models.gamebasics.GameBasics import com.unciv.models.gamebasics.tr @@ -125,6 +126,11 @@ class CityConstructions { inProgressConstructions[currentConstruction] = inProgressConstructions[currentConstruction]!! + productionToAdd } + fun canBePruchasedWithGold(construction: IConstruction): Boolean { + return construction !is SpecialConstruction && + !(construction is Building && construction.isWonder) + } + fun nextTurn(cityStats: Stats) { var construction = getConstruction(currentConstruction) if(construction is SpecialConstruction) return @@ -144,8 +150,15 @@ class CityConstructions { val productionCost = construction.getProductionCost(cityInfo.civInfo.policies.adoptedPolicies) if (inProgressConstructions[currentConstruction]!! >= productionCost) { constructionComplete(construction) - } + //allow ai spending money to purchase building & unit. Buying staff has slightly lower priority than buying tech. + while (cityInfo.civInfo.playerType == PlayerType.AI + && cityInfo.population.population >= 5 + && canBePruchasedWithGold(getConstruction(currentConstruction)) + && cityInfo.civInfo.gold / 5 >= getConstruction(currentConstruction).getGoldCost(cityInfo.civInfo.policies.getAdoptedPolicies()) ) { + purchaseBuilding(currentConstruction) + } + } } fun constructionComplete(construction: IConstruction) { diff --git a/core/src/com/unciv/ui/cityscreen/ConstructionsTable.kt b/core/src/com/unciv/ui/cityscreen/ConstructionsTable.kt index cb03a85bac..026cb55188 100644 --- a/core/src/com/unciv/ui/cityscreen/ConstructionsTable.kt +++ b/core/src/com/unciv/ui/cityscreen/ConstructionsTable.kt @@ -8,6 +8,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.scenes.scene2d.ui.TextButton import com.badlogic.gdx.utils.Align import com.unciv.logic.city.CityInfo +import com.unciv.logic.city.IConstruction import com.unciv.logic.city.SpecialConstruction import com.unciv.models.gamebasics.Building import com.unciv.models.gamebasics.GameBasics @@ -123,9 +124,7 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre row() val purchaseConstructionButton: TextButton - if (construction !is SpecialConstruction && - !(construction is Building && construction.isWonder)) { - + if (city.cityConstructions.canBePruchasedWithGold(construction)) { val buildingGoldCost = construction.getGoldCost(city.civInfo.policies.getAdoptedPolicies()) purchaseConstructionButton = TextButton("Buy for [$buildingGoldCost] gold".tr(), CameraStageBaseScreen.skin) purchaseConstructionButton.onClick("coin") { From a141cb1f1c636f8c3050fc49996940a4a9022003 Mon Sep 17 00:00:00 2001 From: Duan Tao Date: Wed, 23 Jan 2019 15:52:04 +0800 Subject: [PATCH 4/4] Rearrange code for pruchasing stuff. --- .../logic/automation/NextTurnAutomation.kt | 26 +++++++++++++++---- .../com/unciv/logic/city/CityConstructions.kt | 13 ---------- .../src/com/unciv/logic/city/IConstruction.kt | 4 +++ core/src/com/unciv/logic/trade/TradeLogic.kt | 4 +-- .../com/unciv/models/gamebasics/Building.kt | 3 +++ .../unciv/models/gamebasics/unit/BaseUnit.kt | 4 +++ .../unciv/ui/cityscreen/ConstructionsTable.kt | 3 +-- 7 files changed, 35 insertions(+), 22 deletions(-) diff --git a/core/src/com/unciv/logic/automation/NextTurnAutomation.kt b/core/src/com/unciv/logic/automation/NextTurnAutomation.kt index aebc99c513..5af3364e37 100644 --- a/core/src/com/unciv/logic/automation/NextTurnAutomation.kt +++ b/core/src/com/unciv/logic/automation/NextTurnAutomation.kt @@ -22,11 +22,23 @@ class NextTurnAutomation{ exchangeLuxuries(civInfo) declareWar(civInfo) automateCityBombardment(civInfo) + buyBuildingOrUnit(civInfo) automateUnits(civInfo) reassignWorkedTiles(civInfo) trainSettler(civInfo) } + private fun buyBuildingOrUnit(civInfo: CivilizationInfo) { + //allow ai spending money to purchase building & unit. Buying staff has slightly lower priority than buying tech. + for (city in civInfo.cities.sortedByDescending{ it.population.population }) { + val construction = city.cityConstructions.getCurrentConstruction() + if (construction.canBePurchased() + && city.civInfo.gold / 3 >= construction.getGoldCost(civInfo.policies.getAdoptedPolicies()) ) { + city.cityConstructions.purchaseBuilding(construction.name) + } + } + } + private fun exchangeTechs(civInfo: CivilizationInfo) { val otherCivList = civInfo.diplomacy.values.map { it.otherCiv() }. filter { it.playerType == PlayerType.AI && !it.isBarbarianCivilization() }. @@ -51,7 +63,7 @@ class NextTurnAutomation{ tradeLogic.currentTrade.theirOffers.add(theirOffer) } else { //try to buy tech with money, not spending more than 1/3 of treasury - if (ourGold / 3 >= theirValue) + if (ourGold / 2 >= theirValue) { tradeLogic.currentTrade.ourOffers.add(TradeOffer("Gold".tr(), TradeType.Gold, 0, theirValue)) tradeLogic.currentTrade.theirOffers.add(theirOffer) @@ -73,10 +85,14 @@ class NextTurnAutomation{ val costs = techsGroups.keys.sorted() val tech: Technology - if (techsGroups[costs[0]]!!.size == 1 || costs.size == 1) { - tech = techsGroups[costs[0]]!!.getRandom() + val techsCheapest = techsGroups[costs[0]]!! + //Do not consider advanced techs if only one tech left in cheapest groupe + if (techsCheapest.size == 1 || costs.size == 1) { + tech = techsCheapest.getRandom() } else { - tech = (techsGroups[costs[0]]!! + techsGroups[costs[1]]!!).getRandom() + //Choose randomly between cheapest and second cheapest groupe + val techsAdvanced = techsGroups[costs[1]]!! + tech = (techsCheapest + techsAdvanced).getRandom() } civInfo.tech.techsToResearch.add(tech.name) } @@ -199,4 +215,4 @@ class NextTurnAutomation{ } } -} \ No newline at end of file +} diff --git a/core/src/com/unciv/logic/city/CityConstructions.kt b/core/src/com/unciv/logic/city/CityConstructions.kt index 36af78cf8d..310b95f4b5 100644 --- a/core/src/com/unciv/logic/city/CityConstructions.kt +++ b/core/src/com/unciv/logic/city/CityConstructions.kt @@ -126,11 +126,6 @@ class CityConstructions { inProgressConstructions[currentConstruction] = inProgressConstructions[currentConstruction]!! + productionToAdd } - fun canBePruchasedWithGold(construction: IConstruction): Boolean { - return construction !is SpecialConstruction && - !(construction is Building && construction.isWonder) - } - fun nextTurn(cityStats: Stats) { var construction = getConstruction(currentConstruction) if(construction is SpecialConstruction) return @@ -150,14 +145,6 @@ class CityConstructions { val productionCost = construction.getProductionCost(cityInfo.civInfo.policies.adoptedPolicies) if (inProgressConstructions[currentConstruction]!! >= productionCost) { constructionComplete(construction) - - //allow ai spending money to purchase building & unit. Buying staff has slightly lower priority than buying tech. - while (cityInfo.civInfo.playerType == PlayerType.AI - && cityInfo.population.population >= 5 - && canBePruchasedWithGold(getConstruction(currentConstruction)) - && cityInfo.civInfo.gold / 5 >= getConstruction(currentConstruction).getGoldCost(cityInfo.civInfo.policies.getAdoptedPolicies()) ) { - purchaseBuilding(currentConstruction) - } } } diff --git a/core/src/com/unciv/logic/city/IConstruction.kt b/core/src/com/unciv/logic/city/IConstruction.kt index 9665731384..bf18d9dd5c 100644 --- a/core/src/com/unciv/logic/city/IConstruction.kt +++ b/core/src/com/unciv/logic/city/IConstruction.kt @@ -8,6 +8,7 @@ interface IConstruction : INamed, ICivilopedia { fun getGoldCost(adoptedPolicies: HashSet): Int fun isBuildable(construction: CityConstructions): Boolean fun postBuildEvent(construction: CityConstructions) // Yes I'm hilarious. + fun canBePurchased(): Boolean } @@ -35,6 +36,9 @@ open class SpecialConstruction(override var name: String, override val descripti } } + override fun canBePurchased(): Boolean { + return false + } override fun getProductionCost(adoptedPolicies: HashSet): Int { throw Exception("Impossible!") diff --git a/core/src/com/unciv/logic/trade/TradeLogic.kt b/core/src/com/unciv/logic/trade/TradeLogic.kt index 00bea2faf5..830e48f0b3 100644 --- a/core/src/com/unciv/logic/trade/TradeLogic.kt +++ b/core/src/com/unciv/logic/trade/TradeLogic.kt @@ -91,7 +91,7 @@ class TradeLogic(val ourCivilization:CivilizationInfo, val otherCivilization: Ci return value } } - TradeType.Technology -> return sqrt(GameBasics.Technologies[offer.name]!!.cost.toDouble()).toInt()*10 + TradeType.Technology -> return sqrt(GameBasics.Technologies[offer.name]!!.cost.toDouble()).toInt()*20 TradeType.Strategic_Resource -> { if(otherCivIsRecieving) { val resources = ourCivilization.getCivResourcesByName() @@ -211,4 +211,4 @@ class TradeLogic(val ourCivilization:CivilizationInfo, val otherCivilization: Ci transferTrade(ourCivilization,otherCivilization,currentTrade) transferTrade(otherCivilization,ourCivilization,currentTrade.reverse()) } -} \ No newline at end of file +} diff --git a/core/src/com/unciv/models/gamebasics/Building.kt b/core/src/com/unciv/models/gamebasics/Building.kt index b245fdea46..891196b78b 100644 --- a/core/src/com/unciv/models/gamebasics/Building.kt +++ b/core/src/com/unciv/models/gamebasics/Building.kt @@ -149,6 +149,9 @@ class Building : NamedStats(), IConstruction{ return stats } + override fun canBePurchased(): Boolean { + return !isWonder + } override fun getProductionCost(adoptedPolicies: HashSet): Int { return if (!isWonder && culture != 0f && adoptedPolicies.contains("Piety")) (cost * 0.85).toInt() diff --git a/core/src/com/unciv/models/gamebasics/unit/BaseUnit.kt b/core/src/com/unciv/models/gamebasics/unit/BaseUnit.kt index ee91b883f2..f83c836f84 100644 --- a/core/src/com/unciv/models/gamebasics/unit/BaseUnit.kt +++ b/core/src/com/unciv/models/gamebasics/unit/BaseUnit.kt @@ -81,6 +81,10 @@ class BaseUnit : INamed, IConstruction, ICivilopedia { return unit } + override fun canBePurchased(): Boolean { + return true + } + override fun getProductionCost(adoptedPolicies: HashSet): Int = cost override fun getGoldCost(adoptedPolicies: HashSet): Int { diff --git a/core/src/com/unciv/ui/cityscreen/ConstructionsTable.kt b/core/src/com/unciv/ui/cityscreen/ConstructionsTable.kt index 026cb55188..11cd3c9c9a 100644 --- a/core/src/com/unciv/ui/cityscreen/ConstructionsTable.kt +++ b/core/src/com/unciv/ui/cityscreen/ConstructionsTable.kt @@ -8,7 +8,6 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.scenes.scene2d.ui.TextButton import com.badlogic.gdx.utils.Align import com.unciv.logic.city.CityInfo -import com.unciv.logic.city.IConstruction import com.unciv.logic.city.SpecialConstruction import com.unciv.models.gamebasics.Building import com.unciv.models.gamebasics.GameBasics @@ -124,7 +123,7 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre row() val purchaseConstructionButton: TextButton - if (city.cityConstructions.canBePruchasedWithGold(construction)) { + if (construction.canBePurchased()) { val buildingGoldCost = construction.getGoldCost(city.civInfo.policies.getAdoptedPolicies()) purchaseConstructionButton = TextButton("Buy for [$buildingGoldCost] gold".tr(), CameraStageBaseScreen.skin) purchaseConstructionButton.onClick("coin") {