bj.py

'''\
Blackjack - Play.

Cards are integer values from 1 (Ace) to 10.

Rules:
    0 - null
    1 - stay
    2 - hit
    3 - double
    4 - split pair
    5 - bust
    6 - push
    7 - win (got 21)
    8 - blackjack (player)
    9 - blackjack (dealer)

Developer@Sonnack.com
March 2016
'''
####################################################################################################
from sys import stdout, stderr, argv
from os import path
from datetime import datetime, timedelta
from htmlpage import htmlpage
from bj_objects import CardDeck, Dealer, Player
####################################################################################################
#TODO: Validate operation!
#TODO: Try different rules.

HtmlPath = r'C:\CJS\www\root\tmp'

nbr_of_plays = 250
nbr_of_decks = 4
player_bank  = nbr_of_plays
dealer_bank  = 1000000


##================================================================================================##
def PlayBlackjack ():
    data = []
    deck = []
    dealer = Dealer(dealer_bank)
    player = Player(player_bank)
    decks_used = 0

    #TODO: Change to Log!
    fn = 'bj.out'
    fp = open(fn, 'w')
    try:
        print >> fp, '@@: %s' % datetime.now()
        print >> fp, 'Bank: Player: %d, Dealer: %d' % (player.bank, dealer.bank)
        print >> fp

        play = 1
        while (play <= nbr_of_plays) and (100 < dealer.bank) and (0 < player.bank):
            if len(deck) < 13:
                deck = CardDeck(nbr_of_decks)
                decks_used += 1
                print >> fp, 'New Deck: ' + str(deck)
                print >> fp

            # Play...
            dealer.new_hand()
            player.new_hand()
            print >> fp, 'Play: %d' % play

            # Bet...
            player.make_bet()
            print >> fp, 'Bet: %d  {pot: %d}' % (player.bet, player.bank)

            # Deal first card...
            player(deck())
            dealer(deck())
            # Deal second card...
            player(deck())
            dealer(deck())

            # Player plays...
            player.play_hand(deck, dealer, fp)
            if player.split_pair_flag:
                print >> fp, player.p1
                print >> fp, player.p2
            else:
                print >> fp, player

            # Dealer plays...
            dealer.play_hand(deck, player, fp)
            print >> fp, dealer

            # Payoff bets...
            if WinLose(fp, dealer, player):
                player.set_bet_level(True if 0 < player.win_lose else False)
            print >> fp, 'Bank: Player: %d, Dealer: %d' % (player.bank, dealer.bank)

            # Data collection...
            if player.split_pair_flag:
                t1 = (play, player.p1.win_lose, player.p1.bet, player.bet_level, player.bank, player.p1.cards, dealer.cards)
                t2 = (play, player.p2.win_lose, player.p2.bet, player.bet_level, player.bank, player.p2.cards, dealer.cards)
                data.append(t1)
                data.append(t2)
            else:
                t = (play, player.win_lose, player.bet, player.bet_level, player.bank, player.cards, dealer.cards)
                data.append(t)

            # loop...
            play += 1
            print >> fp

        print >> fp
        print >> fp, 'EXIT'
        print >> fp, '@@: %s' % datetime.now()
        print >> fp, 'Player Bank: %6d' % player.bank
        print >> fp, 'Bank Change: %+5d' % (player.bank - player.original_bank)
        print >> fp, 'Max Bank: %5d' % player.max_bank
        print >> fp, 'Min Bank: %5d' % player.min_bank
        print >> fp, 'Card Decks: %d' % decks_used
        print >> fp, 'Cards remaining in deck: %d' % len(deck)
        print >> fp
        print
        print 'Total Plays: %d' % play
        print 'Bank: Player: %d, Dealer: %d' % (player.bank, dealer.bank)
        print 'Bank Change: %+5d' % (player.bank - player.original_bank)
        print 'Max Bank: %5d' % player.max_bank
        print 'Min Bank: %5d' % player.min_bank
        print 'Card Decks: %d' % decks_used
        print 'Cards remaining in deck: %d' % len(deck)
        print

    except Exception as e:
        print >> fp, e
        raise

    finally:
        fp.close()
        print 'wrote: %s' % fn

    return (dealer, player, data)

##================================================================================================##
def WinLose (fp, dealer, player):
    # Split Pair...
    if player.split_pair_flag:
        player.p1.win_lose = WinLoseHand(fp, dealer, player, player.p1)
        player.p2.win_lose = WinLoseHand(fp, dealer, player, player.p2)
        player.win_lose = int((player.p1.win_lose + player.p2.win_lose) / 2)
    # Normal Hand...
    else:
        player.win_lose = WinLoseHand(fp, dealer, player, player)
    return player.win_lose

##================================================================================================##
def WinLoseHand (fp, dealer, player, player_hand):
    fmt = 'Outcome: %s'
    if player_hand.bust():
        print >> fp, fmt % 'Player Busts!'
        dealer.bank += player.bet
        return -1
    if dealer.blackjack():
        if player_hand.blackjack():
            # Tie...
            print >> fp, fmt % 'Blackjack Tie!'
            player.bank += player.bet
            return 0
        # Dealer wins...
        print >> fp, fmt % 'Dealer Blackjack!'
        dealer.bank += player.bet
        return -1
    if player_hand.blackjack():
        # Player blackjack...
        print >> fp, fmt % 'Blackjack!'
        dealer.bank -= (1.5 * player.bet)
        player.bank += (2.5 * player.bet)
        return +2
    if dealer.bust():
        # Player wins...
        print >> fp, fmt % 'Dealer Busts!'
        dealer.bank -= player.bet
        player.bank += (2 * player.bet)
        return +1
    if dealer.hand == player_hand.hand:
        # Tie...
        print >> fp, fmt % 'Push!'
        player.bank += player.bet
        return 0
    if dealer.hand < player_hand.hand:
        print >> fp, fmt % 'Player Wins!'
        dealer.bank -= (1 * player.bet)
        player.bank += (2 * player.bet)
        return +1
    print >> fp, fmt % 'Player Loses!'
    dealer.bank += player.bet
    return -1




