Please review my game. I am learning Python now, so any suggestions are welcome. I am running this on a Linux machine, in Komodo and terminal.
#!/usr/bin/python
#encoding=utf8
import random
# init global variables used for game
player = []
dealer = []
class Deck(object):
def __init__(self,rank=[], suit=[], whole_deck=[], scrambled_deck=[]):
self.rank = ['1','2','3','4','5','6','7','8','9','J','Q','K','A']
self.suit = ['♠','♣','♥','♦︎︎']
self.whole_deck = whole_deck
self.scrambled_deck = scrambled_deck
#construct deck from existing attributes
def makedeck(self):
self.whole_deck = []
i=0
while i < 4:
for r in self.rank:
self.whole_deck.append(r+self.suit[i])
i += 1
return self.whole_deck
self.whole_deck = makedeck(self)
def draw_a_card(self):
d=self.whole_deck.pop(random.choice(range(len(self.whole_deck))))
return d
class Game(Deck):
def __init__(self,credit=100, bet=10):
Deck.__init__(self)
self.credit = credit
self.bet = bet
def getcredit(self):
while True:
try:
self.credit = int(raw_input("How many chips would you like to buy? "))
except:
print "You need to specify number"
continue
else:
print str(self.credit) + ' Chips Purchased'
print "Have fun!"
break
return self.credit
def makebet(self):
while True:
try:
self.bet = int(raw_input("How much do you want to bet? "))
except:
print "You need to specify number"
continue
if self.bet > self.credit:
print 'You can\'t bet more than you have credit'
continue
else:
print 'You are betting ' + str(self.bet)
break
def deal(self, p_turn=0, d_turn=0):
global dealer
global player
i = 0
j = 0
while i < p_turn:
player.append(g.draw_a_card())
i += 1
while j < d_turn:
dealer.append(g.draw_a_card())
j += 1
def clear_screen():
print '\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n'
####################Construct Cards####################
def makecard(dealer, player, hidden=0):
card = ['╔═══════╗\t','║ {} ║\t','║ ║\t','║ {} ║\t','║ ║\t','║ {} ║\t','╚═══════╝\t']
h_card = ['╔═══════╗\t','║▓▓▓▓▓▓▓║\t' ,'║▒▒▒▒▒▒▒║\t','║▓▓▓▓▓▓▓║\t' ,'║▒▒▒▒▒▒▒║\t','║▓▓▓▓▓▓▓║\t' ,'╚═══════╝\t']
global player_cards
player_cards = ['' for i in player]
c=0
p=0
while p < len(player):
for c in range(0, len(card)):
alter = [1,0,0,1,0,0,1]
current_card=[player[p][:1], player[p][1:]]
player_cards[p] += str(card[c]).format(current_card[alter[c]])
player_cards[p] = player_cards[p].split("\t")
p += 1
global dealer_cards
dealer_cards = ['' for i in dealer]
c=0
p=0
while p < len(dealer):
for c in range(0, len(card)):
alter = [1,0,0,1,0,0,1]
current_card=[dealer[p][:1], dealer[p][1:]]
dealer_cards[p] += str(card[c]).format(current_card[alter[c]])
dealer_cards[p] = dealer_cards[p].split("\t")
p += 1
if hidden == 1:
dealer_cards[1]=''.join(h_card)
dealer_cards[1] = dealer_cards[1].split("\t")
def printcards(dealer_cards, player_cards):
for i in range(len(dealer_cards[0])):
for j in range(len(dealer_cards)):
print '{}'.format(dealer_cards[j][i]),
print
for i in range(len(player_cards[0])):
for j in range(len(player_cards)):
print '{}'.format(player_cards[j][i]),
print
####################Construct Cards END####################
def makerank(who):
i=0
player_rank = []
while i < len(who):
player_rank.append(who[i][0])
for ii in player_rank:
player_rank = [10 if ii=='K' or ii=='Q' or ii=='J' else ii for ii in player_rank]
for ii in player_rank:
if ii == 'A':
tmp_suit = player_rank.pop()
# tmp_suit = player_rank.pop(player_rank.index(ii))
if sum([ int(x) for x in player_rank]) <= 10:
tmp_suit = 11
player_rank.append(tmp_suit)
elif sum([ int(x) for x in player_rank]) > 10:
tmp_suit = 1
player_rank.append(tmp_suit)
i += 1
player_rank = [ int(x) for x in player_rank ]
return sum(player_rank)
def newdeck(mindecksize):
d = Deck()
if len(g.whole_deck) < mindecksize:
g.whole_deck = d.whole_deck
def cards(z):
if z == 0:
makecard(dealer, player, 0)
printcards(dealer_cards, player_cards)
elif z == 1:
makecard(dealer, player, 1)
printcards(dealer_cards, player_cards)
def winlose(who):
if who == 'p':
g.credit = g.credit + g.bet
print 'You win!'
print 'Your credit is: ' + str(g.credit)
elif who == 'd':
g.credit = g.credit - g.bet
print 'Dealer wins!'
print 'Your credit is: ' + str(g.credit)
elif who == 'dr':
print 'Push'
print 'Your credit is: ' + str(g.credit)
def dealerplay():
while makerank(dealer) < 17:
g.deal(0,1)
#Debug functions, can be removed at any time
def debug_printset():
i=0
while i < len(player):
print player[i]
i += 1
# Functions end here
g = Game()
def play():
d = Deck()
global g
global player
global dealer
i = 0
clear_screen()
g.getcredit()
while True: #Whole game loop
player = []
dealer = []
g.deal(2,2)
i += 1
clear_screen()
g.makebet()
cards(1)
newdeck(5)
#########################Is it blackjack?#########################
if makerank(player) == 21:
if i == 1 and makerank(dealer) != 21:
print 'Blackjack!'
winlose('p')
break
elif i == 1 and makerank(dealer) == 21:
winlose('dr')
break
#########################Is it blackjack? END#########################
while True: #hand loop
player_input = str(raw_input("Press 'h' to hit, or 's' to stand \n"))
if player_input == 'h':
newdeck(1)
g.deal(1)
if makerank(player) > 21:
clear_screen()
cards(0)
print 'Busted!'
winlose('d')
break
elif makerank(player) < 21:
clear_screen()
cards(1)
continue
elif makerank(player) == 21:
clear_screen()
cards(0)
dealerplay()
if makerank(dealer) == 21:
winlose('dr')
break
elif makerank(dealer) < 21:
winlose('p')
break
elif player_input == 's':
dealerplay()
clear_screen()
cards(0)
if makerank(dealer) > 21:
winlose('p')
break
elif makerank(dealer) > makerank(player):
winlose('d')
break
elif makerank(dealer) < makerank(player):
winlose('p')
break
elif makerank(dealer) == makerank(player):
winlose('dr')
break
###############Gameover?####################
if g.credit == 0:
print "Game Over"
exit()
###############Play again?##################
while True:
print len(g.whole_deck)
print 'press \'d\' to deal again, or \'c\' to close'
deal = str(raw_input())
if deal == 'd':
i -= 1
break
elif deal == 'c':
print 'Game ended. Your remaining credit is: ' + str(g.credit)
exit()
else:
print "Incorrect input, please input 'd' to Deal again, 'c' to close the game"
continue
###############Play again? END##################
play()
-
\$\begingroup\$ This is the coolest freaking thing I've ever seen in my life. \$\endgroup\$papasmurf– papasmurf2016年11月29日 12:39:54 +00:00Commented Nov 29, 2016 at 12:39
2 Answers 2
In general, I think you did a good job overall. That is, getting the game logic to run without serious issue. There were a couple of errors that caused the game to not run correctly. One was if the player
gets a blackjack the game exits without prompting the user for further action:
LOGIC
while True: #Whole game loop
player = []
dealer = []
.....
if makerank(player) == 21:
if i == 1 and makerank(dealer) != 21:
print 'Blackjack!'
winlose('p')
break
elif i == 1 and makerank(dealer) == 21:
winlose('dr')
break
while True: #hand loop
..........
I shortened the code up here but you can see since you do your check outside of "hand-loop" and call break
you will exit the program. This goes for if there is a push on blackjack too.
Exhausting the deck
, where you only reset the deck if the player hits. This is because of how you are drawing cards by calling .pop
.
.....
if player_input == 'h':
newdeck(1)
.....
def draw_a_card(self):
d=self.whole_deck.pop(random.choice(range(len(self.whole_deck))))
return d
If you keep standing on every turn you will eventually get an IndexError
. You could just call random.choice
on the deck and not have to worry about it while using some other condition to reset the deck
:
def draw_a_card(self):
return random.choice(self.whole_deck)
STYLE
There are some style issues here too. These usually come down to personal preferences but if you are having others read your code its best to stay close to pep8 which is a general consesus for helpful style choices.
OOP
You also make use of global
variables quite a bit. Usually using global
s are considered bad practice. What you could do is think about where each one of these functions and variables would logically make sense to be grouped together. Then create a class to encapsulate the variables and functions, adhering to good OOP principles. You do this to a certain degree but you could further it by adding in the global
s too:
class Game(Deck):
def __init__(self,credit=100, bet=10):
Deck.__init__(self)
self.credit = credit
self.bet = bet
# make an attribute for hands
self.player = []
self.dealer = []
CODE DUPLICATION
You also have several spots of code duplication. Keeping with DRY (don't repeat yourself) you could use a loop or recursion to cut down on some of this:
def printcards(dealer_cards, player_cards):
for i in range(len(dealer_cards[0])):
for j in range(len(dealer_cards)):
print '{}'.format(dealer_cards[j][i]),
print
for i in range(len(player_cards[0])):
for j in range(len(player_cards)):
print '{}'.format(player_cards[j][i]),
print
Where you could pass in a list
or any other kind of iterable
and loop for them:
def printcards(hands): # where hands have both player and dealer cards
for hand in hands:
for i in range(len(hand[0]):
.....
There are places where you are using counters too where iterating over the list itself or a range would be fine:
p=0
...
while p < len(dealer):
for c in range(0, len(card)):
alter = [1,0,0,1,0,0,1]
current_card=[dealer[p][:1], dealer[p][1:]]
dealer_cards[p] += str(card[c]).format(current_card[alter[c]])
dealer_cards[p] = dealer_cards[p].split("\t")
p += 1
would be:
for p in range(len(dealer)):
for c in range(0, len(card)):
alter = [1,0,0,1,0,0,1]
current_card=[dealer[p][:1], dealer[p][1:]]
dealer_cards[p] += str(card[c]).format(current_card[alter[c]])
dealer_cards[p] = dealer_cards[p].split("\t")
STANDARD LIBRARY
One of the great things about Python is that there are a rich collection of libraries/modules already made by really intelligent people. Use this to your advantage and get to know different modules and what they offer:
self.whole_deck = []
i=0
while i < 4:
for r in self.rank:
self.whole_deck.append(r+self.suit[i])
i += 1
becomes:
from itertools import product
.....
return [''.join(c) for c in product(self.rank, self.suit)]
Where you can use itertools.product
to create a cartesian product
I re-wrote your program by creating a different game-loop and making a couple of different classes:
#!/usr/bin/python
#encoding=utf8
import random
card = ['╔═══════╗\t',
'║ {} ║\t',
'║ ║\t',
'║ {} ║\t',
'║ ║\t',
'║ {} ║\t',
'╚═══════╝\t'
]
h_card = ['╔═══════╗\t',
'║▓▓▓▓▓▓▓║\t',
'║▒▒▒▒▒▒▒║\t',
'║▓▓▓▓▓▓▓║\t',
'║▒▒▒▒▒▒▒║\t',
'║▓▓▓▓▓▓▓║\t',
'╚═══════╝\t'
]
def make_rank(hand):
hand_rank = 0
hand_str = ''.join(card[0] for card in hand)
for card in hand_str:
if card.isdigit():
hand_rank += int(card)
else:
hand_rank += 10 if card in 'KQJ' else 11
if hand_rank > 21 and 'A' in hand_str:
hand_rank -= 10
return hand_rank
def make_cards(hand, hidden=False):
cards = [''.join(card).format(*c).split('\t') for c in hand]
if hidden:
cards[1] = ''.join(h_card).split('\t')
return cards
def print_cards(hands, hidden=False):
for pos, hand in enumerate(hands):
cards = make_cards(hand, (not pos) & hidden)
for card in zip(*cards):
print(''.join(card))
print
def clear_screen(func):
def wrapper(*args, **kwargs):
print '\n' * 66
return func(*args)
return wrapper
@clear_screen
def get_credit():
while True:
try:
credit = int(raw_input("How many chips would you like to buy? "))
except:
print "You need to specify number"
continue
print '{} Chips Purchased'.format(credit)
print "Have fun!"
break
return credit
@clear_screen
def make_bet(player):
while True:
try:
bet = int(raw_input("How much do you want to bet? "))
except:
print "You need to specify number"
continue
if bet > player.credit:
print 'You can\'t bet more than you have credit'
continue
print 'You are betting {}'.format(bet)
break
player.credit -= bet
return bet
def deal_again(option=''):
if option == 'c':
return False
elif option == 'd':
return True
if option:
print 'Incorrect input, please input "d" to Deal again, "c" to close the game'
print 'press \'d\' to deal again, or \'c\' to close'
option = raw_input()
return deal_again(option)
class Deck(object):
def __init__(self,rank=[], suit=[], whole_deck=[], scrambled_deck=[]):
self.rank = ['2','3','4','5','6','7','8','9','J','Q','K','A']
self.suit = ['♠','♣','♥','♦︎︎']
self.whole_deck = whole_deck
self.scrambled_deck = scrambled_deck
def makedeck(self):
return [(r, s, r) for r in self.rank for s in self.suit]
self.whole_deck = makedeck(self)
def draw_a_card(self):
return random.choice(self.whole_deck)
class Player(object):
def __init__(self, dealer):
self.hand = []
self.credit = 0
self.dealer = dealer
class Dealer(object):
def __init__(self, bet=10):
self.deck = Deck()
self.bet = bet
self.hand = []
self.table_hands = [self.hand]
def add_player(self, player):
self.table_hands.append(player)
@property
def clear_cards(self):
self.table_hands = [[] for hand in self.table_hands]
def deal_hand(self):
self.clear_cards
self.deal(self.table_hands, 2)
def deal(self, hands, turn):
for _ in range(turn):
for hand in hands:
hand.append(self.deck.draw_a_card())
def winlose(self, who):
payout = 0
if who == 'p':
print 'You win!'
payout = self.bet * 2
elif who == 'd':
print 'Dealer wins!'
else:
print 'Push'
payout = self.bet
return payout
@clear_screen
def dealer_play(self, rank):
dealer_hand = self.table_hands[0]
if rank > 16:
return rank
self.deal([dealer_hand], 1)
rank = make_rank(dealer_hand)
print_cards(self.table_hands)
return self.dealer_play(rank)
@clear_screen
def player_play(self, rank, option=''):
player_hand = self.table_hands[1]
if option == 'h':
self.deal([player_hand], 1)
rank = make_rank(player_hand)
print_cards(self.table_hands, True)
if rank >= 21 or option == 's':
return rank
player_input = raw_input('Press "h" to hit, or "s" to stand \n')
return self.player_play(rank, player_input)
def play_hand(dealer, player):
dealer.deal_hand()
print_cards(dealer.table_hands, True)
d_rank, p_rank = map(make_rank, dealer.table_hands)
msg = ''
if p_rank == 21 or d_rank == 21:
msg = 'BlackJack!'
winner = 'p' if p_rank == 21 and d_rank != 21 else \
'd' if p_rank != 21 else 'dr'
else:
p_rank = dealer.player_play(p_rank)
if p_rank > 21:
msg = 'Bust'
winner = 'd'
else:
d_rank = dealer.dealer_play(d_rank)
if d_rank > 21 or p_rank <= 21 and d_rank < p_rank:
winner = 'p'
elif p_rank < 21 and d_rank > p_rank:
winner = 'd'
else:
winner = 'dr'
clear_screen(lambda:None)()
if msg:
print msg
player.credit += dealer.winlose(winner)
print_cards(dealer.table_hands)
print 'Your credit is: {}'.format(player.credit)
def take_seat_at_table():
dealer = Dealer()
player = Player(dealer)
PLAYING = True
player.credit = get_credit()
dealer.add_player(player.hand)
while PLAYING:
dealer.bet = make_bet(player)
play_hand(dealer, player)
if player.credit == 0:
print 'Game Over'
PLAYING = False
else:
PLAYING = deal_again()
print 'Game ended. Your remaining credit is: {}'.format(player.credit)
if __name__ == '__main__':
take_seat_at_table()
-
\$\begingroup\$ This is the best review of my work ever, school university or anything else. It's amazing that you took so much time. Thanks a lot \$\endgroup\$G.Gabunia– G.Gabunia2016年12月04日 09:54:01 +00:00Commented Dec 4, 2016 at 9:54
As noted in a similar question, the deck should be constructed using a list comprehension. There is no rank "1", but there should be a "10".
Explore related questions
See similar questions with these tags.