Blueblimp's idea in action (finding a good time to buy/gain Scouts wasn't easy, but they clearly make the bot better!):
<player name="Ironworks/Great Hall with Scouts"
author="Geronimoo"
description="No description available">
<type name="Optimized"/>
<type name="BigMoney"/>
<type name="Province"/>
<type name="TwoPlayer"/>
<type name="Bot"/>
<type name="UserCreated"/>
<type name="SingleCard"/>
<buy name="Province">
<condition>
<left type="countCardsInDeck" attribute="Harem"/>
<operator type="greaterThan" />
<right type="constant" attribute="0.0"/>
</condition>
</buy>
<buy name="Duchy">
<condition>
<left type="gainsNeededToEndGame"/>
<operator type="smallerOrEqualThan" />
<right type="constant" attribute="5.0"/>
</condition>
</buy>
<buy name="Estate">
<condition>
<left type="gainsNeededToEndGame"/>
<operator type="smallerOrEqualThan" />
<right type="constant" attribute="2.0"/>
</condition>
</buy>
<buy name="Harem"/>
<buy name="Scout">
<condition>
<left type="countCardTypeInDeck" attribute="Victory"/>
<operator type="greaterThan" />
<right type="countAllCardsInDeck"/>
<extra_operation type="divideBy" attribute="3.0" />
</condition>
<condition>
<left type="countCardsInDeck" attribute="Scout"/>
<operator type="smallerThan" />
<right type="constant" attribute="2.0"/>
</condition>
</buy>
<buy name="Ironworks">
<condition>
<left type="countCardsInDeck" attribute="Ironworks"/>
<operator type="smallerThan" />
<right type="constant" attribute="2.0"/>
</condition>
</buy>
<buy name="Chapel" strategy="aggressiveTrashing">
<condition>
<left type="countCardsInDeck" attribute="Chapel"/>
<operator type="equalTo" />
<right type="constant" attribute="0.0"/>
</condition>
</buy>
<buy name="Silver">
<condition>
<left type="countCardsInDeck" attribute="Harem"/>
<operator type="equalTo" />
<right type="constant" attribute="0.0"/>
</condition>
</buy>
<buy name="Great_Hall"/>
<buy name="Silver"/>
</player>
Thanks! I've got this working in Dominate now also, although I haven't implemented intelligent Scout/cantrip interleaving, which should make it better. (The idea is that if you know the top card of your deck is not a victory card, you should draw it with a cantrip such as GH or Ironworks-gaining-GH, whereas if you don't know what it is, then you should play Scout because then maybe you draw it for free.)
I don't know what's the best non-Scout baseline to compare this to. I tried vs Colony BMU and also against the same script minus Scout-buying (which is certainly not the best non-Scout strategy in this kingdom).
Against Colony BMU: terminated at 80.8/19.2 after 26 games
Against same minus Scout-buying: terminated at 70.5/29.5 after 56 games
# Make Scout useful.
# Non-resiliant version (i.e. tries to get all GH's and more than half of Harems).
# Right now, does NOT order Scout/cantrip plays optimally.
{
name: 'UsefulScout'
requires: ['Chapel', 'Scout', 'Ironworks', 'Great Hall', 'Harem', 'Colony']
gainPriority: (state, my) -> [
# Open Ironworks/Chapel.
"Ironworks" if my.countInDeck("Ironworks") == 0 and my.turnsTaken <= 2
"Chapel" if my.countInDeck("Chapel") == 0 and my.turnsTaken <= 2
# Gain Great Halls with Ironworks, but don't buy them.
# Once we run out of Great Halls, use Ironworks for Scouts.
"Great Hall" if state.phase isnt "buy"
"Scout" if state.phase isnt "buy"
# Colonies are always good, since Scout keeps our deck running.
"Colony"
# Lots of Harems are good.
"Harem"
# Consolation prizes if Harems are gone.
"Platinum" if my.countInDeck("Platinum") == 0
"Province"
# Early on, we need to bootstrap to Harems via Silver.
# We don't want too many of these though.
"Silver" if my.countInDeck("Silver") < 2
"Scout"
"Silver" if my.countInDeck("Silver") < 3
]
# I checked and the simulator does use this list (e.g. it will trash
# silver if asked).
trashPriority: (state, my) -> [
"Estate"
# Need enough copper to buy a silver.
"Copper" if my.countInDeck("Copper") > 3
# Once we have a silver/harem, keep enough coppers to buy more silvers (and harems if we have $4
# from silvers+harems).
"Copper" if my.countInDeck("Silver") + my.countInDeck("Harem") >= 1\
and my.countInDeck("Copper") > 2
# Once we have 3 silvers/harems, trash all coppers.
"Copper" if my.countInDeck("Silver") + my.countInDeck("Harem") >= 3
# Trash silvers if it keeps total deck $ at least 6 and doesn't hurt buying Harem.
"Silver" if my.getTotalMoney() >= 8\
and (my.getTreasureInHand() >= 8 or my.getTreasureInHand() < 6)
# Get rid of the Ironworks if we have all GH's and enough Scouts.
"Ironworks" if state.countInSupply("Great Hall") == 0\
and my.countInDeck("Scout") >= 4
]
# Block all trashing we don't authorize. This works around the simulator's
# desire to always trash coppers.
trashValue: (state, card, my) ->
-1
actionPriority: (state, my) -> [
# The default plays Chapel _before_ Ironworks, which completely ruins us.
"Great Hall"
"Ironworks"
"Scout"
"Chapel"
]
}
The version that doesn't buy a Scout:
# The useful Scout bot, minus the Scout.
{
name: 'UsefulScoutMinusScout'
requires: ['Chapel', 'Scout', 'Ironworks', 'Great Hall', 'Harem', 'Colony']
gainPriority: (state, my) -> [
# Open Ironworks/Chapel.
"Ironworks" if my.countInDeck("Ironworks") == 0 and my.turnsTaken <= 2
"Chapel" if my.countInDeck("Chapel") == 0 and my.turnsTaken <= 2
# Gain Great Halls with Ironworks, but don't buy them.
# Once we run out of Great Halls, use Ironworks for Scouts.
"Great Hall" if state.phase isnt "buy"
# Colonies are always good, since Scout keeps our deck running.
"Colony"
# Lots of Harems are good.
"Harem"
# Consolation prizes if Harems are gone.
"Platinum" if my.countInDeck("Platinum") == 0
"Province"
"Platinum"
"Gold"
# Early on, we need to bootstrap to Harems via Silver.
# We don't want too many of these though.
"Silver" if my.countInDeck("Silver") < 2
"Silver" if my.countInDeck("Silver") < 3
]
# I checked and the simulator does use this list (e.g. it will trash
# silver if asked).
trashPriority: (state, my) -> [
"Estate"
# Need enough copper to buy a silver.
"Copper" if my.countInDeck("Copper") > 3
# Once we have a silver/harem, keep enough coppers to buy more silvers (and harems if we have $4
# from silvers+harems).
"Copper" if my.countInDeck("Silver") + my.countInDeck("Harem") >= 1\
and my.countInDeck("Copper") > 2
# Once we have 3 silvers/harems, trash all coppers.
"Copper" if my.countInDeck("Silver") + my.countInDeck("Harem") >= 3
# Trash silvers if it keeps total deck $ at least 6 and doesn't hurt buying Harem.
"Silver" if my.getTotalMoney() >= 8\
and (my.getTreasureInHand() >= 8 or my.getTreasureInHand() < 6)
# Get rid of the Ironworks if we have all GH's and enough Scouts.
"Ironworks" if state.countInSupply("Great Hall") == 0\
and my.countInDeck("Scout") >= 4
]
# Block all trashing we don't authorize. This works around the simulator's
# desire to always trash coppers.
trashValue: (state, card, my) ->
-1
actionPriority: (state, my) -> [
# The default plays Chapel _before_ Ironworks, which completely ruins us.
"Great Hall"
"Ironworks"
"Scout"
"Chapel"
]
}
Edit: As it's written now, it loses against a simple Ironworks/Chapel opening transitioning into standard Colony BMU. Terminated at 37.7/62.3 after 150 games. I don't know whether this means Ironworks/Chapel is better or it just means that Colony BMU is nicely optimized.
# Use Chapel to clear Coppers and Estates, using an
# Ironworks to gain Silvers and transition into Colony BMU.
{
name: 'Ironworks/Chapel'
author: 'blueblimp'
requires: ['Ironworks', 'Chapel']
gainPriority: (state, my) -> [
"Colony" if my.getTotalMoney() > 32
"Province" if state.gainsToEndGame() <= 6
"Duchy" if state.gainsToEndGame() <= 5
"Estate" if state.gainsToEndGame() <= 2
"Platinum"
"Province" if state.countInSupply("Colony") <= 7
"Gold"
"Duchy" if state.gainsToEndGame() <= 6
"Ironworks" if my.countInDeck("Ironworks") == 0
"Chapel" if my.countInDeck("Chapel") == 0
"Silver"
"Copper" if state.gainsToEndGame() <= 2
]
}
Against Geronimoo's formulation in his simulator, Ironworks/Chapel also wins, but only with aggressive trashing. 29/69 on quick. Never mind, I didn't notice his bot is Province and not Colony. With Provinces, it beats a simple Ironworks/Chapel 76/21 on quick. 79/20 against the optimized Harem strategy too, which is something I'd be worried about in a Province game.
<player name="Ironworks/Chapel"
author="blueblimp"
description="Open Ironworks/Chapel and transition into standard BMU.">
<type name="BigMoney"/>
<type name="SingleCard"/>
<type name="Optimized"/>
<type name="Bot"/>
<type name="UserCreated"/>
<type name="Province"/>
<type name="TwoPlayer"/>
<buy name="Province">
<condition>
<left type="getTotalMoney"/>
<operator type="greaterThan" />
<right type="constant" attribute="18.0"/>
</condition>
</buy>
<buy name="Duchy">
<condition>
<left type="countCardsInSupply" attribute="Province"/>
<operator type="smallerOrEqualThan" />
<right type="constant" attribute="4.0"/>
</condition>
</buy>
<buy name="Estate">
<condition>
<left type="countCardsInSupply" attribute="Province"/>
<operator type="smallerOrEqualThan" />
<right type="constant" attribute="2.0"/>
</condition>
</buy>
<buy name="Gold"/>
<buy name="Duchy">
<condition>
<left type="countCardsInSupply" attribute="Province"/>
<operator type="smallerOrEqualThan" />
<right type="constant" attribute="6.0"/>
</condition>
</buy>
<buy name="Ironworks">
<condition>
<left type="countCardsInDeck" attribute="Ironworks"/>
<operator type="equalTo" />
<right type="constant" attribute="0.0"/>
</condition>
</buy>
<buy name="Chapel" strategy="aggressiveTrashing">
<condition>
<left type="countCardsInDeck" attribute="Chapel"/>
<operator type="equalTo" />
<right type="constant" attribute="0.0"/>
</condition>
</buy>
<buy name="Silver"/>
</player>