This topic was inspired by the following forum post, but this forum seems more appropriate to the discussion about simulation. Please see this topic for discussion:
http://forum.dominionstrategy.com/index.php?topic=9456.0the tl;dr is that you can beat big money over 95% of the time quite easily with the cards in that post.
It took a bit to get the simulation working, but a tuned engine handidly can beat big money over 96% of the time on a board with Rats, Watchtower, Armory, Wandering Minstrell amd Bridge. It also beats many many other strategies I have tried it against. When comparing against BigMoney, here's some interesting things I learned.
For an opening build order, my initial guess was ok, but not optimal.
- Initial guess: Armory, Silver, WanderingMinstrel, Watchtower, Rats, Watchtower: 89% win rate
- Rats, Watchtower, Watchtower, Armory: 93.5% win rate
- Rats, Watchtower, Armory, Watchtower: 95.3% win rate
- Armory, Watchtower, Rats, Watchtower: 96.7% win rate
The quickest build seems to favor getting Watchtower/Rats fairly early for maximal trashing.
I confirmed the suspicion mentioned in the other post that adding a jester actually hurts vs big money. Adding a jester brings the win rate down to 82%.
What effect does the armory have on the strategy? If you ignore the armory, your winrate goes down to 82%.
Dont want to get the rats for the trashing? Your win rate goes down to 85%
Wandering minstrell allows you to order the actions placed on top of the deck. Just placing the cards randomly results in a 83.9%. Using a relatively naive ordering, achieved the 96% win rate.
What effect does shelters have? If you play with estates instead of shelters, win rate goes down to 90%.
3 watchtowers seems to be the right number. After all, u need a wandering minstrell for every watchtower you play to keep chaining...
Furthermore, a tuned engine with these cards can beat out otherwise simple but strong contenders:
- 77.6% win vs DoubleWitch
- 72.6% win vs DoubleJack
It can go toe to toe with interesting engine combinations, for example:
- 60.4% win vs EmbassyTunnelSpiceMerchantPlaza
- 53.7% win vs FishingVillageChapelPoorHouse
- 52.3% win vs Rebuild
It can even take some games off of a deck tuned to beat big money 99.89% of the time. (though the strategies aren't tuned against each other)
- 33.8% win vs GardensBeggarIronworks
Here's the complete strategy, using the simulator I've been playing around with.
private static ICardPicker PurchaseOrder()
{
var highPriority = new CardPickByPriority(
CardAcceptance.For<CardTypes.Province>(gameState => gameState.players.CurrentPlayer.AvailableBuys >= 4 || CountAllOwned<CardTypes.Province>(gameState) > 0),
CardAcceptance.For<CardTypes.Duchy>(gameState => CountAllOwned<CardTypes.Province>(gameState) >= 3),
CardAcceptance.For<CardTypes.Estate>(gameState => CountOfPile<CardTypes.Province>(gameState) <= 1));
var buildOrder = new CardPickByBuildOrder(
new CardTypes.Armory(),
new CardTypes.Watchtower(),
new CardTypes.Rats(),
new CardTypes.Watchtower());
var lowPriority = new CardPickByPriority(
CardAcceptance.For<CardTypes.Bridge>(ShouldBuyBridge),
CardAcceptance.For<CardTypes.WanderingMinstrell>(),
CardAcceptance.For<CardTypes.Watchtower>(gameState => CountAllOwned<CardTypes.Watchtower>(gameState) < 3));
return new CardPickConcatenator(highPriority, buildOrder, lowPriority);
}
private static bool ShouldBuyBridge(GameState gameState)
{
return CountAllOwned<CardTypes.WanderingMinstrell>(gameState) > CountAllOwned<CardTypes.Bridge>(gameState) + CountAllOwned<CardTypes.Watchtower>(gameState) + 1;
}
private static bool ShouldPlayArmory(GameState gameState)
{
return CountAllOwned<CardTypes.Bridge>(gameState) < 5;
}
private static bool CanPlayTerminalWhileChaining(GameState gameState)
{
return gameState.players.CurrentPlayer.AvailableActions >= 1;
}
private static bool CanPlay2TerminalsWhileChaining(GameState gameState)
{
return gameState.players.CurrentPlayer.AvailableActions >= 2;
}
private static bool WillRatsComboWork(GameState gameState)
{
return HasCardInHand<CardTypes.Watchtower>(gameState) &&
HasCardInHand<CardTypes.Rats>(gameState) &&
HasCardFromInHand(TrashOrderWithoutRats(), gameState);
}
private static CardPickByPriority ActionOrder()
{
return new CardPickByPriority(
CardAcceptance.For<CardTypes.Armory>(gameState => CanPlay2TerminalsWhileChaining(gameState) && ShouldPlayArmory(gameState)),
CardAcceptance.For<CardTypes.Jester>(gameState => CanPlay2TerminalsWhileChaining(gameState)),
CardAcceptance.For<CardTypes.Bridge>(gameState => CanPlay2TerminalsWhileChaining(gameState)),
CardAcceptance.For<CardTypes.Watchtower>(gameState => CanPlayTerminalWhileChaining(gameState) && !WillRatsComboWork(gameState) && gameState.players.CurrentPlayer.Hand.Count() <= 5),
CardAcceptance.For<CardTypes.Rats>(gameState => WillRatsComboWork(gameState)),
CardAcceptance.For<CardTypes.WanderingMinstrell>(),
CardAcceptance.For<CardTypes.Necropolis>(),
CardAcceptance.For<CardTypes.Jester>(),
CardAcceptance.For<CardTypes.Armory>(ShouldPlayArmory),
CardAcceptance.For<CardTypes.Bridge>(),
CardAcceptance.For<CardTypes.Watchtower>());
}
// dicard order used to tune which actions to put back with wandering minstrell
private static CardPickByPriority DiscardOrder()
{
return new CardPickByPriority(
CardAcceptance.For<CardTypes.Armory>(),
CardAcceptance.For<CardTypes.Bridge>(),
CardAcceptance.For<CardTypes.Necropolis>(),
CardAcceptance.For<CardTypes.Watchtower>(),
CardAcceptance.For<CardTypes.WanderingMinstrell>(),
CardAcceptance.For<CardTypes.Rats>());
}
private static CardPickByPriority TrashOrder()
{
return new CardPickByPriority(
CardAcceptance.For<CardTypes.Rats>(gameState => CountAllOwned<CardTypes.Rats>(gameState) > 0),
CardAcceptance.For<CardTypes.Curse>(),
CardAcceptance.For<CardTypes.Estate>(),
CardAcceptance.For<CardTypes.OvergrownEstate>(),
CardAcceptance.For<CardTypes.Hovel>(),
CardAcceptance.For<CardTypes.Necropolis>(),
CardAcceptance.For<CardTypes.Copper>());
}
private static CardPickByPriority TrashOrderWithoutRats()
{
return new CardPickByPriority(
CardAcceptance.For<CardTypes.Curse>(),
CardAcceptance.For<CardTypes.Estate>(),
CardAcceptance.For<CardTypes.OvergrownEstate>(),
CardAcceptance.For<CardTypes.Hovel>(),
CardAcceptance.For<CardTypes.Necropolis>(),
CardAcceptance.For<CardTypes.Copper>()
);
}