AI trading uses gold inflation (#10370)

* Fixed cities being sold for at most 1000 gold

* Replaced evaluateBuy/SellCost with evaluateBuy/SellCostWithInflation

* Fixed goldInflation being multiplied instead of divided

* Increased inflation modifier, lowering it's impact

* Changed inflation values to be lower

* Moved return value to be inline again (it was moved for testing)
This commit is contained in:
Oskar Niesen
2023-10-29 11:58:59 -05:00
committed by GitHub
parent bd7db9b21a
commit cb661182ec
2 changed files with 33 additions and 8 deletions

View File

@ -175,7 +175,7 @@ object NextTurnAutomation {
if (offer.type == TradeType.Treaty)
continue // Don't try to counter with a defensive pact or research pact
val value = evaluation.evaluateBuyCost(offer, civInfo, otherCiv)
val value = evaluation.evaluateBuyCostWithInflation(offer, civInfo, otherCiv)
if (value > 0)
potentialAsks[offer] = value
}
@ -204,7 +204,7 @@ object NextTurnAutomation {
// Remove 1 amount as long as doing so does not change the price
val originalValue = counterofferAsks[ask]!!
while (ask.amount > 1
&& originalValue == evaluation.evaluateBuyCost(
&& originalValue == evaluation.evaluateBuyCostWithInflation(
TradeOffer(ask.name, ask.type, ask.amount - 1, ask.duration),
civInfo, otherCiv) ) {
ask.amount--
@ -216,7 +216,7 @@ object NextTurnAutomation {
for (goldAsk in counterofferAsks.keys
.filter { it.type == TradeType.Gold_Per_Turn || it.type == TradeType.Gold }
.sortedByDescending { it.type.ordinal }) { // Do GPT first
val valueOfOne = evaluation.evaluateBuyCost(TradeOffer(goldAsk.name, goldAsk.type, 1, goldAsk.duration), civInfo, otherCiv)
val valueOfOne = evaluation.evaluateBuyCostWithInflation(TradeOffer(goldAsk.name, goldAsk.type, 1, goldAsk.duration), civInfo, otherCiv)
val amountCanBeRemoved = deltaInOurFavor / valueOfOne
if (amountCanBeRemoved >= goldAsk.amount) {
deltaInOurFavor -= counterofferAsks[goldAsk]!!
@ -236,7 +236,7 @@ object NextTurnAutomation {
.sortedByDescending { it.type.ordinal }) {
if (tradeLogic.currentTrade.theirOffers.none { it.type == ourGold.type } &&
counterofferAsks.keys.none { it.type == ourGold.type } ) {
val valueOfOne = evaluation.evaluateSellCost(TradeOffer(ourGold.name, ourGold.type, 1, ourGold.duration), civInfo, otherCiv)
val valueOfOne = evaluation.evaluateSellCostWithInflation(TradeOffer(ourGold.name, ourGold.type, 1, ourGold.duration), civInfo, otherCiv)
val amountToGive = min(deltaInOurFavor / valueOfOne, ourGold.amount)
deltaInOurFavor -= amountToGive * valueOfOne
if (amountToGive > 0) {

View File

@ -6,7 +6,6 @@ import com.unciv.logic.automation.ThreatLevel
import com.unciv.logic.automation.civilization.NextTurnAutomation
import com.unciv.logic.city.City
import com.unciv.logic.civilization.Civilization
import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
import com.unciv.logic.civilization.diplomacy.RelationshipLevel
import com.unciv.logic.map.tile.Tile
import com.unciv.models.ruleset.ModOptionsConstants
@ -73,9 +72,9 @@ class TradeEvaluation {
val sumOfTheirOffers = trade.theirOffers.asSequence()
.filter { it.type != TradeType.Treaty } // since treaties should only be evaluated once for 2 sides
.map { evaluateBuyCost(it, evaluator, tradePartner) }.sum()
.map { evaluateBuyCostWithInflation(it, evaluator, tradePartner) }.sum()
var sumOfOurOffers = trade.ourOffers.sumOf { evaluateSellCost(it, evaluator, tradePartner) }
var sumOfOurOffers = trade.ourOffers.sumOf { evaluateSellCostWithInflation(it, evaluator, tradePartner) }
val relationshipLevel = evaluator.getDiplomacyManager(tradePartner).relationshipIgnoreAfraid()
// If we're making a peace treaty, don't try to up the bargain for people you don't like.
@ -94,6 +93,12 @@ class TradeEvaluation {
return sumOfTheirOffers - sumOfOurOffers
}
fun evaluateBuyCostWithInflation(offer: TradeOffer, civInfo: Civilization, tradePartner: Civilization): Int {
if (offer.type != TradeType.Gold && offer.type != TradeType.Gold_Per_Turn)
return (evaluateBuyCost(offer, civInfo, tradePartner) / getGoldInflation(civInfo)).toInt()
return evaluateBuyCost(offer, civInfo, tradePartner)
}
fun evaluateBuyCost(offer: TradeOffer, civInfo: Civilization, tradePartner: Civilization): Int {
when (offer.type) {
@ -198,6 +203,12 @@ class TradeEvaluation {
}
fun evaluateSellCostWithInflation(offer: TradeOffer, civInfo: Civilization, tradePartner: Civilization): Int {
if (offer.type != TradeType.Gold && offer.type != TradeType.Gold_Per_Turn)
return (evaluateSellCost(offer, civInfo, tradePartner) / getGoldInflation(civInfo)).toInt()
return evaluateSellCost(offer, civInfo, tradePartner)
}
fun evaluateSellCost(offer: TradeOffer, civInfo: Civilization, tradePartner: Civilization): Int {
when (offer.type) {
TradeType.Gold -> return offer.amount
@ -275,7 +286,7 @@ class TradeEvaluation {
val stats = city.cityStats.currentCityStats
val sumOfStats =
stats.culture + stats.gold + stats.science + stats.production + stats.happiness + stats.food + distanceBonus
return min(sumOfStats.toInt() * 100, 1000)
return (sumOfStats.toInt() * 100).coerceAtLeast(1000)
}
TradeType.Agreement -> {
if (offer.name == Constants.openBorders) {
@ -292,6 +303,20 @@ class TradeEvaluation {
}
}
/**
* This returns how much one gold is worth now in comparison to starting out the game
* Gold is worth less as the civilization has a higher income
*/
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
// So this does not scale off to infinity
return modifier / (goldPerTurn.pow(1.2).coerceAtLeast(0.0) + (1.11f * modifier)) + .1f
}
/** This code returns a positive value if the city is significantly far away from the capital
* and given how this method is used this ends up making such cities more expensive. That's how
* I found it. I'm not sure it makes sense. One might also find arguments why cities closer to