Skip to content

Instantly share code, notes, and snippets.

@barbazul
Last active November 26, 2018 04:41
Show Gist options
  • Save barbazul/a6461eceeecae00679eb77444c50bcc9 to your computer and use it in GitHub Desktop.
Save barbazul/a6461eceeecae00679eb77444c50bcc9 to your computer and use it in GitHub Desktop.
Adapted Androminion Chuck AI for Dominiate simulator
# This is a port of the Chuck AI from Androminion for the Dominiate simulator
# Original https://github.com/mehtank/androminion/blob/master/vdom/src/com/vdom/players/VDomPlayerChuck.java
# Simulator http://rspeer.github.io/dominiate/play.html
#
# Chuck really likes to buy potion cards
# If potion cards are unavailable, he mostly buys random treasures and action
# favoring expensive cards over cheap ones.
# Starts greening when he can afford a Province or Colony or after turn 12
# If there are no potion-cost actions it will at most buy 5 random actions but
# it will never buy Vineyard with less than 5 actions in deck, so sometimes it
# will buy Potion and never use it. ¯\_(ツ)_/¯
# Play priority is Treasure Map above all (?) then cantrips and villages and
# then terminals (throning them if available)
#
# Commented out some pseudocode with ignored logic due to cards not implemented
# in Dominiate
{
name: 'Chuck',
author: 'dominionator, mehtank, tkdennis, schoeggu and androminionfan (taken from Github contributos)'
requires: [],
playPriority: (state, my) ->
COST_MAX = 14
priority = [
"Treasure Map" if my.countInHand("Treasure Map") >= 2
]
# play prince if action card candidate available. (skipped Prince is not implemented)
# princeCards = this.princeCardCandidates(state, my)
# But if a non candidate action cantrip or village is available prefer it instead
for card in my.hand
if card.actions > 0 # && princeCards.indexOf(card) < 0
priority.push(card.name)
# Prince is not implemented in Dominate
# priority.push("Prince") if princeCards.length > 0
priority.push("Throne Room")
# Disciple is not implemented in Dominiate
# priority.push("Disciple")
priority.push("King's Court")
cost = COST_MAX
while cost >= 0
randList = []
for card in my.hand
continue if card.name == "Treasure Map" ||
card.name == "Tactician" && my.countInPlay("Tactician") > 0
if card.costInCoins(state) == cost
randList.push(card)
randList = this.shuffle(randList)
for r in randList
if r?
priority.push(r.name);
cost--
priority.push(null)
priority
gainPriority: (state, my) ->
midGame = 12
actionCardsMax = 5
priority = [
null if my.coins == 0
"Colony"
"Platinum" if my.turnsTaken < midGame
# Prince is not implemented in Dominiate
#"Prince" if my.turnsTaken < midGame &&
# state.countInSupply("Colony") > 0 &&
# my.countInDeck("Prince") < 2 &&
# princeCandidatesCount > 2 * my.countInDeck("Prince")
"Province"
"Vineyard" if my.turnsTaken > midGame &&
my.numActionCardsInDeck() >= 9
# && will not gain curse due to embargo
"Duchy" if my.turnsTaken > midGame
# && will not gain curse due to embargo
# try cards with potion before silver
"Vineyard" if my.turnsTaken > midGame &&
my.numActionCardsInDeck() >= 6
# && will not gain curse due to embargo
"Posession" if my.countInDeck("Posession") < 2 &&
my.coins < state.cardInfo["Vineyard"].costInCoins(state) + 3
"Golem" if my.countInDeck("Golem") < 2 &&
my.coins < state.cardInfo["Golem"].costInCoins(state) + 3
"Familiar" if my.countInDeck("Familiar") < 2 &&
my.coins < state.cardInfo["Familiar"].costInCoins(state) + 3 &&
my.turnsTaken <= midGame && state.countInSupply("Curse") > 3
"Alchemist" if my.coins < state.cardInfo["Alchemist"].costInCoins(state) + 3
"Philosopher's Stone" if my.coins < state.cardInfo["Philosopher's Stone"].costInCoins(state) + 3
"Scrying Pool" if my.coins < state.cardInfo["Scrying Pool"].costInCoins(state) + 3
"Apothecary" if my.countInDeck("Apothecary") < 2 &&
my.coins < state.cardInfo["Apothecary"].costInCoins(state) + 3
"University" if my.countInDeck("University") < 2 &&
my.coins < state.cardInfo["University"].costInCoins(state) + 3
]
if Math.random() < 0.25
priority.push("Gold") # if will not gain curse due to embargo
priority.push("Silver") # if will not gain curse due to embargo
# Random cards amognst the most expensive available
randList = []
cost = my.coins
highestCost = 0
while cost >= 0
for c, count of state.supply
card = state.cardInfo[c]
multiplierCount = my.countInDeck("Throne Room") + my.countInDeck("King's Court")
# Should also skip ruins and consider disciple and crown in mutipliers calculation
# Those cards are not implemented in Dominiate
continue if card.costInCoins(state) != cost ||
c == "Curse" ||
c == "Copper" ||
c == "Rats" ||
c == "Potion" && !this.shouldBuyPotion(my) ||
c == "Throne Room" && multiplierCount > 2 ||
c == "King's Court" && multiplierCount > 2 ||
!card.isAction && !card.isTreasure
continue if card.isAction && my.numActionCardsInDeck() >= actionCardsMax
# continue if will gain curse due to Embargo
highestCost = card.costInCoins(state) if highestCost == 0
randList.push(c)
break if --cost < highestCost - 2
# prefer silver instead of masterpiece if you can't overpay by 2
masterpiecePos = randList.indexOf("Masterpiece")
if randList.indexOf("Silver") > -1 && masterpiecePos > -1 && my.coins < 5
randList[masterpiecePos] = undefined
randList = this.shuffle(randList)
for r in randList
if r?
priority.push(r)
priority.push("Gold")
priority.push("Silver") # if will not gain curse due to Embargo
if my.turnsTaken > midGame # && will not gain curse due to Embargo
priority.push("Estate")
priority.push(null)
priority
trashPriority: (state, my) ->
[
"Curse"
"Overgrown Estate"
"Ruined Village"
"Ruined Market"
"Survivors"
"Ruined Library"
"Abandoned Mine"
# Any other Ruins. Ruins are not implemented in Dominiate
"Hovel"
"Estate"
"Copper"
"Masterpiece"
]
shuffle: (v) ->
i = v.length
while i
j = parseInt(Math.random() * i)
i -= 1
temp = v[i]
v[i] = v[j]
v[j] = temp
v
shouldBuyPotion: (my) ->
return false if my.countInDeck("Potion") > 2
return false if my.countInDeck("Potion") > 1 && Math.random() > 0.16
return false if my.countInDeck("Potion") > 0 && Math.random() > 0.25
true
}
@barbazul
Copy link
Author

Easy optimization: Instead of iterating hand each choice for generating randList, precalculate from kingdom only once and simply shuffle each time.
Dominiate will ignore unavailable choices

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment