Merge pull request #432 from ninjatao/ai_exchange_tech

Ai exchange tech
This commit is contained in:
Yair Morgenstern 2019-01-23 11:28:48 +02:00 committed by GitHub
commit 0e5c1843fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 92 additions and 15 deletions

View File

@ -58,11 +58,11 @@ class GameInfo {
while(thisPlayer.playerType==PlayerType.AI){ while(thisPlayer.playerType==PlayerType.AI){
NextTurnAutomation().automateCivMoves(thisPlayer) NextTurnAutomation().automateCivMoves(thisPlayer)
if (thisPlayer.tech.techsToResearch.isEmpty()) { // should belong in automation? yes/no? // if (thisPlayer.tech.techsToResearch.isEmpty()) { // should belong in automation? yes/no?
val researchableTechs = GameBasics.Technologies.values // val researchableTechs = GameBasics.Technologies.values
.filter { !thisPlayer.tech.isResearched(it.name) && thisPlayer.tech.canBeResearched(it.name) } // .filter { !thisPlayer.tech.isResearched(it.name) && thisPlayer.tech.canBeResearched(it.name) }
thisPlayer.tech.techsToResearch.add(researchableTechs.minBy { it.cost }!!.name) // thisPlayer.tech.techsToResearch.add(researchableTechs.minBy { it.cost }!!.name)
} // }
switchTurn() switchTurn()
} }

View File

@ -2,31 +2,99 @@ package com.unciv.logic.automation
import com.unciv.logic.city.CityInfo import com.unciv.logic.city.CityInfo
import com.unciv.logic.civilization.CivilizationInfo import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.civilization.PlayerType
import com.unciv.logic.map.MapUnit import com.unciv.logic.map.MapUnit
import com.unciv.logic.trade.TradeLogic import com.unciv.logic.trade.TradeLogic
import com.unciv.logic.trade.TradeOffer
import com.unciv.logic.trade.TradeType import com.unciv.logic.trade.TradeType
import com.unciv.models.gamebasics.GameBasics 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 com.unciv.ui.utils.getRandom
import kotlin.math.min import kotlin.math.min
class NextTurnAutomation{ class NextTurnAutomation{
fun automateCivMoves(civInfo: CivilizationInfo) { fun automateCivMoves(civInfo: CivilizationInfo) {
exchangeTechs(civInfo)
chooseTechToResearch(civInfo) chooseTechToResearch(civInfo)
adoptPolicy(civInfo) adoptPolicy(civInfo)
exchangeLuxuries(civInfo) exchangeLuxuries(civInfo)
declareWar(civInfo) declareWar(civInfo)
automateCityBombardment(civInfo) automateCityBombardment(civInfo)
buyBuildingOrUnit(civInfo)
automateUnits(civInfo) automateUnits(civInfo)
reassignWorkedTiles(civInfo) reassignWorkedTiles(civInfo)
trainSettler(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() }.
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 (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 / 2 >= theirValue)
{
tradeLogic.currentTrade.ourOffers.add(TradeOffer("Gold".tr(), TradeType.Gold, 0, theirValue))
tradeLogic.currentTrade.theirOffers.add(theirOffer)
ourGold -= theirValue
}
}
}
if (tradeLogic.currentTrade.theirOffers.isNotEmpty()) {
tradeLogic.acceptTrade()
}
}
}
private fun chooseTechToResearch(civInfo: CivilizationInfo) { private fun chooseTechToResearch(civInfo: CivilizationInfo) {
if (civInfo.tech.techsToResearch.isEmpty()) { if (civInfo.tech.techsToResearch.isEmpty()) {
val researchableTechs = GameBasics.Technologies.values.filter { civInfo.tech.canBeResearched(it.name) } val researchableTechs = GameBasics.Technologies.values.filter { !civInfo.tech.isResearched(it.name) && civInfo.tech.canBeResearched(it.name) }
val techToResearch = researchableTechs.groupBy { it.cost }.minBy { it.key }!!.value.getRandom() val techsGroups = researchableTechs.groupBy { it.cost }
civInfo.tech.techsResearched.add(techToResearch.name) val costs = techsGroups.keys.sorted()
val tech: Technology
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 {
//Choose randomly between cheapest and second cheapest groupe
val techsAdvanced = techsGroups[costs[1]]!!
tech = (techsCheapest + techsAdvanced).getRandom()
}
civInfo.tech.techsToResearch.add(tech.name)
} }
} }
@ -147,4 +215,4 @@ class NextTurnAutomation{
} }
} }
} }

