Created
November 26, 2018 04:33
-
-
Save barbazul/3a643ac85795715afe3c1bbd231e3ba8 to your computer and use it in GitHub Desktop.
Adapted Androminion Sarah AI for Dominiate simulator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This is a port of the Sarah AI from Androminion for the Dominiate simulator | |
# Original https://github.com/mehtank/androminion/blob/master/vdom/src/com/vdom/players/VDomPlayerSarah.java | |
# Simulator http://rspeer.github.io/dominiate/play.html | |
# | |
# Sarah has several scripted behaviors for preconstructed kingdoms which are | |
# ignored in this implementation. | |
# So what is left is basically the same as Chuck but likes to buy Grand Market | |
# There is a bias that I left out by which it tends to buy less basic treasures | |
# if there are 5 or more cards from Cornucopia expansion | |
# | |
# Commented out some pseudocode with ignored logic due to cards not implemented | |
# in Dominiate | |
{ | |
name: 'Sarah', | |
author: 'dominionator, schoeggu, mehtank, tkdennis and androminionfan (taken from Github contributos)' | |
requires: [], | |
trashPriority: (state, my) -> | |
# trash in this order! | |
[ | |
"Curse" | |
"Rats" | |
"Overgrown Estate" | |
"Ruined Village" | |
"Ruined Market" | |
"Survivors" | |
"Ruined Library" | |
"Abandoned Mine" | |
# Any other Ruins. Ruins are not implemented in Dominiate | |
"Hovel" | |
"Estate" | |
"Copper" | |
"Masterpiece" | |
] | |
gainPriority: (state, my) -> | |
midGame = 12 | |
randomGreen = Math.random() | |
MAX_OF_ONE_ACTION_CARD = 4 | |
silverMax = 4 | |
silverLine = 0.5 | |
actionCardMax = 5 | |
multiplierCount = my.countInDeck("Throne Room") + my.countInDeck("King's Court") | |
maxMultipliers = 2 | |
priority = [ | |
"Colony" | |
"Platinum" if my.coins >= 9 && my.turnsTaken < midGame | |
# Prince is not implemented in Dominiate | |
#"Prince" if my.turnsTaken < midGame && state.countInSupply("Colony") > 0 | |
# && my.countInDeck("Prince") < 2 | |
# && princeCandidates.length >= 2 + 2 * my.countInDeck("Prince") | |
"Province" | |
"Vineyard" if my.turnsTaken > midGame && | |
my.coins <= 7 && | |
randomGreen < 0.25 && | |
my.numActionCardsInDeck() >= 9 | |
# && will not gain curse due to embargo | |
"Duchy" if my.turnsTaken > midGame && | |
my.coins <= 7 && | |
randomGreen < 0.25 | |
# && will not gain curse due to embargo | |
"Vineyard" if my.turnsTaken > midGame && | |
my.coins <= 7 && | |
randomGreen < 0.25 && | |
my.numActionCardsInDeck() >= 6 | |
# && will not gain curse due to embargo | |
"Possession" if my.countInDeck("Possession") < 2 | |
"Grand Market" if Math.random() * MAX_OF_ONE_ACTION_CARD * 2 < my.countInDeck("Grand Market") | |
# try cards with potion before silver | |
# Yes, Possession has already been skipped at this point ¯\_(ツ)_/¯ | |
# And Possession is not implemented anyway | |
#"Possession" if my.countInDeck("Possession") < 2 && | |
# my.coins < state.cardInfo["Possession"].costInCoins(state) + 3 && | |
# my.turnsTaken <= midGame | |
# # && will not gain curse due to Embargo | |
"Golem" if my.countInDeck("Golem") < 2 && | |
my.coins < state.cardInfo["Golem"].costInCoins(state) + 3 && | |
my.turnsTaken <= midGame | |
# && will not gain curse due to Embargo | |
"Familiar" if my.countInDeck("Familiar") < 2 && | |
my.coins < state.cardInfo["Familiar"].costInCoins(state) + 3 && | |
my.turnsTaken <= midGame && | |
state.countInSupply("Curse") > 3 | |
# && will not gain curse due to Embargo | |
"Alchemist" if my.coins < state.cardInfo["Alchemist"].costInCoins(state) + 3 && | |
my.turnsTaken <= midGame | |
# && will not gain curse due to Embargo | |
"Philosopher's Stone" if my.coins < state.cardInfo["Philosopher's Stone"].costInCoins(state) + 3 && | |
my.turnsTaken <= midGame | |
# && will not gain curse due to Embargo | |
"Scrying Pool" if my.coins < state.cardInfo["Scrying Pool"].costInCoins(state) + 3 && | |
my.turnsTaken <= midGame | |
# && will not gain curse due to Embargo | |
"Apothecary" if my.countInDeck("Apothecary") < 2 && | |
my.coins < state.cardInfo["Apothecary"].costInCoins(state) + 3 && | |
my.turnsTaken <= midGame | |
# && will not gain curse due to Embargo | |
"University" if my.countInDeck("University") < 2 && | |
my.coins < state.cardInfo["University"].costInCoins(state) + 3 && | |
my.turnsTaken <= midGame | |
# && will not gain curse due to Embargo | |
"Silver" if my.coins <= silverMax && | |
Math.random() > silverLine | |
# && will not gain curse due to Embargo | |
"Gold" if my.coins == 6 && | |
Math.random() > silverLine | |
# && will not gain curse due to Embargo | |
] | |
cost = my.coins | |
while cost >= 0 | |
randList = [] | |
for card, quantity of state.supply | |
c = state.cardInfo[card] | |
continue if c.costInCoins(state) != cost | |
continue if c.isAction && my.numActionCardsInDeck() >= actionCardMax || | |
card == "Masterpiece" || | |
card == "Gold" || | |
card == "Platinum" || | |
card == "Curse" || | |
# Also skip ruins (which are not implemented) | |
card == "Copper" || | |
card == "Rats" || | |
card == "Potion" && !this.shouldBuyPotion(my) || | |
card == "Throne Room" && multiplierCount >= maxMultipliers || | |
card == "Disciple" && multiplierCount >= maxMultipliers || | |
card == "King's Court" && multiplierCount >= maxMultipliers || | |
# Will get Curse due to Embargo | |
!c.isAction && !c.isTreasure # && is not an Event | |
currentCount = my.countInDeck(card) | |
if c.isTreasure || | |
c.isVictory || | |
currentCount == 0 || | |
Math.random() * MAX_OF_ONE_ACTION_CARD < currentCount | |
randList.push(card) | |
randList = this.shuffle(randList) | |
# prefer silver instead of masterpiece if you can't overpay by 2 | |
masterpieceIndex = randList.indexOf("Masterpiece") | |
if masterpieceIndex > -1 && | |
randList.indexOf("Silver") > -1 && | |
my.coins < 5 | |
randList[masterpieceIndex] = undefined | |
for card in randList | |
priority.push(card) | |
cost-- | |
priority.push("Platinum") | |
priority.push("Gold") # if will not gain curse due to Embargo | |
priority.push("Silver") # if will not gain curse due to Embargo | |
priority.push(null) | |
priority | |
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 | |
playValue: (state, card, my) -> | |
# don't play rats | |
return -Infinity if card.name == "Rats" | |
null | |
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 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment