예제 #1
0
    def actions(self, state):
        results = []
        kingdom, deck, hand, drawPile, discardPile, phase, turn, buys, actions, money, cardsPlayed = state
        if self.endOfGame(state):
            #Note: Most simulations should never get here.
            #Returns an "idle" move if the game is over, so that getQ for qLearning doesn't break.
            return ["idle"]

        if phase == "buy":
            results.append(("buy", -1))
            handValue = cardUtils.computeHandValue(hand)
            for cardID in kingdom:
                if kingdom[cardID] > 0:
                    buyCard = cardUtils.getCardFromID(cardID)
                    if buyCard.cardCost <= money:
                        results.append(("buy", buyCard.cardID))

        if phase == "action":
            results.append(("play", -1))
            for cardID in set(hand):
                card = cardUtils.getCardFromID(cardID)
                if "action" in card.cardType:
                    results.append(("play", card.cardID))

        return results
예제 #2
0
 def actions(self, state):
     results = []
     kingdom, deck, hand, drawPile, discardPile, phase, turn, buys, actions, money, cardsPlayed = state
     if self.endOfGame(state):
         #Note: Most simulations should never get here. 
         #Returns an "idle" move if the game is over, so that getQ for qLearning doesn't break.
         return ["idle"]
         
     if phase == "buy":
         results.append(("buy", -1))
         handValue = cardUtils.computeHandValue(hand)
         for cardID in kingdom:
             if kingdom[cardID] > 0:
                 buyCard = cardUtils.getCardFromID(cardID)
                 if buyCard.cardCost <= money:
                     results.append(("buy", buyCard.cardID))
     
     if phase == "action":
         results.append(("play", -1))
         for cardID in set(hand):
             card = cardUtils.getCardFromID(cardID)
             if "action" in card.cardType:
                 results.append(("play", card.cardID))
                 
     return results
예제 #3
0
 def __init__(self, mdp, usingCachedWeights=False, cachingWeights=False, cacheStringKey=""):
     self.handSize = mdp.handSize
     self.maxTurns = mdp.maxTurns
     self.bigVPCard = max((cardUtils.getCardFromID(cardID).victoryPoints, cardUtils.getCardFromID(cardID)) for cardID in mdp.startKingdom)[1]
     self.usingCachedWeights = usingCachedWeights
     self.cachingWeights = cachingWeights
     self.cacheStringKey = cacheStringKey
     
     return
예제 #4
0
    def __init__(self,
                 mdp,
                 usingCachedWeights=False,
                 cachingWeights=False,
                 cacheStringKey=""):
        self.handSize = mdp.handSize
        self.maxTurns = mdp.maxTurns
        self.bigVPCard = max((cardUtils.getCardFromID(cardID).victoryPoints,
                              cardUtils.getCardFromID(cardID))
                             for cardID in mdp.startKingdom)[1]
        self.usingCachedWeights = usingCachedWeights
        self.cachingWeights = cachingWeights
        self.cacheStringKey = cacheStringKey

        return
예제 #5
0
def printGameHistory(gameHistory, mdp, allPlayerStates=[], playerID=None):
    #TODO: readability: /3 , * 3 ???
    print "player states: ", allPlayerStates
    for i in range(len(gameHistory) / 3):
        state = gameHistory[i * 3 + 2]
        kingdom, deck, hand, drawPile, discardPile, phase, turn, buys, actions, money, cardsPlayed = state
        print "Turn:", turn,
        if phase == "buy":
            print "Money:", money, 
        action = gameHistory[i * 3]
        if action[0] == 'buy':
                buy, buyCardID = action
                if buyCardID == -1:
                    cardName = "None"
                else:
                    cardName = cardUtils.getCardFromID(buyCardID).cardName
                print "Action:", buy, cardName
        else:
            print action
        print "Deck after:",
        cardUtils.printDeck(deck)
        print "Drew hand: ", hand
        print "###############################################" 
        if mdp.endOfGame(state):
            print "end of game"
            for ID in range(len(allPlayerStates)):
                kingdom1, deck1, hand1, drawPile1, discardPile1, phase1, turn1, buys1, actions1, money1, cardsPlayed1 = allPlayerStates[ID]

                otherPlayerStates = list(allPlayerStates)
                otherPlayerStates.remove(allPlayerStates[ID])
                print "Player ", str(ID), "Game Reward: ", str(mdp.computeReward(allPlayerStates[ID], otherPlayerStates))
                print "Number of Victory Points:", str(cardUtils.computeVictoryPoints(deck1))
            print "Number of Turns:", turn