View File

@ -2,6 +2,7 @@ package com.unciv.logic.city
import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.Color
import com.unciv.logic.automation.Automation import com.unciv.logic.automation.Automation
import com.unciv.logic.civilization.PlayerType
import com.unciv.models.gamebasics.Building import com.unciv.models.gamebasics.Building
import com.unciv.models.gamebasics.GameBasics import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.gamebasics.tr import com.unciv.models.gamebasics.tr
@ -145,7 +146,6 @@ class CityConstructions {
if (inProgressConstructions[currentConstruction]!! >= productionCost) { if (inProgressConstructions[currentConstruction]!! >= productionCost) {
constructionComplete(construction) constructionComplete(construction)
} }
} }
fun constructionComplete(construction: IConstruction) { fun constructionComplete(construction: IConstruction) {

View File

@ -8,6 +8,7 @@ interface IConstruction : INamed, ICivilopedia {
fun getGoldCost(adoptedPolicies: HashSet<String>): Int fun getGoldCost(adoptedPolicies: HashSet<String>): Int
fun isBuildable(construction: CityConstructions): Boolean fun isBuildable(construction: CityConstructions): Boolean
fun postBuildEvent(construction: CityConstructions) // Yes I'm hilarious. 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<String>): Int { override fun getProductionCost(adoptedPolicies: HashSet<String>): Int {
throw Exception("Impossible!") throw Exception("Impossible!")

View File

@ -91,7 +91,7 @@ class TradeLogic(val ourCivilization:CivilizationInfo, val otherCivilization: Ci
return value 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 -> { TradeType.Strategic_Resource -> {
if(otherCivIsRecieving) { if(otherCivIsRecieving) {
val resources = ourCivilization.getCivResourcesByName() val resources = ourCivilization.getCivResourcesByName()
@ -211,4 +211,4 @@ class TradeLogic(val ourCivilization:CivilizationInfo, val otherCivilization: Ci
transferTrade(ourCivilization,otherCivilization,currentTrade) transferTrade(ourCivilization,otherCivilization,currentTrade)
transferTrade(otherCivilization,ourCivilization,currentTrade.reverse()) transferTrade(otherCivilization,ourCivilization,currentTrade.reverse())
} }
} }

View File

@ -149,6 +149,9 @@ class Building : NamedStats(), IConstruction{
return stats return stats
} }
override fun canBePurchased(): Boolean {
return !isWonder
}
override fun getProductionCost(adoptedPolicies: HashSet<String>): Int { override fun getProductionCost(adoptedPolicies: HashSet<String>): Int {
return if (!isWonder && culture != 0f && adoptedPolicies.contains("Piety")) (cost * 0.85).toInt() return if (!isWonder && culture != 0f && adoptedPolicies.contains("Piety")) (cost * 0.85).toInt()

View File

@ -81,6 +81,10 @@ class BaseUnit : INamed, IConstruction, ICivilopedia {
return unit return unit
} }
override fun canBePurchased(): Boolean {
return true
}
override fun getProductionCost(adoptedPolicies: HashSet<String>): Int = cost override fun getProductionCost(adoptedPolicies: HashSet<String>): Int = cost
override fun getGoldCost(adoptedPolicies: HashSet<String>): Int { override fun getGoldCost(adoptedPolicies: HashSet<String>): Int {

View File

@ -123,9 +123,7 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre
row() row()
val purchaseConstructionButton: TextButton val purchaseConstructionButton: TextButton
if (construction !is SpecialConstruction && if (construction.canBePurchased()) {
!(construction is Building && construction.isWonder)) {
val buildingGoldCost = construction.getGoldCost(city.civInfo.policies.getAdoptedPolicies()) val buildingGoldCost = construction.getGoldCost(city.civInfo.policies.getAdoptedPolicies())
purchaseConstructionButton = TextButton("Buy for [$buildingGoldCost] gold".tr(), CameraStageBaseScreen.skin) purchaseConstructionButton = TextButton("Buy for [$buildingGoldCost] gold".tr(), CameraStageBaseScreen.skin)
purchaseConstructionButton.onClick("coin") { purchaseConstructionButton.onClick("coin") {