##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
class PageWriter (object):
    '''HTML Page Writer class.'''
    results = {-1:'Lose', 0:'Push', +1:'Win!', +2:'BJ!'}

    def __init__ (self, _player, _data):
        self.ts = datetime.now()
        self.player = _player
        self.data = _data

    def create_html_page (self, filename):
        fp = open(filename, 'w')
        try:
            H1 = 'Blackjack'
            H2 = 'Python'
            H3 = 'Blackjack Play Log'
            SS = ['/basic.css']
            JS = []
            pg = htmlpage(H3, h1=H1, h2=H2, csspages=SS, jspages=JS)
            pg.writepage(fp, self)
            #...
            print 'wrote: %s' % filename
        except Exception as e:
            raise
        finally:
            fp.close()

    def writepage (self, fp):
        fp.write('<div style="font-size:medium;border-spacing:4px 0;padding:0;margin:6pt 12pt;">\n')
        fp.write('<div>%s</div>' % self.ts.strftime('%c'))
        nh = len(self.data)
        np = self.data[nh-1][0]
        fp.write('<div>Plays: %d (Hands: %d)</div>' % (np,nh))
        fp.write('<div>Player Bank: %6d (Original: %d)</div>' % (self.player.bank, self.player.original_bank))
        dif = self.player.bank - self.player.original_bank
        pct = 100.0 * (self.player.bank / self.player.original_bank)
        fp.write('<div>Bank Change: <strong>%+5d</strong> (%.2f%%)</div>' % (dif,pct))
        fp.write('<div>Max Bank: %5d</div>' % self.player.max_bank)
        fp.write('<div>Min Bank: %5d</div>' % self.player.min_bank)
        fp.write('</div>\n')

        fp.write('<table style="font-size:small;border-spacing:4px 0;padding:0;border:1px solid black;margin:12pt;">\n')
        fp.write('<thead style="font-style:italic;">\n')
        fp.write('<tr>\n')
        fp.write('<th>#</th>\n')
        fp.write('<th>&raquo;&raquo;&raquo;</th>\n')
        fp.write('<th>&equiv;</th>\n')
        fp.write('<th>bet</th>\n')
        fp.write('<th>&plusmn;</th>\n')
        fp.write('<th>$$</th>\n')
        fp.write('<th style="text-align:left;">Player</th>\n')
        fp.write('<th style="text-align:left;">Dealer</th>\n')
        fp.write('</tr>\n')
        fp.write('</thead>\n')

        fp.write('<tbody>\n')
        for datum in self.data:
            r = self.results[datum[1]]
            cr = 'red' if datum[1] < 0 else ('green' if 0 < datum[1] else 'blue')
            b = (datum[4] - self.player.original_bank)
            cb = 'red' if datum[4] < self.player.original_bank else 'green'
            fp.write('<tr>\n')
            fp.write('<td style="text-align:left;padding:3px 4pt;">%4d</td>\n' % datum[0])
            fp.write('<td style="color:%s;font-weight:bold;text-left:right;padding:3px 9pt 3px 6pt;">%s</td>\n' % (cr,r))
            fp.write('<td style="text-align:center;padding:3px 4pt;">%s</td>\n' % str(datum[3]))
            fp.write('<td style="font-weight:bold;text-align:right;padding:3px 9pt 3px 6pt;">%d</td>\n' % datum[2])
            fp.write('<td style="color:%s;text-align:right;padding:3px 9pt 3px 6pt;">%+.1f</td>\n' % (cb,b))
            fp.write('<td style="text-align:right;padding:3px 6pt 3px 4pt;">%.1f</td>\n' % datum[4])
            fp.write('<td style="text-align:left;padding:3px 4pt;">%s</td>\n' % str(datum[5]))
            fp.write('<td style="text-align:left;padding:3px 4pt;">%s</td>\n' % str(datum[6]))
            fp.write('</tr>\n')

        fp.write('</tbody>\n')
        fp.write('</table>\n')
        fp.write('\n')



##================================================================================================##
def do_main (*args):
    print 'main/parameters: %d' % len(args)
    filename = args[0] if 0 < len(args) else 'bj_play.html'
    htmlname = path.join(HtmlPath, filename)
    # Play...
    dealer, player, data = PlayBlackjack()
    # Print...
    pgwr = PageWriter(player, data)
    pgwr.create_html_page(htmlname)
    return 'Done!'
####################################################################################################
def dispatch (cmd, *args):
    print 'command: %s' % cmd
    print 'arguments: %d' % len(args)
    if cmd == 'test': return do_main(*args)
    if cmd == 'main': return do_main(*args)
    return 'Nothing to do!'
####################################################################################################
if __name__ == '__main__':
    print 'autorun: %s' % argv[0]
    cmd = argv[1] if 1 < len(argv) else ''
    etc = argv[2:] if 2 < len(argv) else []
    obj = dispatch(cmd, *etc)
    print obj
####################################################################################################
'''eof'''