예제 #6
0
파일: main.py 프로젝트: njabswalsh/Dominion
 def computeHandValue(hand):
     handValue = 0
     for cardID in hand:
         card = cardUtils.getCardFromID(cardID)
         if card.cardType == "treasure":
             handValue += card.treasureValue
     return handValue
예제 #7
0
 def getAction(self, state, actions, otherPlayerStates = []):
     kingdom, deck, hand, drawPile, discardPile, phase, turn, buys, actions, money, cardsPlayed = state
     if phase == "buy":
         handValue = cardUtils.computeHandValue(hand)
         if handValue > self.bigVPCard.cardCost:
             return ("buy", self.bigVPCard.cardID)
         bestTreasureCard = None
         bestTreasureValue = float('-inf')
         for cardID in kingdom:
             card = cardUtils.getCardFromID(cardID)
             if "treasure" in card.cardType:
                 if card.cardCost <= handValue and card.treasureValue > bestTreasureValue:
                     bestTreasureCard = card
                     bestTreasureValue = card.treasureValue
         return ("buy", bestTreasureCard.cardID)
     if phase == "action":
         return ("play", -1)
예제 #8
0
 def getAction(self, state, actions, otherPlayerStates=[]):
     kingdom, deck, hand, drawPile, discardPile, phase, turn, buys, actions, money, cardsPlayed = state
     if phase == "buy":
         handValue = cardUtils.computeHandValue(hand)
         if handValue > self.bigVPCard.cardCost:
             return ("buy", self.bigVPCard.cardID)
         bestTreasureCard = None
         bestTreasureValue = float('-inf')
         for cardID in kingdom:
             card = cardUtils.getCardFromID(cardID)
             if "treasure" in card.cardType:
                 if card.cardCost <= handValue and card.treasureValue > bestTreasureValue:
                     bestTreasureCard = card
                     bestTreasureValue = card.treasureValue
         return ("buy", bestTreasureCard.cardID)
     if phase == "action":
         return ("play", -1)
예제 #9
0
    def getBestCardToBuy(self, money, kingdom):
        #Deal with buying VP cards
        if money >= 8:
            return 5 #CardID of province
        if kingdom[5] <= self.vpParemeters[0]:
            if money >= 5:
                return 4
        if kingdom[5] <= self.vpParemeters[1]:
            if money >= 2:
                return 3

        for i in range(len(self.buyList)):
            cardID, numberToBuy = self.buyList[i]
            if numberToBuy > 0 and kingdom[cardID] > 0:
                cardCost = cardUtils.getCardFromID(cardID).cardCost
                if cardCost <= money:
                    self.buyList[i] = (cardID, numberToBuy - 1)
                    return cardID
        return -1
예제 #10
0
    def getBestCardToBuy(self, money, kingdom):
        #Deal with buying VP cards
        if money >= 8:
            return 5 #CardID of province
        if kingdom[5] <= self.vpParemeters[0]:
            if money >= 5:
                return 4
        if kingdom[5] <= self.vpParemeters[1]:
            if money >= 2:
                return 3

        for i in range(len(self.buyList)):
            cardID, numberToBuy = self.buyList[i]
            if numberToBuy > 0 and kingdom[cardID] > 0:
                cardCost = cardUtils.getCardFromID(cardID).cardCost
                if cardCost <= money:
                    self.buyList[i] = (cardID, numberToBuy - 1)
                    return cardID
        return -1
예제 #11
0
파일: main.py 프로젝트: njabswalsh/Dominion
 def actions(self, state):
     def computeHandValue(hand):
         handValue = 0
         for cardID in hand:
             card = cardUtils.getCardFromID(cardID)
             if card.cardType == "treasure":
                 handValue += card.treasureValue
         return handValue
     # BEGIN_YOUR_CODE (around 5 lines of code expected)
     results = []
     results.append(("buy", -1))
     deck, hand, drawPile, discardPile, phase, turn = state
     if turn == self.maxTurns:
         return []
     if phase == "buy":
         handValue = computeHandValue(hand)
         for cardID in self.kingdom:
             buyCard = cardUtils.getCardFromID(cardID)
             if buyCard.cardCost <= handValue:
                 results.append(("buy", buyCard.cardID))
     #print handValue
     return results
예제 #12
0
def gameStageFeatureExtractor(state, otherPlayerStates=[]) :
    kingdom, deck, hand, drawPile, discardPile, phase, turn, buys, actions, money, cardsPlayed = state
    features = []
    #Compute "Stage" of game
    opponentState = otherPlayerStates[0]
    oppkingdom, oppdeck, opphand, oppdrawPile, oppdiscardPile, oppphase, oppturn, oppbuys, oppactions, oppmoney, oppcardsPlayed = opponentState
    gameStage = "Start"
    if deck[5] > 0 or oppdeck[5] > 0:
        gameStage = "Middle"
    if deck[5] + oppdeck[5] > 6:
        gameStage = "End"

    deckValue = cardUtils.computeDeckValue(deck)
    treasureCount = 0
    for cardID in deck:
        if "treasure" in cardUtils.getCardFromID(cardID).cardType:
            treasureCount += deck[cardID]
    averageMoneyValue =  (deckValue + 0.0) / treasureCount
    roundedMoneyValue = round(averageMoneyValue, 1)
    features.append(("AverageMoneyValue:" + str(roundedMoneyValue) + "Stage" + gameStage, 1))

    numProvinces = cardUtils.getNumProvinceCards(deck)
    features.append(("provincesInDeck:" + str(numProvinces) + "Stage:" + gameStage, 1))

    for cardID in deck:
        features.append(("numOfCardsInDeckOfType" + str(cardID) + "=" + str(deck[cardID]) + "Stage:" + gameStage, 1))

    vPoints = cardUtils.computeVictoryPoints(deck)
    maxOtherPlayerVPoints = 0
    for state in otherPlayerStates:
        playerVPoints = cardUtils.computeVPointsFromState(state)
        if playerVPoints > maxOtherPlayerVPoints:
            maxOtherPlayerVPoints = playerVPoints
    vPointsDif = vPoints - maxOtherPlayerVPoints
    features.append(("vPointsDif" + str(vPointsDif) + "Stage" + gameStage, 1))
    return features
예제 #13
0
def gameStageFeatureExtractor(state, otherPlayerStates=[]) :
    kingdom, deck, hand, drawPile, discardPile, phase, turn, buys, actions, money, cardsPlayed = state
    features = []
    #Compute "Stage" of game
    opponentState = otherPlayerStates[0]
    oppkingdom, oppdeck, opphand, oppdrawPile, oppdiscardPile, oppphase, oppturn, oppbuys, oppactions, oppmoney, oppcardsPlayed = opponentState
    gameStage = "Start"
    if deck[5] > 0 or oppdeck[5] > 0:
        gameStage = "Middle"
    if deck[5] + oppdeck[5] > 6:
        gameStage = "End"

    deckValue = cardUtils.computeDeckValue(deck)
    treasureCount = 0
    for cardID in deck:
        if "treasure" in cardUtils.getCardFromID(cardID).cardType:
            treasureCount += deck[cardID]
    averageMoneyValue =  (deckValue + 0.0) / treasureCount
    roundedMoneyValue = round(averageMoneyValue, 1)
    features.append(("AverageMoneyValue:" + str(roundedMoneyValue) + "Stage" + gameStage, 1))

    numProvinces = cardUtils.getNumProvinceCards(deck)
    features.append(("provincesInDeck:" + str(numProvinces) + "Stage:" + gameStage, 1))

    for cardID in deck:
        features.append(("numOfCardsInDeckOfType" + str(cardID) + "=" + str(deck[cardID]) + "Stage:" + gameStage, 1))

    vPoints = cardUtils.computeVictoryPoints(deck)
    maxOtherPlayerVPoints = 0
    for state in otherPlayerStates:
        playerVPoints = cardUtils.computeVPointsFromState(state)
        if playerVPoints > maxOtherPlayerVPoints:
            maxOtherPlayerVPoints = playerVPoints
    vPointsDif = vPoints - maxOtherPlayerVPoints
    features.append(("vPointsDif" + str(vPointsDif) + "Stage" + gameStage, 1))
    return features
