import random  
import copy

## Constants
HIT, STAND = 1, 2  
ACE = 1  
CLUBS, DIAMONDS, HEARTS, SPADES = 1, 2, 3, 4  
IN_PLAY, DEALER_BLACKJACK, PLAYER_BLACKJACK, PUSH, WIN, LOSE, BUST = 1, 2, 3, 4, 5, 6, 7  
RESULTS = [None, "In play", "Dealer blackjack", "Player blackjack",  
           "Push", "Win", "Lose", "Bust"]
SUITS = ["Clubs","Diamonds","Hearts","Spades"]  
RANKS = ["Ace","2","3","4","5","6","7","8","9","10","Jack","Queen","King"]


class GameState:  
    def __init__(self):
        self.playerCards = []
        self.dealerCards = []
        self.money = 0
        self.result = None
        self.deck = Deck()


class Card:  
    def __init__(self, rank, suit):
        self.rank = rank
        self.suit = suit

    def __repr__(self):
        return "%s of %s" % (RANKS[self.rank-1], SUITS[self.suit-1])


class Deck:  
    def __init__(self):
        self.deck = []

        for s in range(1,5):
            for r in range(1,14):
                self.deck.append(Card(r,s))

        random.shuffle(self.deck)

    def Deal(self, num=1):
        if num==1:
            return self.deck.pop(random.randint(0,len(self.deck)-1))
        else:
            cards = []
            for n in range(0,num):
                cards.append(self.Deal())
            return cards


class Blackjack:  
    def Count(self, cards):
        sum = [0]
        for c in cards:
            if c.rank == ACE:
                k = len(sum)
                for n in range(0,k):
                    sum[n] += 1
                    sum.append(sum[n]+10)
                sum = list(set(sum))
            else:
                for n in range(0,len(sum)):
                    if c.rank >= 10:
                        sum[n] += 10
                    else:
                        sum[n] += c.rank
        sum.sort()
        return sum

    def Trim(self, cards):
        trimmed = []
        for n in cards:
            if n <= 21:
                trimmed.append(n)
        if trimmed == []:
            trimmed = [min(cards)]
        return trimmed

    def Action(self, action, s):
        state = copy.deepcopy(s)
        if action == STAND:
            dealerVals = self.Count(state.dealerCards)
            while max(dealerVals) < 17:
                state.dealerCards.append(state.deck.Deal())
                dealerVals = self.Trim(self.Count(state.dealerCards))
            if max(dealerVals) > 21 or max(dealerVals) < max(self.Trim(self.Count(state.playerCards))):
                state.result = WIN
                state.money += 1
            elif max(dealerVals) == max(self.Trim(self.Count(state.playerCards))):
                state.result = PUSH
            else:
                state.result = LOSE
                state.money -= 1
        elif action == HIT:
            state.playerCards.append(state.deck.Deal())
            if min(self.Count(state.playerCards)) > 21:
                state.result = BUST
                state.money -= 1

        return state

    def NewHand(self):
        state = GameState()
        state.dealerCards = state.deck.Deal(2)
        state.playerCards = state.deck.Deal(2)

        if (max(self.Count(state.dealerCards)) == 21 and
            max(self.Count(state.playerCards)) == 21):
            state.result = PUSH
        elif max(self.Count(state.dealerCards)) == 21:
            state.result = DEALER_BLACKJACK
            state.money -= 1
        elif max(self.Count(state.playerCards)) == 21:
            state.result = PLAYER_BLACKJACK
            state.money += 2
        else:
            state.result = IN_PLAY

        return state


def main():  
    bj = Blackjack()
    money = 0
    action = None

    while True:
        state = bj.NewHand()
        print "Dealer shows: %s" % state.dealerCards[0]
        print "Your cards: %s" % state.playerCards

        if state.result == PUSH:
            print "Dealer shows: %s" % state.dealerCards
            print "PUSH"
        elif state.result == DEALER_BLACKJACK:
            print "Dealer shows: %s" % state.dealerCards
            print "Dealer blackjack! <img src="http://trevorcappallo.com/wp-includes/images/smilies/icon_sad.gif" alt=":(" class="wp-smiley"> "
            money += state.money
        elif state.result == PLAYER_BLACKJACK:
            print "Dealer shows: %s" % state.dealerCards
            print "You got a blackjack! <img src="http://trevorcappallo.com/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley"> "
            money += state.money
        else:
            while state.result == IN_PLAY:
                print "\nYour move (1 for hit, 2 for stand, any other to quit):",
                action = input()
                if action != 1 and action != 2:
                    return

                state = bj.Action(action, state)
                print "Your cards: %s" % state.playerCards
                if state.result != IN_PLAY:
                    print "Dealer cards: %s" % state.dealerCards
                    print "Result: %s" % RESULTS[state.result]
                    money += state.money
        print "\nYour balance: %i" % money
        print "---------------------------------------------------------"


if __name__ == '__main__':  
    main()