This is a simple vegas-style blackjack game written in Python. This game was a very early project of mine when I was first learning Python ( and programming for that matter ), so the code isn't the best. Still, this might be entertaining or educational.
It currently supports up to 6 players. Network play is not currently supported.
Version 2.0.1
download
Code Listing:
#!/usr/bin/python
"""
--------------------------------------------------------------------------------
PyBlackJack
Python GUI Vegas Style Blackjack Simulator
(c)2004 Thomas McGrew
This application is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This application is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this application; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
--------------------------------------------------------------------------------
"""
import Tkinter
import tkSimpleDialog
import tkMessageBox
import os
from glob import glob
from sys import argv
from random import shuffle
from math import sqrt,ceil
#--change to the PyBlackjack directory---------------
os.chdir(os.path.abspath(os.path.dirname(argv[0])))
#--constants--------------------
VERSION = '2.0.1'
CONFIGFILE = "PyBlackjack.conf"
TABLE = "#0B4"
LOSE = "#E66"
PUSH = "#FF8"
WIN = "#4BD"
WHITE = "#FFF"
HIGHLIGHT = "#CFD"
MAXPLAYERS = 6
#--(sort of) Constants--------------------
# I was going to implement an interactive menu
# to change the fonts, but I couldn't figure out
# how to make Python detect the fonts installed
# on each system [yet].
# If you don't like these fonts, change them here.
# the format is ('font name',size[,'style'])
mainFont = ('comic sans ms',16,'bold')
subFont = ('comic sans ms',12,'bold')
buttonFont = ('comic sans ms',14)
menuFont = ('comic sans ms',11,'bold')
cardValue = {'J':10,'Q':10,'K':10,'A':11}
cards = []
#----------------------------------------------------------------
# The following section of code is derived from
# cards.py written by WVU Tech Comp. Sci. Dept.
# http://www.wvutech.edu/cs/
# Create two lists that describe a deck of cards
cardValues = ['A',2,3,4,5,6,7,8,9,10,'J','Q','K']
cardSuits=['Clubs','Hearts','Diamonds','Spades']
# Put cards in the deck
for suit in cardSuits:
for value in cardValues:
newCard=tuple((value,suit))
cards.append(newCard)
#----------------------------------------------------------------
def firstGame():
initGUI() # Set up the window
bindKeys() # Set up keyboard shortcuts
newGame()
def newGame():
global maxFunds
global winner
global winningFunds
global mainWindow
global startingFunds
global cardBack
global cardPointer
global showDownCard
global dealerPoints
global dealerHand
global playerFunds
global playerPoints
global playerHand
global playerWinLoss
global numPlayers
global playerName
global gameField
global playerBet
# set/reset variables
cardPointer = 0
showDownCard = 0
dealerPoints = 0
dealerHand = []
playerFunds = []
playerPoints = []
playerHand = []
playerWinLoss = []
numPlayers = 0
playerName = []
gameField = []
playerBet = []
# Let's play!
playerName = []
playerFunds = []
numPlayers = 0
shuffleDeck() # Shuffle the cards
# retreive settings, if available
if (readCFG()):
# if not
tkMessageBox.showwarning(title="Warning", message="Configuration file is corrupted or missing -- using default values.")
startingFunds = 1000
cardBack = "blueback.gif"
writeCFG()
# in case the player tries to start a new game while the deck select
# frame is open.
try:
deckSelectFrame.destroy()
except NameError:
pass
initGame() # Set up the Game
initField() # Set up the game table
maxFunds = 0
winner = ''
winningFunds = 5 * playerFunds[numPlayers] # 5 times the initial funds
while (numPlayers > 0) and (maxFunds < winningFunds):
placeBets()
# turn the game spaces back to green
for x in range (0,numPlayers):
gameField[x].config(background = TABLE)
playHand()
# this will color code the game spaces to show who won and lost.
for x in range (0,numPlayers):
if (playerWinLoss[x] == 'WIN'):
gameField[x].config(background = WIN)
elif (playerWinLoss[x] == 'LOSE'):
gameField[x].config(background = LOSE)
elif (playerWinLoss[x] == 'TIE'):
gameField[x].config(background = PUSH)
maxFunds = max(maxFunds,playerFunds[x])
if (numPlayers):
for x in range (0,numPlayers):
if (playerFunds[x] >= winningFunds):
if (winner == ''):
winner = playerName[x].upper()
else:
winner = winner + " AND " + playerName[x].upper()
tkMessageBox.showinfo('Game Over','THE WINNER IS ' + winner + '!!!')
else:
tkMessageBox.showinfo('Game Over','THE HOUSE WINS!!')
# the game is over, so we'll wait for the player to decide what to do next
mainWindow.mainloop()
def initGUI():
global mainWindow
global menuBar
global fileMenu
global optionsMenu
mainWindow = Tkinter.Tk()
mainWindow.title('PyBlackJack ' + VERSION)
menuBar=Tkinter.Menu(mainWindow)
mainWindow["menu"] = menuBar
fileMenu = Tkinter.Menu(menuBar,tearoff=0)
fileMenu.add_command(label="New Game F2", command=fmNewGame,font=menuFont)
fileMenu.add_command(label="Exit Ctrl+X", command=mainWindow.destroy,font=menuFont)
optionsMenu = Tkinter.Menu(menuBar,tearoff=0)
optionsMenu.add_command(label="Funds", command=setFunds,font=menuFont)
optionsMenu.add_command(label="Deck", command=setDeck,font=menuFont)
menuBar.add_cascade(label="File",menu=fileMenu,font=menuFont)
menuBar.add_cascade(label="Options",menu=optionsMenu,font=menuFont)
# ------ Begin Menu Commands -------------------------------------------
def fmNewGame(event=None):
global mainWindow
mainFrame.destroy()
newGame()
def close(event=None):
mainWindow.destroy()
def setFunds():
global startingFunds
newFunds = tkSimpleDialog.askinteger("Adjust Funds","How much money shall we have to start with?",minvalue=100)
if (newFunds):
startingFunds = newFunds
writeCFG()
def setDeck():
global backFile
global backImage
global deckSelectFrame
global deckSelectCanvas
global imagePosition
optionsMenu.entryconfig(1,state="disabled")
backFile = []
backImage = []
imagePosition = []
mainFrame.pack_forget()
deckSelectFrame = Tkinter.Frame(mainWindow)
deckSelectFrame.pack(expand=Tkinter.YES,fill=Tkinter.BOTH)
deckSelectCanvas = Tkinter.Canvas(deckSelectFrame,background = TABLE)
deckSelectCanvas.pack(expand=Tkinter.YES,fill=Tkinter.BOTH)
if (deckSelectCanvas.winfo_width() == 1): # the canvas isn't drawn yet
mainWindow.wait_visibility(deckSelectCanvas) # wait for the canvas to show up
for gif in glob("*????.gif"):
backFile.append(gif)
total = len(backFile)
for i in range (0,len(backFile)):
backImage.append(Tkinter.PhotoImage(file=backFile[i]))
xpos = (i % int(ceil(sqrt(total)))) * 100 + 50
ypos = (i / int(ceil(sqrt(total)))) * 120 + 60
imagePosition.append([xpos,ypos])
deckSelectCanvas.create_image(xpos,ypos,image = backImage[i])
deckSelectCanvas.config(width=(int(ceil(sqrt(total))) * 100),height=(int(ceil(total / (ceil(sqrt(total))))) * 120))
deckSelectCanvas.bind("<1>",chooseDeck)
def chooseDeck(event):
global cardBack
for i in range (0,len(imagePosition)):
if (abs(event.x - imagePosition[i][0]) <= 37) and (abs(event.y - imagePosition[i][1]) <= 45):
optionsMenu.entryconfig(1,state='normal')
cardBack = backFile[i]
deckSelectFrame.destroy()
mainFrame.pack(side = Tkinter.TOP,expand = Tkinter.YES,fill = Tkinter.BOTH)
writeCFG()
try:
refresh()
except (IndexError,NameError):
pass
# ------- End Menu Commands ------------------------------------------
def initField():
global mainFrame
global scoreField
global funcField
global numPlayers
global gameField
mainFrame = Tkinter.Frame(mainWindow)
mainFrame.pack(side = Tkinter.TOP,expand = Tkinter.YES,fill = Tkinter.BOTH)
SubFrame = [Tkinter.Frame(mainFrame),Tkinter.Frame(mainFrame)]
SubFrame[0].pack(side = Tkinter.TOP,expand = Tkinter.YES,fill = Tkinter.BOTH)
SubFrame[1].pack(side = Tkinter.TOP,expand = Tkinter.YES,fill = Tkinter.BOTH)
scoreField = Tkinter.Canvas(SubFrame[0],width = 190, height = 250,background = WHITE)
scoreField.pack(side = Tkinter.LEFT,expand = Tkinter.YES, fill = Tkinter.BOTH)
gameField = []
for gf in range (0,numPlayers + 1):
gameField.append(Tkinter.Canvas(SubFrame[min(1,numPlayers-gf)],width = 160,height = 250,background = TABLE))
gameField[gf].pack(side = Tkinter.LEFT,expand = Tkinter.YES,fill = Tkinter.BOTH)
funcField = Tkinter.Canvas(SubFrame[0],width = 190,height = 250,background = WHITE)
funcField.pack(side = Tkinter.RIGHT,expand = Tkinter.YES, fill = Tkinter.BOTH)
refreshFunds()
def initGame():
global numPlayers
global mainWindow
global playerName
global playerFunds
global playerBet
numPlayers = 0
# Let's see who's playing
#DialogWin = Tkinter.Tk()
#DialogWin.title("Question")
#PlayerDialog = Tkinter.Canvas(DialogWin)
#PlayerDialog.create_text(10,10,text ="How many players do we have here?")
#p = Tkinter.IntVar()
#P1 = Tkinter.Radiobutton(PlayerDialog,variable = p,text = "1",value = 1)
#P2 = Tkinter.Radiobutton(PlayerDialog,variable = p,text = "2",value = 2)
#P3 = Tkinter.Radiobutton(PlayerDialog,variable = p,text = "3",value = 3)
#P4 = Tkinter.Radiobutton(PlayerDialog,variable = p,text = "4",value = 4)
#Go = Tkinter.Button(PlayerDialog,command = NumberOfPlayerSelect,text = "Go!")
#P1.pack(side = Tkinter.LEFT)
#P2.pack(side = Tkinter.LEFT)
#P3.pack(side = Tkinter.LEFT)
#P4.pack(side = Tkinter.LEFT)
#Go.pack(side = Tkinter.LEFT)
#mainWindow.wait_window(DialogWin)
# Since that doesn't appear to be working correctly,
# we'll use this for now.
p = tkSimpleDialog.askinteger("Question","How Many Players?",minvalue=1,maxvalue=MAXPLAYERS,parent=mainWindow)
numPlayers = p
if (numPlayers < 1) or (numPlayers > MAXPLAYERS):
numPlayers = 1
for x in range (1,numPlayers + 1):
pn = tkSimpleDialog.askstring("Question","Who is player " + `x` + "?",parent = mainWindow)
if not (pn):
pn = 'Player ' + `x`
playerName.append(pn)
playerFunds.append(startingFunds)
playerBet.append(startingFunds / 2)
playerFunds.append(startingFunds)
def refresh():
global mainWindow
global showDownCard
global gameField
global playerHand
global dealerHand
global CardImage
global TempCardImage
calcPoints()
pointDisplay = []
CardImage = []
for player in range (0,numPlayers+1):
# I keep getting a 'Too early to create image' error,
# so I am adding the following line to slow things down
# a bit. Hopefully this will solve the problem.
# It should also ensure that the cards are drawn in the
# right place on the gameboard by waiting until the canvas
# is drawn before it checks the width.
if (gameField[player].winfo_width() == 1): # the canvas isn't drawn yet
mainWindow.wait_visibility(gameField[player]) # wait for the canvas to show up
gameField[player].delete('all')
midField = gameField[player].winfo_width() / 2
if (player < numPlayers):
gameField[player].create_text(midField,80,text=playerName[player],font=mainFont)
gameField[player].create_text(midField,105,text="Bet: " + `playerBet[player]`,font=mainFont)
gameField[player].create_text(midField,130,text="--" + str(playerPoints[player]) + "--",font=mainFont)
else:
gameField[player].create_text(midField,50,text="Dealer",font=mainFont)
gameField[player].create_text(midField,75,text="Hits on 16",font=subFont)
gameField[player].create_text(midField,90,text="Stands on 17",font=subFont)
if (showDownCard):
gameField[player].create_text(midField,115,text="--" + str(dealerPoints) + "--",font=mainFont)
TempCardImage = []
if (player == numPlayers):
numCards = len(dealerHand)
for x in range (0,numCards):
if not (showDownCard) and (x):
TempCardImage.append(Tkinter.PhotoImage(file = cardBack))
else:
TempCardImage.append(Tkinter.PhotoImage(file = dealerHand[x][1][0].lower() + str(dealerHand[x][0]).lower() + '.gif'))
else:
numCards = len(playerHand[player])
for x in range (0,numCards):
TempCardImage.append(Tkinter.PhotoImage(file = playerHand[player][x][1][0].lower() + str(playerHand[player][x][0]).lower() + '.gif'))
CardImage.append(TempCardImage)
for y in range (0,numCards):
Xplacement = int((midField / 6.0) * (6.5 - numCards / 2.0 + y))
gameField[player].create_image(Xplacement,200,image = CardImage[player][y])
def refreshFunds():
global scoreField
global mainWindow
global numPlayers
global scoreField
if(scoreField.winfo_width() == 1):
mainWindow.wait_visibility(scoreField)
scoreField.delete('all')
midField = scoreField.winfo_width() / 2
scoreField.create_text(midField,25,text='Player Funds',font = mainFont)
for x in range (0,numPlayers):
scoreField.create_text(midField,30 * x + 55,text=playerName[x] + ': ' + `playerFunds[x]`,font = mainFont)
def shuffleDeck():
global cardPointer
global cards
cardPointer = 0 # set the card pointer to the top card
shuffle(cards)
def dealCards(): # gee, I wonder what this does
global showDownCard
global numPlayers
global cardPointer
global dealerHand
global playerHand
showDownCard = 0
dealerHand = []
playerHand = []
# distribute the cards to start the round
dealerHand.append(cards[numPlayers + cardPointer])
dealerHand.append(cards[numPlayers * 2 + cardPointer + 1])
for x in range (0,numPlayers):
playerHand.append([cards[x + cardPointer],cards[numPlayers + x + cardPointer + 1]])
# set the card pointer to the first card that hasn't been dealt
cardPointer += 2 * (numPlayers + 1)
def hitMe(player): # hit me baby, one more time!
global cardPointer
global playerHand
# a player can only have 5 cards in blackjack, so:--\
if (len(playerHand[player]) < 5): # <----------------/
playerHand[player].append(cards[cardPointer])
cardPointer+=1 # next card
def hitDealer(): # givin' the dog a bone
global cardPointer
global dealerHand
#-a player can only have 5 cards in blackjack, so:--\
if (len(dealerHand) < 5): # <-----------------------/
dealerHand.append(cards[cardPointer])
cardPointer+=1 #next card
def calcPoints(): # caclulates each player's (and dealer) points
global dealerPoints
global playerPoints
global playerHand
global dealerHand
playerPoints = []
dealerPoints = 0
for x in range (0,numPlayers):# for each player
z = 0 # reset total
for y in range(0,5): # totalling the player card values
if (y < len(playerHand[x])):
if (playerHand[x][y][0] <= 10):
z += playerHand[x][y][0]
else:
z += cardValue[playerHand[x][y][0]]
for y in range(0,5):
if (z > 21) and (y < len(playerHand[x])) and (playerHand[x][y][0] == 'A'):
z-=10
if (z > 21):
z = 'BUST'
elif (z == 21) and (len(playerHand[x]) == 2):
z = 'BLACKJACK'
elif (len(playerHand[x]) == 5):
z = '5 CARD'
playerPoints.append(z)
z = 0 # reset total
for y in range(0,5): # totalling the dealer card values
if (y < len(dealerHand)):
if (dealerHand[y][0] <= 10):
z += dealerHand[y][0]
else:
z += cardValue[dealerHand[y][0]]
# Remember an Ace can be 11 or 1
for y in range(0,5):
if (z > 21) and (y < len(dealerHand)) and (dealerHand[y][0] == 'A'):
z-=10
if (z > 21):
z = 'BUST'
if (z == 21) and (len(dealerHand) == 2):
z = 'BLACKJACK'
dealerPoints = z
def playHand():
global mainWindow
global numPlayers
global gameField
global showDownCard
global playerWinLoss
global hs
playerWinLoss = []
if (cardPointer > (52 - (numPlayers + 1) * 5)):
# only if there are not enough cards to be sure you will have enough
shuffleDeck()
dealCards()
calcPoints()
refresh()
for x in range (0,numPlayers):
gameField[x].config(background = HIGHLIGHT) # highlight the current player
hs = 'first'
while (hs != 'stand') and (playerPoints[x] != 'BUST') and (len(playerHand[x]) < 5):
functions('HitStand',x)
mainWindow.wait_window(hitButton)
if (hs == 'hit'):
hitMe(x)
refresh()
gameField[x].config(background = TABLE) #put it back to regular green
showDownCard = 1
while (dealerPoints < 17) and (len(dealerHand) < 5):
hitDealer()
calcPoints() # so the dealer doesn't keep hitting
#refresh()
for x in range (0,numPlayers):
playerWinLoss.append(WinLoss(x))
calcFunds()
refresh()
def functions(which,i=''):
global mainWindow
global funcField
global numPlayers
global hitButton
global standButton
global dealButton
global betScale
global playerFunds
if (funcField.winfo_width() == 1):
mainWindow.wait_visibility(funcField)
midField = funcField.winfo_width() / 2
if (which == 'HitStand'): # Create the 'hit or stand' buttons
funcField.create_text(midField,50,text = playerName[i],font = mainFont)
hitButton = Tkinter.Button(text = 'Hit Me!',command = hit,font = buttonFont)
standButton = Tkinter.Button(text = 'Stand',command = stand,font = buttonFont)
funcField.create_window(midField,125,window = hitButton)
funcField.create_window(midField,200,window = standButton)
if (which == 'PlaceBet'): #Create the bet scales
betScale = []
funcField.create_text(midField,50,text = 'Place', font = mainFont)
funcField.create_text(midField,75,text = 'Your', font = mainFont)
funcField.create_text(midField,100,text = 'Bet', font = mainFont)
for x in range (0,numPlayers):
betScale.append(Tkinter.Scale(gameField[x],orient = Tkinter.HORIZONTAL,from_=25,to=playerFunds[x],relief = Tkinter.RAISED,length=gameField[x].winfo_width()-20,sliderlength=20,resolution=25))
#funcField.create_window(midField,40 * x + 55,window = betScale[x])
#funcField.create_window(60 * x + 30,110,window = betScale[x])
gameField[x].create_window(gameField[x].winfo_width()/2,35,window = betScale[x])
betScale[x].set(min(playerBet[x],playerFunds[x]))
dealButton = Tkinter.Button(text = 'Deal!',command = finishBets,font = buttonFont)
funcField.create_window(midField,175,window = dealButton)
def finishBets():
global numPlayers
global dealButton
global funcField
global betScale
global playerBet
playerBet = []
for x in range (0,numPlayers):
playerBet.append(betScale[x].get())
playerFunds[x] -= playerBet[x]
dealButton.destroy()
funcField.delete('all')
def hit():
global hitButton
global standButton
global funcField
global hs
hs = 'hit'
hitButton.destroy()
standButton.destroy()
funcField.delete('all')
def stand():
global standButton
global hitButton
global funcField
global hs
hs = 'stand'
hitButton.destroy()
standButton.destroy()
funcField.delete('all')
def WinLoss(player):
global dealerPoints
global playerPoints
# if playerPoints and dealerPoints are a score,
# not a word, compare the scores.
if (playerPoints[player] <= 21) and (dealerPoints <= 21):
if (playerPoints[player] > dealerPoints):
return 'WIN'
elif (playerPoints[player] < dealerPoints):
return 'LOSE'
else:
return 'TIE'
# if one or both of them are not scores, follow these rules.
else:
if (playerPoints[player] == 'BUST'):
return 'LOSE'
elif (dealerPoints == 'BUST'):
return 'WIN'
elif (playerPoints[player] == 'BLACKJACK') and (dealerPoints != 'BLACKJACK'):
return 'WIN'
elif (playerPoints[player] != 'BLACKJACK') and (dealerPoints == 'BLACKJACK'):
return 'LOSE'
elif (playerPoints[player] == '5 CARD') and (dealerPoints != '5 CARD'):
return 'WIN'
elif (playerPoints[player] != '5 CARD') and dealerPoints == ('5 CARD'):
return 'LOSE'
else:
return 'TIE'
def placeBets():
global mainWindow
global dealButton
functions('PlaceBet')
mainWindow.wait_window(dealButton)
refreshFunds()
def calcFunds():
global numPlayers
playerBroke = 0
for x in range (0,numPlayers):
if (playerWinLoss[x] == 'WIN') and (playerPoints[x] == 'BLACKJACK'):
# payout is 3 to 2 for a Blackjack win
playerFunds[x] = playerFunds[x] + ((playerBet[x] * 5 + 1 )/ 2)
elif (playerWinLoss[x] == 'WIN'): # if they win, they win!
playerFunds[x] = playerFunds[x] + (playerBet[x] * 2)
elif (playerWinLoss[x] == 'TIE'): # if they tie, give back the money!
playerFunds[x] += playerBet[x]
if (playerFunds[x] < 25):
playerBroke = 1
refreshFunds()
if (playerBroke): # if you ain't got no money, you can't play!
elimPlayer() # somebody's outta dough, kick'em out!
def elimPlayer():
global numPlayers
global mainFrame
global playerName
global playerFunds
global playerHand
global playerWinLoss
global playerPoints
global playerBet
x = 0
# check to see which players are broke,
# and delete them.
while (x < len(playerName)):
if (playerFunds[x] < 25):
tkMessageBox.showinfo('Message',playerName[x] + ' is out of money!!')
del playerName[x]
del playerFunds[x]
del playerHand[x]
del playerWinLoss[x]
del playerPoints[x]
del playerBet[x]
numPlayers -= 1
else:
x += 1
mainFrame.destroy()
initField()
def readCFG(): # Read settings from CONFIGFILE
global startingFunds
global cardBack
if not os.path.exists(CONFIGFILE):
return 1
conf = open(CONFIGFILE,"r")
conf.seek(0,2)
eof = conf.tell()
option = ''
conf.seek(0,0)
while not (option == "[Starting Funds]"):
option = conf.readline().strip()
if (conf.tell() == eof):
conf.close()
return 1
startingFunds = int(conf.readline().strip())
conf.seek(0,0)
while not (option == "[Deck]"):
option = conf.readline().strip()
if (conf.tell() == eof):
conf.close()
return 1
cardBack = conf.readline().strip()
conf.close()
if not os.path.exists(cardBack):
return 1
return 0
def writeCFG():
conf = open(CONFIGFILE,"w")
conf.write("[Starting Funds]\n" + str(startingFunds) + "\n\n")
conf.write ("[Deck]\n" + str(cardBack) + "\n\n")
conf.close()
def bindKeys():
mainWindow.bind_all("<F2>",fmNewGame)
mainWindow.bind_all("<Control-x>",close)
mainWindow.protocol('WM_DELETE_WINDOW',close)
if __name__ == "__main__":
try:
firstGame() #start a game
except Tkinter.TclError:
print "Thank You For Playing!"