예제 #14
0
파일: main.py 프로젝트: njabswalsh/Dominion
def printActions(actions):
    for action in actions:
        actionType, cardID = action
        print actionType, cardUtils.getCardFromID(cardID).cardName, ",",
    print
예제 #15
0
    def succAndProbs(self, state, action, otherPlayerStates=[]):
        kingdom, deck, hand, drawPile, discardPile, phase, turn, buys, actions, money, cardsPlayed = state
        nextDeck = Counter(deck)
        nextDiscardPile = Counter(discardPile)
        nextKingdom = Counter(kingdom)
        nextPhase = phase
        nextBuys = buys
        nextActions = actions
        nextMoney = money
        actionType, cardID = action
        results = []
        newDrawPile = Counter(drawPile)
        nextCardsPlayed = Counter(cardsPlayed)
        if actionType == "play":
            #Not playing a card (i.e. Playing "None")
            if cardID == -1:
                nextMoney += cardUtils.computeHandValue(hand)
                nextPhase = "buy"
                newState = (util.HashableDict(nextKingdom), util.HashableDict(nextDeck), tuple(hand), util.HashableDict(newDrawPile), util.HashableDict(nextDiscardPile), nextPhase, turn, nextBuys, nextActions, nextMoney, util.HashableDict(nextCardsPlayed))
                prob = 1
                results.append((newState, prob))
            else:
                nextHand = list(hand)
                #Remove card from hand
                nextHand.remove(cardID)
                #Discard the card
                nextCardsPlayed[cardID] += 1
                #Play the card (Deal with the effects)
                nextActions -= 1
                cardEffects = cardUtils.getCardFromID(cardID).effects
                nextBuys += cardEffects["buys"]
                nextActions += cardEffects["actions"]
                nextMoney += cardEffects["money"]
                #Draw cards
                numCardsToDraw = cardEffects["cards"]
                if numCardsToDraw == 0:
                    if nextActions == 0:
                        nextMoney += cardUtils.computeHandValue(nextHand)
                        nextPhase = "buy"
                    newState = (util.HashableDict(nextKingdom), util.HashableDict(nextDeck), tuple(nextHand), util.HashableDict(newDrawPile), util.HashableDict(nextDiscardPile), nextPhase, turn, nextBuys, nextActions, nextMoney, util.HashableDict(nextCardsPlayed))
                    prob = 1
                    results.append((newState, prob))
                else:
                    newHand = list(nextHand)
                    if sum(newDrawPile.values()) + sum(nextDiscardPile.values()) < numCardsToDraw:

                        #Draw the rest of the deck 
                        for cardID in newDrawPile.keys():
                            for i in range(newDrawPile[cardID]):
                                newHand.append(cardID)
                                newDrawPile[cardID] -= 1
                                numCardsToDraw -= 1
                        #Draw the rest of the discard pile
                        for cardID in nextDiscardPile.keys():
                            for i in range(nextDiscardPile[cardID]):
                                newHand.append(cardID)
                                nextDiscardPile[cardID] -= 1
                                numCardsToDraw -= 1
                        nextHand = newHand
                        nextHand.sort()
                        nextDrawPile = Counter(newDrawPile)
                        if nextActions == 0:
                            nextMoney += cardUtils.computeHandValue(nextHand)
                            nextPhase = "buy"
                        newState = (util.HashableDict(nextKingdom), util.HashableDict(nextDeck), tuple(nextHand), util.HashableDict(nextDrawPile), util.HashableDict(nextDiscardPile), nextPhase, turn, nextBuys, nextActions, nextMoney, util.HashableDict(nextCardsPlayed))
                        prob = 1
                        results.append((newState, prob))
                    else:
                        if sum(newDrawPile.values()) < numCardsToDraw:
                            #Draw the rest of the deck 
                            for cardID in newDrawPile.keys():
                                for i in range(newDrawPile[cardID]):
                                    newHand.append(cardID)
                                    newDrawPile[cardID] -= 1
                                    numCardsToDraw -= 1
                            #Reshuffle
                            newDrawPile = nextDiscardPile
                            nextDiscardPile = Counter()
                        numHands = util.nchoosek(sum(newDrawPile.values()), numCardsToDraw)
                        handsAndProbs = []
                        computeHandsAndProbs(kingdom, [], numHands, handsAndProbs, Counter(newDrawPile), 0, numCardsToDraw)
                        results = []
                        tempMoney = nextMoney
                        for handAddition, prob in handsAndProbs:
                            nextMoney = tempMoney
                            nextHand = newHand + handAddition
                            nextHand.sort()
                            nextDrawPile = Counter(newDrawPile)
                            for cardID in handAddition:
                                nextDrawPile[cardID] -= 1
                            if nextActions == 0:
                                nextMoney += cardUtils.computeHandValue(nextHand)
                                nextPhase = "buy"
                            newState = (util.HashableDict(nextKingdom), util.HashableDict(nextDeck), tuple(nextHand), util.HashableDict(nextDrawPile), util.HashableDict(nextDiscardPile), nextPhase, turn, nextBuys, nextActions, nextMoney, util.HashableDict(nextCardsPlayed))
                            results.append((newState, prob))
                #
        if actionType == "buy":
            if cardID != -1:
                #Buy the card
                nextDeck[cardID] += 1
                nextDiscardPile[cardID] += 1
                nextKingdom[cardID] -= 1
                nextBuys -= 1
                nextMoney -= cardUtils.getCardFromID(cardID).cardCost
            #Start a new turn if we choose to buy nothing or only have one card to buy
            if buys == 1 or cardID == -1:
                #Discard the action cards we played
                nextDiscardPile += nextCardsPlayed
                nextCardsPlayed = Counter()
                turn += 1
                nextBuys = 1
                nextMoney = 0
                nextActions = 1
                nextPhase = "action"
                #Discard your hand
                for cardID in hand:
                    nextDiscardPile[cardID] += 1
                #Compute new hands and probabilities
                newHand = []
                handSize = self.handSize
                newDrawPile = Counter(drawPile)
                if sum(newDrawPile.values()) < self.handSize:
                    #Reshuffle. 
                    for cardID in newDrawPile.keys():
                        for i in range(newDrawPile[cardID]):
                            newHand.append(cardID)
                            newDrawPile[cardID] -= 1
                            handSize -= 1
                    newDrawPile = nextDiscardPile
                    nextDiscardPile = Counter()
                numHands = util.nchoosek(sum(newDrawPile.values()), handSize)
                handsAndProbs = []
                computeHandsAndProbs(kingdom, [], numHands, handsAndProbs, Counter(newDrawPile), 0, handSize)
                results = []
                for handAddition, prob in handsAndProbs:
                    nextHand = newHand + handAddition
                    nextHand.sort()
                    nextDrawPile = Counter(newDrawPile)
                    for cardID in handAddition:
                        nextDrawPile[cardID] -= 1
                    newState = (util.HashableDict(nextKingdom), util.HashableDict(nextDeck), tuple(nextHand), util.HashableDict(nextDrawPile), util.HashableDict(nextDiscardPile), nextPhase, turn, nextBuys, nextActions, nextMoney, util.HashableDict(nextCardsPlayed))
                    results.append((newState, prob))
            else:
                newState = (util.HashableDict(nextKingdom), util.HashableDict(nextDeck), tuple(hand), util.HashableDict(newDrawPile), util.HashableDict(nextDiscardPile), nextPhase, turn, nextBuys, nextActions, nextMoney, util.HashableDict(nextCardsPlayed))
                prob = 1
                results.append((newState, prob))
        return results
