summaryrefslogtreecommitdiff
path: root/sw-engine
diff options
context:
space:
mode:
authorjoffrey-bion <joffrey.bion@gmail.com>2020-11-27 01:25:09 +0100
committerjoffrey-bion <joffrey.bion@gmail.com>2020-11-27 14:38:45 +0100
commit719fcf03862174be1454731c59128d278e9523be (patch)
treea9d9c02497ea82dd36bdda7c7fa1a2a3c9ca674e /sw-engine
parentUse Kotlinx Serialization in Spring Boot instead of Jackson (diff)
downloadseven-wonders-719fcf03862174be1454731c59128d278e9523be.tar.gz
seven-wonders-719fcf03862174be1454731c59128d278e9523be.tar.bz2
seven-wonders-719fcf03862174be1454731c59128d278e9523be.zip
Introduce priced transactions
This is useful to provide information about the price per provider.
Diffstat (limited to 'sw-engine')
-rw-r--r--sw-engine/src/main/kotlin/org/luxons/sevenwonders/engine/cards/RequirementsSatisfaction.kt8
-rw-r--r--sw-engine/src/main/kotlin/org/luxons/sevenwonders/engine/resources/BestPriceCalculator.kt26
-rw-r--r--sw-engine/src/main/kotlin/org/luxons/sevenwonders/engine/resources/ResourceTransactions.kt9
-rw-r--r--sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/cards/RequirementsTest.kt10
-rw-r--r--sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/resources/BestPriceCalculatorTest.kt49
-rw-r--r--sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/resources/ResourceTransactionsTest.kt16
-rw-r--r--sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/test/TestUtils.kt22
7 files changed, 76 insertions, 64 deletions
diff --git a/sw-engine/src/main/kotlin/org/luxons/sevenwonders/engine/cards/RequirementsSatisfaction.kt b/sw-engine/src/main/kotlin/org/luxons/sevenwonders/engine/cards/RequirementsSatisfaction.kt
index 3a1ac5ce..f9566981 100644
--- a/sw-engine/src/main/kotlin/org/luxons/sevenwonders/engine/cards/RequirementsSatisfaction.kt
+++ b/sw-engine/src/main/kotlin/org/luxons/sevenwonders/engine/cards/RequirementsSatisfaction.kt
@@ -1,14 +1,14 @@
package org.luxons.sevenwonders.engine.cards
import org.luxons.sevenwonders.model.cards.PlayabilityLevel
-import org.luxons.sevenwonders.model.resources.ResourceTransactions
+import org.luxons.sevenwonders.model.resources.PricedResourceTransactions
import org.luxons.sevenwonders.model.resources.noTransactions
internal data class RequirementsSatisfaction(
val satisfied: Boolean,
val level: PlayabilityLevel,
val minPrice: Int,
- val cheapestTransactions: Set<ResourceTransactions>,
+ val cheapestTransactions: Set<PricedResourceTransactions>,
) {
companion object {
@@ -24,13 +24,13 @@ internal data class RequirementsSatisfaction(
internal fun enoughResourcesAndGold(minPrice: Int) =
RequirementsSatisfaction(true, PlayabilityLevel.ENOUGH_GOLD_AND_RES, minPrice, setOf(noTransactions()))
- internal fun metWithHelp(minPrice: Int, cheapestTransactions: Set<ResourceTransactions>) =
+ internal fun metWithHelp(minPrice: Int, cheapestTransactions: Set<PricedResourceTransactions>) =
RequirementsSatisfaction(true, PlayabilityLevel.REQUIRES_HELP, minPrice, cheapestTransactions)
internal fun missingRequiredGold(minPrice: Int) =
RequirementsSatisfaction(false, PlayabilityLevel.MISSING_REQUIRED_GOLD, minPrice, emptySet())
- internal fun missingGoldForResources(minPrice: Int, cheapestTransactions: Set<ResourceTransactions>) =
+ internal fun missingGoldForResources(minPrice: Int, cheapestTransactions: Set<PricedResourceTransactions>) =
RequirementsSatisfaction(false, PlayabilityLevel.MISSING_GOLD_FOR_RES, minPrice, cheapestTransactions)
internal fun unavailableResources() =
diff --git a/sw-engine/src/main/kotlin/org/luxons/sevenwonders/engine/resources/BestPriceCalculator.kt b/sw-engine/src/main/kotlin/org/luxons/sevenwonders/engine/resources/BestPriceCalculator.kt
index 846e7fd2..967bee2c 100644
--- a/sw-engine/src/main/kotlin/org/luxons/sevenwonders/engine/resources/BestPriceCalculator.kt
+++ b/sw-engine/src/main/kotlin/org/luxons/sevenwonders/engine/resources/BestPriceCalculator.kt
@@ -1,16 +1,15 @@
package org.luxons.sevenwonders.engine.resources
import org.luxons.sevenwonders.engine.Player
+import org.luxons.sevenwonders.model.resources.PricedResourceTransactions
import org.luxons.sevenwonders.model.resources.Provider
-import org.luxons.sevenwonders.model.resources.ResourceTransactions
import org.luxons.sevenwonders.model.resources.ResourceType
-import java.util.EnumMap
-import java.util.EnumSet
+import java.util.*
internal fun bestSolution(resources: Resources, player: Player): TransactionPlan =
BestPriceCalculator(resources, player).computeBestSolution()
-data class TransactionPlan(val price: Int, val possibleTransactions: Set<ResourceTransactions>)
+data class TransactionPlan(val price: Int, val possibleTransactions: Set<PricedResourceTransactions>)
private class ResourcePool(
val provider: Provider?,
@@ -27,9 +26,10 @@ private class BestPriceCalculator(resourcesToPay: Resources, player: Player) {
private val pools: List<ResourcePool>
private val resourcesLeftToPay: MutableResources
private val boughtResources: MutableMap<Provider, MutableResources> = EnumMap(Provider::class.java)
- private var pricePaid: Int = 0
+ private val pricePaid: MutableMap<Provider, Int> = EnumMap(Provider::class.java)
+ private var totalPricePaid: Int = 0
- private var bestSolutions: MutableSet<ResourceTransactions> = mutableSetOf()
+ private var bestSolutions: MutableSet<PricedResourceTransactions> = mutableSetOf()
private var bestPrice: Int = Integer.MAX_VALUE
init {
@@ -93,11 +93,13 @@ private class BestPriceCalculator(resourcesToPay: Resources, player: Player) {
fun buyOne(provider: Provider, type: ResourceType, cost: Int) {
boughtResources.getOrPut(provider) { MutableResources() }.add(type, 1)
- pricePaid += cost
+ pricePaid.merge(provider, cost) { old, new -> old + new }
+ totalPricePaid += cost
}
fun unbuyOne(provider: Provider, type: ResourceType, cost: Int) {
- pricePaid -= cost
+ totalPricePaid -= cost
+ pricePaid.merge(provider, -cost) { old, new -> old + new }
boughtResources[provider]!!.remove(type, 1)
}
@@ -113,14 +115,14 @@ private class BestPriceCalculator(resourcesToPay: Resources, player: Player) {
}
private fun updateBestSolutionIfNeeded() {
- if (pricePaid > bestPrice) return
+ if (totalPricePaid > bestPrice) return
- if (pricePaid < bestPrice) {
- bestPrice = pricePaid
+ if (totalPricePaid < bestPrice) {
+ bestPrice = totalPricePaid
bestSolutions.clear()
}
// avoid mutating the resources from the transactions
- val transactionSet = boughtResources.mapValues { (_, res) -> res.copy() }.toTransactions()
+ val transactionSet = boughtResources.mapValues { (_, res) -> res.copy() }.toTransactions(pricePaid)
bestSolutions.add(transactionSet)
}
}
diff --git a/sw-engine/src/main/kotlin/org/luxons/sevenwonders/engine/resources/ResourceTransactions.kt b/sw-engine/src/main/kotlin/org/luxons/sevenwonders/engine/resources/ResourceTransactions.kt
index c3e0fefa..c6309151 100644
--- a/sw-engine/src/main/kotlin/org/luxons/sevenwonders/engine/resources/ResourceTransactions.kt
+++ b/sw-engine/src/main/kotlin/org/luxons/sevenwonders/engine/resources/ResourceTransactions.kt
@@ -2,14 +2,11 @@ package org.luxons.sevenwonders.engine.resources
import org.luxons.sevenwonders.engine.Player
import org.luxons.sevenwonders.engine.converters.toCountedResourcesList
-import org.luxons.sevenwonders.model.resources.CountedResource
-import org.luxons.sevenwonders.model.resources.Provider
-import org.luxons.sevenwonders.model.resources.ResourceTransaction
-import org.luxons.sevenwonders.model.resources.ResourceTransactions
+import org.luxons.sevenwonders.model.resources.*
-fun Map<Provider, Resources>.toTransactions(): ResourceTransactions = //
+fun Map<Provider, Resources>.toTransactions(price: Map<Provider, Int>): PricedResourceTransactions = //
filterValues { !it.isEmpty() } //
- .map { (p, res) -> ResourceTransaction(p, res.toCountedResourcesList()) } //
+ .map { (p, res) -> PricedResourceTransaction(p, res.toCountedResourcesList(), price[p]!!) } //
.toSet()
fun ResourceTransactions.asResources(): Resources = flatMap { it.resources }.asResources()
diff --git a/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/cards/RequirementsTest.kt b/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/cards/RequirementsTest.kt
index d2ef7930..d3fdc94c 100644
--- a/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/cards/RequirementsTest.kt
+++ b/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/cards/RequirementsTest.kt
@@ -9,8 +9,8 @@ import org.junit.runner.RunWith
import org.luxons.sevenwonders.engine.SimplePlayer
import org.luxons.sevenwonders.engine.boards.Table
import org.luxons.sevenwonders.engine.resources.emptyResources
+import org.luxons.sevenwonders.engine.test.createPricedTransactions
import org.luxons.sevenwonders.engine.test.createRequirements
-import org.luxons.sevenwonders.engine.test.createTransactions
import org.luxons.sevenwonders.engine.test.singleBoardPlayer
import org.luxons.sevenwonders.engine.test.testBoard
import org.luxons.sevenwonders.model.resources.Provider
@@ -110,7 +110,7 @@ class RequirementsTest {
val table = Table(listOf(board, neighbourBoard))
val player = SimplePlayer(0, table)
- val resources = createTransactions(Provider.RIGHT_PLAYER, boughtResource)
+ val resources = createPricedTransactions(Provider.RIGHT_PLAYER, 2, boughtResource)
val neighbourHasResource = boughtResource == requiredResource
assertEquals(neighbourHasResource, requirements.areMetWithHelpBy(board, resources))
@@ -118,8 +118,8 @@ class RequirementsTest {
val satisfaction = requirements.assess(player)
if (neighbourHasResource) {
val transactions = setOf(
- createTransactions(Provider.LEFT_PLAYER, requiredResource),
- createTransactions(Provider.RIGHT_PLAYER, requiredResource),
+ createPricedTransactions(Provider.LEFT_PLAYER, 2, requiredResource),
+ createPricedTransactions(Provider.RIGHT_PLAYER, 2, requiredResource),
)
assertEquals(RequirementsSatisfaction.metWithHelp(2, transactions), satisfaction)
} else {
@@ -138,7 +138,7 @@ class RequirementsTest {
val table = Table(listOf(board, neighbourBoard))
val player = SimplePlayer(0, table)
- val transactions = createTransactions(Provider.RIGHT_PLAYER, requiredResource)
+ val transactions = createPricedTransactions(Provider.RIGHT_PLAYER, 2, requiredResource)
assertTrue(requirements.areMetWithHelpBy(board, transactions))
assertTrue(requirements.assess(player).satisfied)
diff --git a/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/resources/BestPriceCalculatorTest.kt b/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/resources/BestPriceCalculatorTest.kt
index 36e4046f..1a56caf4 100644
--- a/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/resources/BestPriceCalculatorTest.kt
+++ b/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/resources/BestPriceCalculatorTest.kt
@@ -3,20 +3,20 @@ package org.luxons.sevenwonders.engine.resources
import org.junit.Test
import org.luxons.sevenwonders.engine.SimplePlayer
import org.luxons.sevenwonders.engine.boards.Table
-import org.luxons.sevenwonders.engine.test.createTransaction
-import org.luxons.sevenwonders.engine.test.createTransactions
+import org.luxons.sevenwonders.engine.test.createPricedTransaction
+import org.luxons.sevenwonders.engine.test.createPricedTransactions
import org.luxons.sevenwonders.engine.test.testBoard
import org.luxons.sevenwonders.engine.test.testTable
+import org.luxons.sevenwonders.model.resources.PricedResourceTransactions
import org.luxons.sevenwonders.model.resources.Provider.LEFT_PLAYER
import org.luxons.sevenwonders.model.resources.Provider.RIGHT_PLAYER
-import org.luxons.sevenwonders.model.resources.ResourceTransactions
import org.luxons.sevenwonders.model.resources.ResourceType.*
import org.luxons.sevenwonders.model.resources.noTransactions
import kotlin.test.assertEquals
class BestPriceCalculatorTest {
- private fun solutions(price: Int, vararg resourceTransactions: ResourceTransactions) =
+ private fun solutions(price: Int, vararg resourceTransactions: PricedResourceTransactions) =
TransactionPlan(price, setOf(*resourceTransactions))
@Test
@@ -41,12 +41,12 @@ class BestPriceCalculatorTest {
val resources = resourcesOf(STONE, STONE)
- val stoneLeftSingle = createTransaction(LEFT_PLAYER, STONE)
- val stoneRightSingle = createTransaction(RIGHT_PLAYER, STONE)
+ val stoneLeftSingle = createPricedTransaction(LEFT_PLAYER, 2, STONE)
+ val stoneRightSingle = createPricedTransaction(RIGHT_PLAYER, 2, STONE)
- val stoneLeft = createTransactions(stoneLeftSingle)
- val stoneRight = createTransactions(stoneRightSingle)
- val stoneLeftAndRight = createTransactions(stoneLeftSingle, stoneRightSingle)
+ val stoneLeft = createPricedTransactions(stoneLeftSingle)
+ val stoneRight = createPricedTransactions(stoneRightSingle)
+ val stoneLeftAndRight = createPricedTransactions(stoneLeftSingle, stoneRightSingle)
assertEquals(solutions(2, stoneLeft), bestSolution(resources, player0))
assertEquals(solutions(4, stoneLeftAndRight), bestSolution(resources, player1))
@@ -70,10 +70,11 @@ class BestPriceCalculatorTest {
val resources = resourcesOf(WOOD)
- val woodLeft = createTransactions(LEFT_PLAYER, WOOD)
- val woodRight = createTransactions(RIGHT_PLAYER, WOOD)
+ val woodLeft = createPricedTransactions(LEFT_PLAYER, 2, WOOD)
+ val woodRightDiscounted = createPricedTransactions(RIGHT_PLAYER, 1, WOOD)
+ val woodRight = createPricedTransactions(RIGHT_PLAYER, 2, WOOD)
- assertEquals(solutions(1, woodRight), bestSolution(resources, player0))
+ assertEquals(solutions(1, woodRightDiscounted), bestSolution(resources, player0))
assertEquals(solutions(0, noTransactions()), bestSolution(resources, player1))
assertEquals(solutions(2, woodLeft, woodRight), bestSolution(resources, player2))
assertEquals(solutions(0, noTransactions()), bestSolution(resources, player3))
@@ -97,9 +98,9 @@ class BestPriceCalculatorTest {
val player2 = SimplePlayer(2, table)
val resources = resourcesOf(WOOD)
- val woodRight = createTransactions(RIGHT_PLAYER, WOOD)
+ val woodRightDiscounted = createPricedTransactions(RIGHT_PLAYER, 1, WOOD)
- assertEquals(solutions(1, woodRight), bestSolution(resources, player0))
+ assertEquals(solutions(1, woodRightDiscounted), bestSolution(resources, player0))
assertEquals(solutions(0, noTransactions()), bestSolution(resources, player1))
assertEquals(solutions(0, noTransactions()), bestSolution(resources, player2))
}
@@ -133,14 +134,14 @@ class BestPriceCalculatorTest {
val resources = resourcesOf(WOOD, CLAY, CLAY, CLAY)
- val claysRight = createTransaction(RIGHT_PLAYER, CLAY, CLAY)
- val claysLeft = createTransaction(LEFT_PLAYER, CLAY, CLAY)
- val clayLeft = createTransaction(LEFT_PLAYER, CLAY)
- val clayRight = createTransaction(RIGHT_PLAYER, CLAY)
+ val claysRightDiscounted = createPricedTransaction(RIGHT_PLAYER, 2, CLAY, CLAY)
+ val claysLeft = createPricedTransaction(LEFT_PLAYER, 4, CLAY, CLAY)
+ val clayLeft = createPricedTransaction(LEFT_PLAYER, 2, CLAY)
+ val clayRight = createPricedTransaction(RIGHT_PLAYER, 2, CLAY)
- assertEquals(solutions(2, createTransactions(claysRight)), bestSolution(resources, player0))
- assertEquals(solutions(2, createTransactions(clayLeft)), bestSolution(resources, player1))
- assertEquals(solutions(6, createTransactions(claysLeft, clayRight)), bestSolution(resources, player2))
+ assertEquals(solutions(2, createPricedTransactions(claysRightDiscounted)), bestSolution(resources, player0))
+ assertEquals(solutions(2, createPricedTransactions(clayLeft)), bestSolution(resources, player1))
+ assertEquals(solutions(6, createPricedTransactions(claysLeft, clayRight)), bestSolution(resources, player2))
}
@Test
@@ -164,10 +165,10 @@ class BestPriceCalculatorTest {
val player2 = SimplePlayer(2, table)
val resources = resourcesOf(ORE, CLAY)
- val oreAndClayLeft = createTransactions(LEFT_PLAYER, ORE, CLAY)
- val clayRight = createTransactions(RIGHT_PLAYER, CLAY)
+ val oreAndClayLeft = createPricedTransactions(LEFT_PLAYER, 4, ORE, CLAY)
+ val clayRightDiscounted = createPricedTransactions(RIGHT_PLAYER, 1, CLAY)
- assertEquals(solutions(1, clayRight), bestSolution(resources, player0))
+ assertEquals(solutions(1, clayRightDiscounted), bestSolution(resources, player0))
assertEquals(solutions(0, noTransactions()), bestSolution(resources, player1))
assertEquals(solutions(4, oreAndClayLeft), bestSolution(resources, player2))
}
diff --git a/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/resources/ResourceTransactionsTest.kt b/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/resources/ResourceTransactionsTest.kt
index 7b08be9a..440db729 100644
--- a/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/resources/ResourceTransactionsTest.kt
+++ b/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/resources/ResourceTransactionsTest.kt
@@ -1,7 +1,8 @@
package org.luxons.sevenwonders.engine.resources
import org.junit.Test
-import org.luxons.sevenwonders.engine.test.createTransaction
+import org.luxons.sevenwonders.engine.test.createPricedTransaction
+import org.luxons.sevenwonders.engine.test.createPricedTransactions
import org.luxons.sevenwonders.model.resources.Provider
import org.luxons.sevenwonders.model.resources.ResourceType
import org.luxons.sevenwonders.model.resources.ResourceType.CLAY
@@ -16,13 +17,16 @@ class ResourceTransactionsTest {
Provider.LEFT_PLAYER to (1 of WOOD) + (1 of CLAY),
Provider.RIGHT_PLAYER to (1 of WOOD),
)
-
- val expectedNormalized = setOf(
- createTransaction(Provider.LEFT_PLAYER, WOOD, CLAY),
- createTransaction(Provider.RIGHT_PLAYER, WOOD),
+ val priceMap = mapOf(
+ Provider.LEFT_PLAYER to 4,
+ Provider.RIGHT_PLAYER to 2,
)
- assertEquals(expectedNormalized, transactionMap.toTransactions().toSet())
+ val expectedNormalized = createPricedTransactions(
+ createPricedTransaction(Provider.LEFT_PLAYER, 4, WOOD, CLAY),
+ createPricedTransaction(Provider.RIGHT_PLAYER, 2, WOOD),
+ )
+ assertEquals(expectedNormalized, transactionMap.toTransactions(priceMap))
}
private infix fun Int.of(type: ResourceType): Resources = resourcesOf(type to this)
diff --git a/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/test/TestUtils.kt b/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/test/TestUtils.kt
index a7ed406b..0e8800f3 100644
--- a/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/test/TestUtils.kt
+++ b/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/test/TestUtils.kt
@@ -22,12 +22,7 @@ import org.luxons.sevenwonders.model.Settings
import org.luxons.sevenwonders.model.boards.RelativeBoardPosition
import org.luxons.sevenwonders.model.cards.CardBack
import org.luxons.sevenwonders.model.cards.Color
-import org.luxons.sevenwonders.model.resources.CountedResource
-import org.luxons.sevenwonders.model.resources.Provider
-import org.luxons.sevenwonders.model.resources.ResourceTransaction
-import org.luxons.sevenwonders.model.resources.ResourceTransactions
-import org.luxons.sevenwonders.model.resources.ResourceType
-import org.luxons.sevenwonders.model.resources.noTransactions
+import org.luxons.sevenwonders.model.resources.*
internal const val SEED: Long = 42
@@ -70,7 +65,20 @@ internal fun createTransactions(provider: Provider, vararg resources: ResourceTy
internal fun createTransactions(vararg transactions: ResourceTransaction): ResourceTransactions = transactions.toSet()
internal fun createTransaction(provider: Provider, vararg resources: ResourceType): ResourceTransaction =
- ResourceTransaction(provider, resources.groupBy { it }.map { (type, reps) -> CountedResource(reps.size, type) })
+ createPricedTransaction(provider, 0, *resources)
+
+internal fun createPricedTransactions(vararg transactions: PricedResourceTransaction): PricedResourceTransactions =
+ transactions.toSet()
+
+internal fun createPricedTransactions(provider: Provider, price: Int, vararg resources: ResourceType): PricedResourceTransactions =
+ createPricedTransactions(createPricedTransaction(provider, price, *resources))
+
+internal fun createPricedTransaction(provider: Provider, price: Int, vararg resources: ResourceType) =
+ PricedResourceTransaction(
+ provider = provider,
+ resources = resources.groupBy { it }.map { (type, reps) -> CountedResource(reps.size, type) },
+ totalPrice = price,
+ )
internal fun createRequirements(vararg types: ResourceType): Requirements =
Requirements(resources = resourcesOf(*types))
bgstack15