From e60873d75a36b8078f0d30af6d5f826fdad58d2c Mon Sep 17 00:00:00 2001 From: EmperorPinguin <99119424+EmperorPinguin@users.noreply.github.com> Date: Sun, 20 Oct 2024 13:20:53 +0200 Subject: [PATCH] Update AI trading logic (#12305) * AI behaviour changes * Update Automation.kt * Update Automation.kt * Update Automation.kt * Update Automation.kt * Update Automation.kt * Update ConstructionAutomation.kt * Update Automation.kt * Reverting some changes * Changes * revert changes * revert changes * revert changes * revert changes * Update CityLocationTileRanker.kt * Citizen assignment for stat conversion * Update CityLocationTileRanker.kt * Reduce AI settling * Avoid AI building units when in negative Supply * Update CityLocationTileRanker.kt * Update CityLocationTileRanker.kt * Update CityLocationTileRanker.kt * Update ConstructionAutomation.kt * Update build.gradle.kts * Update gradle-wrapper.properties * Update CityLocationTileRanker.kt * Update CityLocationTileRanker.kt * Update ConstructionAutomation.kt * Update CityLocationTileRanker.kt * AI changes for humans * Fix puppet focus * Update Automation.kt * Puppet focus * Update Automation.kt * Update Automation.kt * Update Automation.kt * Update Automation.kt * Update Automation.kt * Update Automation.kt * Update Automation.kt * Update Automation.kt * Update Automation.kt * Update Stats.kt * Update CityTurnManager.kt * Remove specialist science modifier * Update ReligionAutomation.kt * Update ReligionAutomation.kt * Update ReligionAutomation.kt * Update CivilianUnitAutomation.kt * Update ReligionAutomation.kt * Worker prioritization Workers are valuable in expand cities. * Update ConstructionAutomation.kt Food always important, it's rarely good to skip e.g. granary if we're on 6 pop. * Update ConstructionAutomation.kt Should achieve about the same with less lines of code. * Update Automation.kt * Update ConstructionAutomation.kt * Update Policies.json * Update Policies.json * Update Policies.json * Update ConstructionAutomation.kt * Update Policies.json * Update ReligionAutomation.kt * Update ReligionAutomation.kt * Update ReligionAutomation.kt * Update ReligionAutomation.kt * Rename Crop Yield to Growth * Update worker usage * Update UnitAutomation.kt * Tutorials update * Update Tutorials.json * Fix spelling error * Update Tutorials.json * Update Tutorials.json * Update Tutorials.json * Update Tutorials.json * Update Tutorials.json * Update Tutorials.json * Update Tutorials.json * Update Tutorials.json * AI tech and policy choices * Update Techs.json * Update Policies.json * Update ConstructionAutomation.kt * Update UnitPromotions.json * Update * Update Policies.json * Update Tutorials.json * ReligionAutomation bugfix * Update ReligionAutomation.kt * Update ReligionAutomation.kt * Update ReligionAutomation.kt * Update ReligionAutomation.kt * Update ReligionAutomation.kt * Update ReligionAutomation.kt * Update ReligionAutomation.kt * Update AI city settling and science game * Update ReligionAutomation.kt * Maybe revert this now the belief picking has improved * Update ReligionAutomation.kt * Remove some if-statements * Update Automation.kt * Update Automation.kt * Update ConsoleLauncher.kt * Update * Update Automation.kt * Update TileImprovements.json * Update AI trading * Update TradeAutomation.kt --- .../automation/civilization/TradeAutomation.kt | 8 ++++---- core/src/com/unciv/logic/trade/TradeEvaluation.kt | 14 ++++++++------ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/core/src/com/unciv/logic/automation/civilization/TradeAutomation.kt b/core/src/com/unciv/logic/automation/civilization/TradeAutomation.kt index 6d3318ec78357..460a5e1b8ab3c 100644 --- a/core/src/com/unciv/logic/automation/civilization/TradeAutomation.kt +++ b/core/src/com/unciv/logic/automation/civilization/TradeAutomation.kt @@ -52,9 +52,8 @@ object TradeAutomation { * guaranteed to find the best or closest one. */ private fun getCounteroffer(civInfo: Civilization, tradeRequest: TradeRequest): TradeRequest? { val otherCiv = civInfo.gameInfo.getCivilization(tradeRequest.requestingCiv) - // AIs counteroffering each other is problematic as they tend to ping-pong back and forth forever - if (otherCiv.playerType == PlayerType.AI) - return null + // AIs counteroffering each other could be problematic if they ping-pong back and forth forever + // If this happens, that means our trade automation doesn't settle into an equilibrium that's favourable to both parties, so that should be updated when observed val evaluation = TradeEvaluation() var deltaInOurFavor = evaluation.getTradeAcceptability(tradeRequest.trade, civInfo, otherCiv, true) if (deltaInOurFavor > 0) deltaInOurFavor = (deltaInOurFavor / 1.1f).toInt() // They seem very interested in this deal, let's push it a bit. @@ -75,7 +74,8 @@ object TradeAutomation { continue // For example resources gained by trade or CS if (offer.type == TradeOfferType.City) continue // Players generally don't want to give up their cities, and they might misclick - + if (offer.type == TradeOfferType.Luxury_Resource) + continue // Don't ask for luxuries as counteroffer, players likely don't want to sell them if they didn't offer them already if (tradeLogic.currentTrade.theirOffers.any { it.type == offer.type && it.name == offer.name }) continue // So you don't get double offers of open borders declarations of war etc. if (offer.type == TradeOfferType.Treaty) diff --git a/core/src/com/unciv/logic/trade/TradeEvaluation.kt b/core/src/com/unciv/logic/trade/TradeEvaluation.kt index d868008ab7fc2..0758a03137ad6 100644 --- a/core/src/com/unciv/logic/trade/TradeEvaluation.kt +++ b/core/src/com/unciv/logic/trade/TradeEvaluation.kt @@ -115,8 +115,10 @@ class TradeEvaluation { private fun evaluateBuyCost(offer: TradeOffer, civInfo: Civilization, tradePartner: Civilization, trade: Trade): Int { when (offer.type) { TradeOfferType.Gold -> return offer.amount - // GPT loses 1% of value for each 'future' turn, meaning: gold now is more valuable than gold in the future - TradeOfferType.Gold_Per_Turn -> return (1..offer.duration).sumOf { offer.amount * 0.99.pow(it) }.toInt() + // GPT loses value for each 'future' turn, meaning: gold now is more valuable than gold in the future + // Empire-wide production tends to grow at roughly 2% per turn (quick speed), so let's take that as a base line + // Formula could be more sophisticated by taking into account game speed and estimated chance of the gpt-giver cancelling the trade after X amount of turns + TradeOfferType.Gold_Per_Turn -> return (1..offer.duration).sumOf { offer.amount * 0.98.pow(it) }.toInt() TradeOfferType.Treaty -> { return when (offer.name) { // Since it will be evaluated twice, once when they evaluate our offer and once when they evaluate theirs @@ -332,11 +334,11 @@ class TradeEvaluation { fun getGoldInflation(civInfo: Civilization): Double { val modifier = 1000.0 val goldPerTurn = civInfo.stats.statsForNextTurn.gold.toDouble() - // To visualise the function, plug this into a 2d graphing calculator \frac{1000}{x^{1.2}+1.11*1000} - // Goes from 1 at GPT = 0 to .834 at GPT = 100, .296 at GPT = 1000 and 0.116 at GPT = 10000 - // The current value of gold will never go below 10% or the .1f that it is set to + // To visualise the function, plug this into a 2d graphing calculator \frac{1000}{x^{1.2}+1.66*1000} + // Goes from 1 at GPT = 0 to .923 at GPT = 100, .577 at GPT = 1000 and 0.415 at GPT = 10000 + // The current value of gold will never go below 40%, or the .4f that it is set to (being roughly the efficiency ratio between purchasing and upgrading units) // So this does not scale off to infinity - return modifier / (goldPerTurn.coerceAtLeast(1.0).pow(1.2) + (1.11 * modifier)) + .1 + return modifier/ (goldPerTurn.coerceAtLeast(1.0).pow(1.2) + (1.66 * modifier)) + .4 } /** This code returns a positive value if the city is significantly far away from the capital