예제 #16
0
    def succAndProbs(self, state, action, otherPlayerStates=[]):
        kingdom, deck, hand, drawPile, discardPile, phase, turn, buys, actions, money, cardsPlayed = state
        nextDeck = Counter(deck)
        nextDiscardPile = Counter(discardPile)
        nextKingdom = Counter(kingdom)
        nextPhase = phase
        nextBuys = buys
        nextActions = actions
        nextMoney = money
        actionType, cardID = action
        results = []
        newDrawPile = Counter(drawPile)
        nextCardsPlayed = Counter(cardsPlayed)
        if actionType == "play":
            #Not playing a card (i.e. Playing "None")
            if cardID == -1:
                nextMoney += cardUtils.computeHandValue(hand)
                nextPhase = "buy"
                newState = (util.HashableDict(nextKingdom),
                            util.HashableDict(nextDeck), tuple(hand),
                            util.HashableDict(newDrawPile),
                            util.HashableDict(nextDiscardPile), nextPhase,
                            turn, nextBuys, nextActions, nextMoney,
                            util.HashableDict(nextCardsPlayed))
                prob = 1
                results.append((newState, prob))
            else:
                nextHand = list(hand)
                #Remove card from hand
                nextHand.remove(cardID)
                #Discard the card
                nextCardsPlayed[cardID] += 1
                #Play the card (Deal with the effects)
                nextActions -= 1
                cardEffects = cardUtils.getCardFromID(cardID).effects
                nextBuys += cardEffects["buys"]
                nextActions += cardEffects["actions"]
                nextMoney += cardEffects["money"]
                #Draw cards
                numCardsToDraw = cardEffects["cards"]
                if numCardsToDraw == 0:
                    if nextActions == 0:
                        nextMoney += cardUtils.computeHandValue(nextHand)
                        nextPhase = "buy"
                    newState = (util.HashableDict(nextKingdom),
                                util.HashableDict(nextDeck), tuple(nextHand),
                                util.HashableDict(newDrawPile),
                                util.HashableDict(nextDiscardPile), nextPhase,
                                turn, nextBuys, nextActions, nextMoney,
                                util.HashableDict(nextCardsPlayed))
                    prob = 1
                    results.append((newState, prob))
                else:
                    newHand = list(nextHand)
                    if sum(newDrawPile.values()) + sum(
                            nextDiscardPile.values()) < numCardsToDraw:

                        #Draw the rest of the deck
                        for cardID in newDrawPile.keys():
                            for i in range(newDrawPile[cardID]):
                                newHand.append(cardID)
                                newDrawPile[cardID] -= 1
                                numCardsToDraw -= 1
                        #Draw the rest of the discard pile
                        for cardID in nextDiscardPile.keys():
                            for i in range(nextDiscardPile[cardID]):
                                newHand.append(cardID)
                                nextDiscardPile[cardID] -= 1
                                numCardsToDraw -= 1
                        nextHand = newHand
                        nextHand.sort()
                        nextDrawPile = Counter(newDrawPile)
                        if nextActions == 0:
                            nextMoney += cardUtils.computeHandValue(nextHand)
                            nextPhase = "buy"
                        newState = (util.HashableDict(nextKingdom),
                                    util.HashableDict(nextDeck),
                                    tuple(nextHand),
                                    util.HashableDict(nextDrawPile),
                                    util.HashableDict(nextDiscardPile),
                                    nextPhase, turn, nextBuys, nextActions,
                                    nextMoney,
                                    util.HashableDict(nextCardsPlayed))
                        prob = 1
                        results.append((newState, prob))
                    else:
                        if sum(newDrawPile.values()) < numCardsToDraw:
                            #Draw the rest of the deck
                            for cardID in newDrawPile.keys():
                                for i in range(newDrawPile[cardID]):
                                    newHand.append(cardID)
                                    newDrawPile[cardID] -= 1
                                    numCardsToDraw -= 1
                            #Reshuffle
                            newDrawPile = nextDiscardPile
                            nextDiscardPile = Counter()
                        numHands = util.nchoosek(sum(newDrawPile.values()),
                                                 numCardsToDraw)
                        handsAndProbs = []
                        computeHandsAndProbs(kingdom, [],
                                             numHands, handsAndProbs,
                                             Counter(newDrawPile), 0,
                                             numCardsToDraw)
                        results = []
                        tempMoney = nextMoney
                        for handAddition, prob in handsAndProbs:
                            nextMoney = tempMoney
                            nextHand = newHand + handAddition
                            nextHand.sort()
                            nextDrawPile = Counter(newDrawPile)
                            for cardID in handAddition:
                                nextDrawPile[cardID] -= 1
                            if nextActions == 0:
                                nextMoney += cardUtils.computeHandValue(
                                    nextHand)
                                nextPhase = "buy"
                            newState = (util.HashableDict(nextKingdom),
                                        util.HashableDict(nextDeck),
                                        tuple(nextHand),
                                        util.HashableDict(nextDrawPile),
                                        util.HashableDict(nextDiscardPile),
                                        nextPhase, turn, nextBuys, nextActions,
                                        nextMoney,
                                        util.HashableDict(nextCardsPlayed))
                            results.append((newState, prob))
                #
        if actionType == "buy":
            if cardID != -1:
                #Buy the card
                nextDeck[cardID] += 1
                nextDiscardPile[cardID] += 1
                nextKingdom[cardID] -= 1
                nextBuys -= 1
                nextMoney -= cardUtils.getCardFromID(cardID).cardCost
            #Start a new turn if we choose to buy nothing or only have one card to buy
            if buys == 1 or cardID == -1:
                #Discard the action cards we played
                nextDiscardPile += nextCardsPlayed
                nextCardsPlayed = Counter()
                turn += 1
                nextBuys = 1
                nextMoney = 0
                nextActions = 1
                nextPhase = "action"
                #Discard your hand
                for cardID in hand:
                    nextDiscardPile[cardID] += 1
                #Compute new hands and probabilities
                newHand = []
                handSize = self.handSize
                newDrawPile = Counter(drawPile)
                if sum(newDrawPile.values()) < self.handSize:
                    #Reshuffle.
                    for cardID in newDrawPile.keys():
                        for i in range(newDrawPile[cardID]):
                            newHand.append(cardID)
                            newDrawPile[cardID] -= 1
                            handSize -= 1
                    newDrawPile = nextDiscardPile
                    nextDiscardPile = Counter()
                numHands = util.nchoosek(sum(newDrawPile.values()), handSize)
                handsAndProbs = []
                computeHandsAndProbs(kingdom, [], numHands, handsAndProbs,
                                     Counter(newDrawPile), 0, handSize)
                results = []
                for handAddition, prob in handsAndProbs:
                    nextHand = newHand + handAddition
                    nextHand.sort()
                    nextDrawPile = Counter(newDrawPile)
                    for cardID in handAddition:
                        nextDrawPile[cardID] -= 1
                    newState = (util.HashableDict(nextKingdom),
                                util.HashableDict(nextDeck), tuple(nextHand),
                                util.HashableDict(nextDrawPile),
                                util.HashableDict(nextDiscardPile), nextPhase,
                                turn, nextBuys, nextActions, nextMoney,
                                util.HashableDict(nextCardsPlayed))
                    results.append((newState, prob))
            else:
                newState = (util.HashableDict(nextKingdom),
                            util.HashableDict(nextDeck), tuple(hand),
                            util.HashableDict(newDrawPile),
                            util.HashableDict(nextDiscardPile), nextPhase,
                            turn, nextBuys, nextActions, nextMoney,
                            util.HashableDict(nextCardsPlayed))
                prob = 1
                results.append((newState, prob))
        return results