#                             BlackJack                             #
#                                                                   #
#       Created by      Ole Jensen                                  #
#                       26 July 2003                                #
#                                                                   #
#       filename        BlackJack ver. 0.5.py                       #
#                                                                   #
#       location (url)  http://dbhome.dk/learningtoprogram/programs/#
#                       BlackJack/                                  #
#                                                                   #
#       Catagogy:       Card games;                                 #
#                       computer games;                             #
#                       gambling                                    #
#####################################################################
#                                                                   #
#                    BlackJack ver. 0.5 Alpha                       #
#   You can read version history in 'BlackJack Ducumentation.txt'   #
#                Check out the rules of blackjack at                #
#                   http://www.blackjackinfo.com/                   #
#                                                                   #
#            Any ideas/recomendations/errors/whatever               #
#            Just mail me at learning.python@dbmail.dk              #
#                                                                   #
#####################################################################

# importing modules
import random
from time import sleep
import sys

# Funcions
def hit_or_stand():
    print "Do you want to\n1 hit or\n2 stand?"

def shuffle():
    """deck = shuffle -> deck will be created,\nand
    consist of 6 decks of cards of 4 colours each."""
    deck = []
    colour = [ace, 2, 3, 4, 5, 6, 7, 8, 9, 10, jack, queen, king]
    for i in range(24):
        deck.append(colour[:])
    return deck


def deal(hand, deck):
    """deal(hand, deck) -> one card will be cut from
    the deck\nand copied to the hand."""
    # We need a colour and a value using
    # random.randrange to get a random card from
    # the deck
    colour = random.randrange(0, len(deck))
    if len(deck[colour]) == 0:
        del deck[colour]
        colour = random.randrange(0, len(deck))
            
    value = random.randrange(0, len(deck[colour]))
    # Adding the card to hand
    hand.append(deck[colour][value])
    # And deleting the card from the deck
    del(deck[colour][value])

def sum_(hand):
    """sum_(hand) -> returns the value that the
    player holds"""
    t = i = 0
    for x in hand:
	t += x  # This counts the value of the hand, counting ace as 11
	if x == ace:
	    i = i + 1   #Counts aces in hand
    if t == 21 and len(hand) == 2:
	    return "BlackJack"
    elif i == 0:    # If no ace's: do this
	if len(hand) == 5 and t <= 21:
            return 21   # If you hold five cards, it counts as 21 but < BJ
	else:
	    return t
    elif i > 0:     # If you hold ace(s) the sum must be calculated differently
        # 'Hard sum' is when you have no ace or ace(s) counts as 1
	hard = t - i*10
	# 'Soft sum' is the sum of hand carrying an ace with the value of 11
	soft = t - (i-1)*10 # Hence 'i' is one less then with hard sum
	if len(hand) == 5 and hard <= 21:
	    return 21	
	elif t > 21 and soft > 21:
	    return hard
	else:
	    return hard, soft
    else:   # Just in case
	return "Out of Bounds"

def count(deck):
    """count(deck) -> returns the amount of cards in the deck."""
    i = 0
    for x in deck:
        i += len(x)
    return i

def dealer(hand):
    """Dealer(hand) -> returns 1 if dealer has to hit"""
    if (sum_(hand) < 17) or ((type(sum_(hand)) == tuple) and (sum_(hand)[1] <= 17)):
        return 1
    else:
        return 0

def win_lose(dhand, phand):
    """Win_lose(dhand, phand) -> returns the hand that wins.\n
    Dhand is the dealers hand and phand is the players hand."""
    play = sum_(phand)
    deal = sum_(dhand)
    if type(play) == tuple:
        play = play[1]
    if type(deal) == tuple:
        deal = deal[1]

    if play == "BlackJack" and play != deal:
        return "BJ"
    elif (play > deal) or ((deal > 21) and deal!= "BlackJack"):
        return 1
    elif (play < deal) or (deal == "BlackJack" and deal != play):
        return 0
    else:
        return 2

# Defining card values
# As default ace is 11. Check sum_() above.
ace = 11
jack = queen = king = 10

# Starting with a fresh deck of cards
deck_cards = shuffle()

money = 100
print "Before finding a game, you check your wallet."
print "You've got %s$" % money

# Bet will be a string until we change it.
bet = raw_input("Place your bet, please:\n>")

# If the player bets 0, he quits the game.
# however the value bet is a raw_input() (a string) and
# we haven't change the value to an integer
# yet. Therefore bet needs to be different
# from the string value 0 (zero) to start
# playing.
while bet != "0":

    # Just making sure the player typed what
    # he was told. So if he didn't enter an
    # integer he will stay in this loop, until
    # he does, or 'till the world disolves into
    # atoms!
    while type(bet) != int:
        try:
            # using eval to check (below) to see if the
            # player tries to bet a floating number
            bet = eval(bet)
        except:
            if type(bet) == float:
                # The player might think it is ok to bet
                # floating numbers, so let's tell him its
                # not!
                print "Your need to bet a whole amount of $"
            elif type != int:
                print "Your bet should be in US$"
            bet = raw_input("Place your bet please:\n>")
        if bet == 0:
            sys.exit()
    # Wow we finished that loop. Hence bet must now be an integer!

    # Well we can't play for free...
    money = money - bet
    
    # minimum bet is 5 and max bet is 50.
    # So bet should be between those numbers.
    if 5 <= bet <= 50:
        # Just reseting the values from last game
        hand = []   # Player hand is always empty when starting
        dhand = []  # As well as the dealers hand
        bust = 0    # And bust is false (for now ;-))
        if count(deck_cards) < 20:   # if needed: shufle
            deck_cards = shuffle()
            print "Shufling"
            print "."
            sleep(1)
            print "."
            sleep(1)
            print "."
        deal(hand, deck_cards)
        deal(hand, deck_cards)
        if type(sum_(hand))== tuple:    #i.e. more than one value
                                        # make sure the string can handle that
            print "You hold:", hand, "sum: %s/%s" % (sum_(hand)[0], sum_(hand)[1])
        else:
            print "you hold:", hand, "sum: %s" % (sum_(hand))

        if sum_(hand) != "BlackJack":
            hit_or_stand()
            play = raw_input(">")

            while play != "2":
                if play == "1": # Same as in the first loop
                    deal(hand, deck_cards)
                    if sum_(hand) > 21 and type(sum_(hand)) == int: # Thats a bust
                        bust = 1
                        print "You busted with", hand, "sum: %s" % (sum_(hand))
                        break
                                
                    if type(sum_(hand))== tuple:
                        # This requires a change in the value of sum as
                        # you cannot concatinate a string and a tupple
                        print "You hold:", hand, "sum: %s/%s" % (sum_(hand)[0], sum_(hand)[1])
                    else:
                        print "You hold:", hand, "sum: %s" % (sum_(hand))
                    hit_or_stand()
                    play = raw_input(">")
                    
                else:
                    hit_or_stand()
                    play = raw_input(">")

        # Dealers turn:
        if not bust:
            deal(dhand, deck_cards)
            deal(dhand, deck_cards)
            print dhand
            sleep(1)
            while dealer(dhand):
                deal(dhand, deck_cards)
                print dhand
                sleep(1)


            if win_lose(dhand, hand) == 1:
                print "Player wins"
                money = money + (2 * bet)
            elif win_lose(dhand, hand) == 0:
                print "Dealer wins"
                # wave goodbye that bet!
            elif win_lose(dhand, hand) == 2:
                print "Push"
                # its a draw so you get you bet back
                money = money + bet
            else:
                 print "You win - holding BlackJack"
                 # BlackJack gives 3:2
                 # Remember to avoid integer division
                 money = money + bet + float(3 * bet)/2

        print "Dealer has:", sum_(dhand), "player has:", sum_(hand)
        sleep(2)
        print ""
        print ""
        if money < 0:
            print "You wake up in a dark, cold alley, beaten up and \n\
with broken thumbs, and realise that maybe next time you\n\
shouldn't bet money that you don't have...\n\n\t\t\tGAME OVER"
            sleep(10)
            break
        
        # place a new bet
        print "You still have %s$ to play with" % money
        bet = raw_input("Place your bet please:\n>")
    else:
        if 5 > bet:
            print "Minimum bet is 5$"
        elif 50 < bet:
            print "Maximum bet is 50$"
        else:   # this shouldn't happen
            print "Oh my God what did you do???"
        # The bet is refused, so give the bet back
        # to the player.
        money = money + bet
        print "You still have %s$ to play with" % money
        bet = raw_input("Place your bet please:\n>")
print "end"

