From b8a6afedb14a1d54d77df918dc1d5b53be11c44b Mon Sep 17 00:00:00 2001 From: joffrey-bion Date: Sat, 28 Nov 2020 00:21:43 +0100 Subject: Make all transactions available Sometimes the strategic move can be to spend more money on a different player, rather than less money on the wrong player. We need to make these strategic moves available through the UI. To make up for the explosion in combinations, we just have to get rid of the options that result in the same money for each neighbour. As long as we give the same amounts, we don't care whether it's for wood or clay. Related: https://github.com/joffrey-bion/seven-wonders/issues/50 --- .../org/luxons/sevenwonders/engine/GameTest.kt | 17 +- .../sevenwonders/engine/cards/RequirementsTest.kt | 4 +- .../engine/resources/BestPriceCalculatorTest.kt | 175 ------------------ .../resources/TransactionOptionsCalculatorTest.kt | 201 +++++++++++++++++++++ 4 files changed, 207 insertions(+), 190 deletions(-) delete mode 100644 sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/resources/BestPriceCalculatorTest.kt create mode 100644 sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/resources/TransactionOptionsCalculatorTest.kt (limited to 'sw-engine/src/test/kotlin') diff --git a/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/GameTest.kt b/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/GameTest.kt index 783d3eab..62267c7a 100644 --- a/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/GameTest.kt +++ b/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/GameTest.kt @@ -4,23 +4,14 @@ import org.luxons.sevenwonders.engine.data.GameDefinition import org.luxons.sevenwonders.engine.data.LAST_AGE import org.luxons.sevenwonders.engine.test.SEED import org.luxons.sevenwonders.engine.test.testSettings -import org.luxons.sevenwonders.model.Action -import org.luxons.sevenwonders.model.MoveType -import org.luxons.sevenwonders.model.PlayedMove -import org.luxons.sevenwonders.model.PlayerMove -import org.luxons.sevenwonders.model.PlayerTurnInfo +import org.luxons.sevenwonders.model.* import org.luxons.sevenwonders.model.cards.HandCard import org.luxons.sevenwonders.model.cards.TableCard import org.luxons.sevenwonders.model.resources.ResourceTransactions import org.luxons.sevenwonders.model.resources.noTransactions import org.luxons.sevenwonders.model.wonders.deal import kotlin.random.Random -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertFalse -import kotlin.test.assertNotNull -import kotlin.test.assertTrue -import kotlin.test.fail +import kotlin.test.* class GameTest { @@ -91,12 +82,12 @@ class GameTest { private fun createPlayCardMove(turnInfo: PlayerTurnInfo): MoveExpectation { val wonderBuildability = turnInfo.wonderBuildability if (wonderBuildability.isBuildable) { - val transactions = wonderBuildability.cheapestTransactions.first() + val transactions = wonderBuildability.transactionsOptions.first() return planMove(turnInfo, MoveType.UPGRADE_WONDER, turnInfo.hand!!.first(), transactions) } val playableCard = turnInfo.hand!!.firstOrNull { it.playability.isPlayable } return if (playableCard != null) { - planMove(turnInfo, MoveType.PLAY, playableCard, playableCard.playability.cheapestTransactions.first()) + planMove(turnInfo, MoveType.PLAY, playableCard, playableCard.playability.transactionOptions.first()) } else { planMove(turnInfo, MoveType.DISCARD, turnInfo.hand!!.first(), noTransactions()) } 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 d3fdc94c..36dc8ed1 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 @@ -117,11 +117,11 @@ class RequirementsTest { val satisfaction = requirements.assess(player) if (neighbourHasResource) { - val transactions = setOf( + val transactionOptions = listOf( createPricedTransactions(Provider.LEFT_PLAYER, 2, requiredResource), createPricedTransactions(Provider.RIGHT_PLAYER, 2, requiredResource), ) - assertEquals(RequirementsSatisfaction.metWithHelp(2, transactions), satisfaction) + assertEquals(RequirementsSatisfaction.metWithHelp(2, transactionOptions), satisfaction) } else { assertEquals(RequirementsSatisfaction.unavailableResources(), satisfaction) } 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 deleted file mode 100644 index 1a56caf4..00000000 --- a/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/resources/BestPriceCalculatorTest.kt +++ /dev/null @@ -1,175 +0,0 @@ -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.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.ResourceType.* -import org.luxons.sevenwonders.model.resources.noTransactions -import kotlin.test.assertEquals - -class BestPriceCalculatorTest { - - private fun solutions(price: Int, vararg resourceTransactions: PricedResourceTransactions) = - TransactionPlan(price, setOf(*resourceTransactions)) - - @Test - fun bestPrice_0forEmptyResources() { - val table = testTable(3) - val player0 = SimplePlayer(0, table) - val emptyResources = emptyResources() - val emptyTransactions = noTransactions() - assertEquals(solutions(0, emptyTransactions), bestSolution(emptyResources, player0)) - } - - @Test - fun bestPrice_fixedResources_defaultCost() { - val left = testBoard(STONE) - val main = testBoard(STONE) - val right = testBoard(WOOD) - val table = Table(listOf(main, right, left)) - - val player0 = SimplePlayer(0, table) - val player1 = SimplePlayer(1, table) - val player2 = SimplePlayer(2, table) - - val resources = resourcesOf(STONE, STONE) - - val stoneLeftSingle = createPricedTransaction(LEFT_PLAYER, 2, STONE) - val stoneRightSingle = createPricedTransaction(RIGHT_PLAYER, 2, STONE) - - 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)) - assertEquals(solutions(2, stoneRight), bestSolution(resources, player2)) - } - - @Test - fun bestPrice_fixedResources_overridenCost() { - val main = testBoard(STONE) - main.tradingRules.setCost(WOOD, RIGHT_PLAYER, 1) - - val left = testBoard(WOOD) - val right = testBoard(WOOD) - val opposite = testBoard(GLASS) - val table = Table(listOf(main, right, opposite, left)) - - val player0 = SimplePlayer(0, table) - val player1 = SimplePlayer(1, table) - val player2 = SimplePlayer(2, table) - val player3 = SimplePlayer(3, table) - - val resources = resourcesOf(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, 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)) - } - - @Test - fun bestPrice_mixedResources_overridenCost() { - val left = testBoard(WOOD) - - val main = testBoard(STONE) - main.tradingRules.setCost(WOOD, RIGHT_PLAYER, 1) - - val right = testBoard(ORE) - right.production.addChoice(WOOD, CLAY) - right.publicProduction.addChoice(WOOD, CLAY) - - val table = Table(listOf(main, right, left)) - - val player0 = SimplePlayer(0, table) - val player1 = SimplePlayer(1, table) - val player2 = SimplePlayer(2, table) - - val resources = resourcesOf(WOOD) - val woodRightDiscounted = createPricedTransactions(RIGHT_PLAYER, 1, WOOD) - - assertEquals(solutions(1, woodRightDiscounted), bestSolution(resources, player0)) - assertEquals(solutions(0, noTransactions()), bestSolution(resources, player1)) - assertEquals(solutions(0, noTransactions()), bestSolution(resources, player2)) - } - - @Test - fun bestPrice_mixedResources_overridenCost_sameMultipleTimes() { - val left = testBoard(WOOD) - - val main = testBoard(WOOD) - main.tradingRules.setCost(CLAY, LEFT_PLAYER, 1) - main.tradingRules.setCost(CLAY, RIGHT_PLAYER, 1) - - main.publicProduction.addFixedResource(STONE, 1) - main.publicProduction.addChoice(CLAY, ORE) - main.production.addFixedResource(STONE, 1) - main.production.addChoice(CLAY, ORE) - - val right = testBoard(CLAY) - right.publicProduction.addFixedResource(ORE, 1) - right.publicProduction.addFixedResource(CLAY, 1) - right.publicProduction.addFixedResource(WOOD, 2) - right.production.addFixedResource(ORE, 1) - right.production.addFixedResource(CLAY, 1) - right.production.addFixedResource(WOOD, 2) - - val table = Table(listOf(main, right, left)) - - val player0 = SimplePlayer(0, table) - val player1 = SimplePlayer(1, table) - val player2 = SimplePlayer(2, table) - - val resources = resourcesOf(WOOD, CLAY, CLAY, 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, createPricedTransactions(claysRightDiscounted)), bestSolution(resources, player0)) - assertEquals(solutions(2, createPricedTransactions(clayLeft)), bestSolution(resources, player1)) - assertEquals(solutions(6, createPricedTransactions(claysLeft, clayRight)), bestSolution(resources, player2)) - } - - @Test - fun bestPrice_chooseCheapest() { - val left = testBoard(WOOD) - - val main = testBoard(WOOD) - main.production.addChoice(CLAY, ORE) - main.tradingRules.setCost(CLAY, RIGHT_PLAYER, 1) - - val right = testBoard(WOOD) - right.production.addFixedResource(ORE, 1) - right.production.addFixedResource(CLAY, 1) - right.publicProduction.addFixedResource(ORE, 1) - right.publicProduction.addFixedResource(CLAY, 1) - - val table = Table(listOf(main, right, left)) - - val player0 = SimplePlayer(0, table) - val player1 = SimplePlayer(1, table) - val player2 = SimplePlayer(2, table) - - val resources = resourcesOf(ORE, CLAY) - val oreAndClayLeft = createPricedTransactions(LEFT_PLAYER, 4, ORE, CLAY) - val clayRightDiscounted = createPricedTransactions(RIGHT_PLAYER, 1, CLAY) - - 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/TransactionOptionsCalculatorTest.kt b/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/resources/TransactionOptionsCalculatorTest.kt new file mode 100644 index 00000000..da4b608e --- /dev/null +++ b/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/resources/TransactionOptionsCalculatorTest.kt @@ -0,0 +1,201 @@ +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.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.Provider.LEFT_PLAYER +import org.luxons.sevenwonders.model.resources.Provider.RIGHT_PLAYER +import org.luxons.sevenwonders.model.resources.ResourceType.* +import org.luxons.sevenwonders.model.resources.noTransactions +import org.luxons.sevenwonders.model.resources.singleOptionNoTransactionNeeded +import kotlin.test.assertEquals + +class TransactionOptionsCalculatorTest { + + @Test + fun transactionOptions_noResourcesRequired_nothingToBuy() { + val table = testTable(3) + val player0 = SimplePlayer(0, table) + val emptyResources = emptyResources() + assertEquals(singleOptionNoTransactionNeeded(), transactionOptions(emptyResources, player0)) + } + + @Test + fun transactionOptions_initialResources_defaultCost() { + val board2 = testBoard(STONE) + val board0 = testBoard(STONE) + val board1 = testBoard(WOOD) + val table = Table(listOf(board0, board1, board2)) + + val player0 = SimplePlayer(0, table) + val player1 = SimplePlayer(1, table) + val player2 = SimplePlayer(2, table) + + val resources = resourcesOf(STONE, STONE) + + val stoneLeftSingle = createPricedTransaction(LEFT_PLAYER, 2, STONE) + val stoneRightSingle = createPricedTransaction(RIGHT_PLAYER, 2, STONE) + + val stoneLeft = createPricedTransactions(stoneLeftSingle) + val stoneRight = createPricedTransactions(stoneRightSingle) + val stoneLeftAndRight = createPricedTransactions(stoneLeftSingle, stoneRightSingle) + + assertEquals(listOf(stoneLeft), transactionOptions(resources, player0)) + assertEquals(listOf(stoneLeftAndRight), transactionOptions(resources, player1)) + assertEquals(listOf(stoneRight), transactionOptions(resources, player2)) + } + + @Test + fun transactionOptions_fixedResources_defaultCost() { + val board2 = testBoard(WOOD) + + val board0 = testBoard(STONE) + board0.publicProduction.addFixedResource(CLAY, 1) + board0.production.addFixedResource(CLAY, 1) + + val board1 = testBoard(ORE) + + val table = Table(listOf(board0, board1, board2)) + + val player0 = SimplePlayer(0, table) + val player1 = SimplePlayer(1, table) + val player2 = SimplePlayer(2, table) + + val resources = resourcesOf(STONE, CLAY) + + val stoneAndClayLeft = createPricedTransaction(LEFT_PLAYER, 4, STONE, CLAY) + val stoneAndClayRight = createPricedTransaction(RIGHT_PLAYER, 4, STONE, CLAY) + + assertEquals(singleOptionNoTransactionNeeded(), transactionOptions(resources, player0)) + assertEquals(listOf(createPricedTransactions(stoneAndClayLeft)), transactionOptions(resources, player1)) + assertEquals(listOf(createPricedTransactions(stoneAndClayRight)), transactionOptions(resources, player2)) + } + + @Test + fun transactionOptions_fixedResources_overridenCost() { + val board0 = testBoard(STONE) + board0.tradingRules.setCost(WOOD, RIGHT_PLAYER, 1) + + val board1 = testBoard(WOOD) + val board2 = testBoard(GLASS) + val board3 = testBoard(WOOD) + + val table = Table(listOf(board0, board1, board2, board3)) + + val player0 = SimplePlayer(0, table) + val player1 = SimplePlayer(1, table) + val player2 = SimplePlayer(2, table) + val player3 = SimplePlayer(3, table) + + val resources = resourcesOf(WOOD) + + val woodLeft = createPricedTransactions(LEFT_PLAYER, 2, WOOD) + val woodRightDiscounted = createPricedTransactions(RIGHT_PLAYER, 1, WOOD) + val woodRight = createPricedTransactions(RIGHT_PLAYER, 2, WOOD) + + assertEquals(listOf(woodRightDiscounted, woodLeft), transactionOptions(resources, player0)) + assertEquals(listOf(noTransactions()), transactionOptions(resources, player1)) + assertEquals(listOf(woodLeft, woodRight), transactionOptions(resources, player2)) + assertEquals(listOf(noTransactions()), transactionOptions(resources, player3)) + } + + @Test + fun transactionOptions_mixedResources_overridenCost() { + val board0 = testBoard(STONE) + board0.tradingRules.setCost(WOOD, RIGHT_PLAYER, 1) + + val board1 = testBoard(ORE) + board1.production.addChoice(WOOD, CLAY) + board1.publicProduction.addChoice(WOOD, CLAY) + + val board2 = testBoard(WOOD) + + val table = Table(listOf(board0, board1, board2)) + + val player0 = SimplePlayer(0, table) + val player1 = SimplePlayer(1, table) + val player2 = SimplePlayer(2, table) + + val resources = resourcesOf(WOOD) + + val woodRightDiscounted = createPricedTransactions(RIGHT_PLAYER, 1, WOOD) + val woodLeft = createPricedTransactions(LEFT_PLAYER, 2, WOOD) + + assertEquals(listOf(woodRightDiscounted, woodLeft), transactionOptions(resources, player0)) + assertEquals(listOf(noTransactions()), transactionOptions(resources, player1)) + assertEquals(listOf(noTransactions()), transactionOptions(resources, player2)) + } + + @Test + fun transactionOptions_mixedResources_overridenCost_sameMultipleTimes() { + val board0 = testBoard(WOOD) + board0.tradingRules.setCost(CLAY, LEFT_PLAYER, 1) + board0.tradingRules.setCost(CLAY, RIGHT_PLAYER, 1) + + board0.publicProduction.addFixedResource(STONE, 1) + board0.publicProduction.addChoice(CLAY, ORE) + board0.production.addFixedResource(STONE, 1) + board0.production.addChoice(CLAY, ORE) + + val board1 = testBoard(CLAY) + board1.publicProduction.addFixedResource(ORE, 1) + board1.publicProduction.addFixedResource(CLAY, 1) + board1.publicProduction.addFixedResource(WOOD, 2) + board1.production.addFixedResource(ORE, 1) + board1.production.addFixedResource(CLAY, 1) + board1.production.addFixedResource(WOOD, 2) + + val board2 = testBoard(WOOD) + + val table = Table(listOf(board0, board1, board2)) + + val player0 = SimplePlayer(0, table) + val player1 = SimplePlayer(1, table) + val player2 = SimplePlayer(2, table) + + val resources = resourcesOf(WOOD, CLAY, CLAY, 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(listOf(createPricedTransactions(claysRightDiscounted)), transactionOptions(resources, player0)) + assertEquals(listOf(createPricedTransactions(clayLeft)), transactionOptions(resources, player1)) + assertEquals(listOf(createPricedTransactions(claysLeft, clayRight)), transactionOptions(resources, player2)) + } + + @Test + fun transactionOptions_cheapestFirst() { + val board0 = testBoard(WOOD) + board0.production.addChoice(CLAY, ORE) + board0.tradingRules.setCost(CLAY, RIGHT_PLAYER, 1) + + val board1 = testBoard(WOOD) + board1.production.addFixedResource(ORE, 1) + board1.production.addFixedResource(CLAY, 1) + board1.publicProduction.addFixedResource(ORE, 1) + board1.publicProduction.addFixedResource(CLAY, 1) + + val board2 = testBoard(WOOD) + + val table = Table(listOf(board0, board1, board2)) + + val player0 = SimplePlayer(0, table) + val player1 = SimplePlayer(1, table) + val player2 = SimplePlayer(2, table) + + val resources = resourcesOf(ORE, CLAY) + + val clayRightDiscounted = createPricedTransactions(RIGHT_PLAYER, 1, CLAY) + val oreAndClayLeft = createPricedTransactions(LEFT_PLAYER, 4, ORE, CLAY) + + assertEquals(listOf(clayRightDiscounted), transactionOptions(resources, player0)) + assertEquals(listOf(noTransactions()), transactionOptions(resources, player1)) + assertEquals(listOf(oreAndClayLeft), transactionOptions(resources, player2)) + } +} -- cgit