Python, modifying a blackjack game - python

I am in need of help with an assignment I have been given.
I have been asked to modify the section below from a blackjack game so that a dealer deals a card to each player and the highest card wins unless there is a draw.
I am unable to get the code right for this.
This is what i have in place:
for player in self.still_playing:
if player.total > self.players.total:
player.win()
elif player.total < self.players.total:
player.lose()
else:
player.push()
here is the rest of the code:
import Cards, Games
class BJ_Card(Cards.Card):
# Defines a Blackjack card
ACE_VALUE = 1
#property
def value(self):
if self.is_face_up:
val = BJ_Card.CARDS.index(self.card) + 1
if val > 10:
val = 10
else:
val = None
return val
# This object returns a number between 1 and 10,
# representing the value of a Blackjack card
class BJ_Deck(Cards.Deck):
# Defines a Blackjack deck
def populate(self):
for suit in BJ_Card.SUITS:
for card in BJ_Card.CARDS:
self.cards.append(BJ_Card(card, suit))
class BJ_Hand(Cards.Hand):
# Defines a Blackjack hand
def __init__(self, name):
super(BJ_Hand, self).__init__()
self.name = name
def __str__(self):
rep = self.name + ":\t" + super(BJ_Hand, self).__str__()
if self.total:
rep += "(" + str(self.total) + ")"
return rep
#property
def total(self):
# If a card has the value None, then total is None
for card in self.cards:
if not card.value:
return None
# Add card values
t = 0
for card in self.cards:
t += card.value
# Check if hand contains an Ace
contains_ace = False
for card in self.cards:
if card.value == BJ_Card.ACE_VALUE:
contains_ace = True
# treat Ace as 1
contains_ace = 1
return t
def is_busted(self):
return self.total > 21
class BJ_Player(BJ_Hand):
# Defines a Blackjack player
def is_hitting(self):
response = Games.askYesNo("\n" + self.name + ", do you want another
card? (Y/N): ")
return response == "y"
def bust(self):
print(self.name, "busts.")
self.lose()
def lose(self):
print(self.name, "loses.")
def win(self):
print(self.name, "wins.")
def push(self):
print(self.name, "draws.")
class BJ_Dealer(BJ_Hand):
# Defines a Blackjack dealer
def is_hitting(self):
return self.total < 17
def bust(self):
print(self.name, "busts.")
def flip_first_card(self):
first_card = self.cards[0]
first_card.flip()
class BJ_Game(object):
# Defines a Blackjack game
def __init__(self, names):
self.players = []
for name in names:
player = BJ_Player(name)
self.players.append(player)
self.dealer = BJ_Dealer("Dealer")
self.deck = BJ_Deck()
self.deck.populate()
self.deck.shuffle()
#property
def still_playing(self):
sp = []
for player in self.players:
if not player.is_busted():
sp.append(player)
return sp
def __additional_cards(self, player):
while not player.is_busted() and player.is_hitting():
self.deck.deal([player])
print(player)
if player.is_busted():
player.bust()
def play(self):
# Deal initial 1 card to all players
self.deck.deal(self.players, per_hand = 1)
for player in self.players:
print(player)
for player in self.still_playing:
if player.total > self.players.total:
player.win()
elif player.total < self.players.total:
player.lose()
else:
player.push()
# Remove everyone's cards
for player in self.players:
player.clear()
def main():
print("\nWelcome to the Python Blackjack game.\n")
names = []
number = Games.askForNumber("How many players? (2-7): ", low = 2, high =
8)
print()
i = 1
for i in range(number):
name = input("Enter player name: ")
if name == "":
names.append("Anon")
print()
i += 1
else:
names.append(name)
print()
i += 1
game = BJ_Game(names)
again = "Y"
while again == "y" or again == "Y":
game.play()
again = Games.askYesNo("\nDo you want to play again?: ")
main()

self.players
is a list of BJ_Player classes / objects. You're calling self.players.total i.e trying to get the property total of a python list which does not exist as this is not a property of a list. I assume you're trying to do something more like;
for player in self.players:
print(player.total)
this way you would be accessing each players total. However, the class BJ_Player does not appear to have a total property either, so you will need to add this to the class and then use a loop like the one given above.

Related

Why is my code printing out the same thing over and over again?

import random
from time import sleep
def wait():
#sleep(0.5)
print()
p1_discards = []
p2_discards = []
p1_card = []
p2_card = []
class Card():
def __init__(self, value, name, suit):
self.value = value
self.name = name
self.suit = suit
def __lt__(self, other):
return self.value < other.value
def __gt__(self, other):
return self.value > other.value
def __eq__(self, other):
return self.value == other.value
def __str__(self):
return f'{self.name} of {self.suit}'
def create_deck():
deck = []
suits = ("Clubs","Spades","Hearts","Diamonds")
ranks = ("2","3","4","5","6","7","8","9","10","Jack","Queen","King","Ace")
for s in suits:
for i,r in enumerate(ranks):
deck.append(Card(i+1,r,s))
return deck
def find_winner(card1, card2):
if card1 > card2:
p1_discards.append(card2)
p1_discards.append(card1)
return p1_name
if card1 < card2:
p2_discards.append(card1)
p2_discards.append(card2)
return p2_name
else:
p1_discards.append(card1)
p2_discards.append(card2)
return "No one wins"
def main():
global p1_name, p2_name
p1_name = input("Enter player one's name: ")
p2_name = input("Enter player two's name: ")
deck = create_deck()
random.shuffle(deck)
while len(deck) > 0:
p1_card.append(deck.pop())
p1_draw = p1_card.pop()
p2_card.append(deck.pop())
p2_draw = p2_card.pop()
winner = find_winner(p1_draw, p2_draw)
print(f"{p1_name} draws a {p1_draw}")
print(f"{p2_name} draws a {p2_draw}")
print(f"{winner} wins")
input("Press enter to play again")
print('test1')
wait()
while len(p1_discards) > 1 and len(p2_discards) > 1:
if len(p1_discards) == 0:
print(f"{p1_name} has no cards left!")
if len(p2_discards) == 0:
print(f"{p2_name} has no cards left!")
print('test2')
p1_card.append(p1_discards.pop())
p1_draw = p1_card.pop()
p2_card.append(p2_discards.pop())
p2_draw = p2_card.pop()
winner = find_winner(p1_draw, p2_draw)
print(f"{p1_name} draws a {p1_draw}")
print(f"{p2_name} draws a {p2_draw}")
print(f"{winner} wins")
input("Press enter to play again")
wait()
if __name__ == '__main__':
main()
In the second while loop, the same card gets shown to the player over and over again. I'm not sure why this is the case and I would like help. The first while loop goes by without problems, but when the code reaches the second while loop, it starts to print the same thing over and over. I have used print commmands to ensure that the issue lies within only the second while loop, not the first.
I tried to make new variables and lists, but nothing worked and it just kept printing the same thing over and over without fixing anything.

Why is my card deck adding more cards in a sequence the more you draw in a loop?

I'm trying to make a deck of cards, and it's' gone very good for the most part. I'm stuck right now because when I try to draw a card, it adds a card every time. For example, during the third loop of drawing cards, I ask to draw three. It actually gives me information for five cards. Please help if you can.
Here's my code:
class Card:
def __init__(self, direction, arrows):
self.direction = direction
self.arrows = arrows
def show(self):
print("This card has", self.arrows, self.direction, "facing arrows.")
class Deck:
def __init__(self):
self.cards = []
self.build()
def build(self):
for d in ["north", "east", "south", "west"]:
for a in range(1, 4):
self.cards.append(Card(d, a))
def show(self):
for c in self.cards:
c.show()
def shuffle(self):
for i in range(len(self.cards) - 1, 0, -1):
r = random.randint(0, i)
self.cards[i], self.cards[r], = self.cards[r], self.cards[i]
def drawCard(self):
return self.cards.pop()
class Player:
def __init__(self, name):
self.name = name
self.hand = []
def draw(self, deck):
self.hand.append(deck.drawCard())
return self
def showHand(self):
for card in self.hand:
card.show()
cardamount = 24
while cardamount > 1:
choice = input("What do you want to do?\n")
deck = Deck()
joe = Player
if choice == "draw":
numberchoice = (int(input("How many?\n")))
if numberchoice <= cardamount:
for count in range(numberchoice):
deck.shuffle()
joe.draw(deck)
joe.showHand()
deck.shuffle()
cardamount = cardamount - 1
else:
print("NOT AN OPTION")
print("You ran out of cards.")```
for count in range(numberchoice):
deck.shuffle()
joe.draw(deck)
joe.showHand()
deck.shuffle()
cardamount = cardamount - 1
Each time through the loop, you draw one card and then show the whole hand.
So if you draw three cards, you would draw the first card and show it, then draw the second card and show both of them, then draw the third card and show all three, for a total of six cards shown.
To fix this, move showHand() outside of the draw loop.

Why is it creating a bound method and how to fix it?

When I manually call deal method it works but when under while playing it creates a bound method.
Any ideas to fix it.
import random
#Raw values
suits = ("Hearts","Diamonds","Spades","Clubs")
ranks = ("Two","Three","Four","Five","Six","Seven","Eight","Nine","Ten","Jack","Queen","King","Ace")
values = {"Two":2,"Three":3,"Four":4,"Five":5,"Six":6,"Seven":7,"Eight":8,"Nine":9,"Ten":10,"Jack":10,"Queen":10,"King":10,"Ace":11}
playing = True
Classes are defined here
#Define classes
class Card:
def __init__(self,suit,rank):
self.suit = suit
self.rank = rank
def __str__(self):
return self.rank + " of " + self.suit
class Deck:
def __init__(self):
self.deck = []
for suit in suits:
for rank in ranks:
self.deck.append(Card(suit,rank))
def __str__(self):
deck_comp = ""
for card in self.deck:
deck_comp += " \n " + card.__str__()
return "The deck has" + deck_comp
def shuffle(self):
random.shuffle(self.deck)
def deal(self):
single_card = self.deck.pop()
return single_card
Hand class for the creating the hands for players
class Hand:
def __init__(self):
self.cards = []
self.value = 0
self.ace = 0
def add_card(self,card):
self.cards.append(card)
self.value += values[card.rank]
if card.rank == "Ace":
self.ace += 1
def adjust_for_ace(self):
while self.value >21 and self.ace>0:
self.value -= 10
self.ace -= 1
Functions are made here
#Functions to use during play
def Take_bet(chips):
while True:
try:
chips.bet = int(input("Enter your bet:"))
except ValueError:
print("Bet must be in integer form")
else:
if chips.bet>chips.chip:
print("Bet is outside ",chips.chip)
else:
break
Hit function is mainly creating the bound method problem
def Hit(deck,hand):
hand.add_card(deck.deal)
hand.adjust_for_ace()
def Hit_or_stand(deck,hand):
global playing
while True:
x = input("Would you like hit or stand(enter 'h' or 's'):")
if x[0].lower()=='h':
Hit(deck,hand)
elif x[0].lower()=='s':
playing = False
else:
print("Please try again.")
continue
break
while True:
print("Welcome to Blackjack! Get as close to 21 as possible without going over\n The dealer hits until it reaches 17.Aces count as 1 or 11")
deck = Deck()
deck.shuffle()
Manually calling the deal method successfully creates an instance of card class
player_hand = Hand()
player_hand.add_card(deck.deal())
player_hand.add_card(deck.deal())
dealer_hand = Hand()
dealer_hand.add_card(deck.deal())
dealer_hand.add_card(deck.deal())
player_chips = Chips()
Take_bet(player_chips)
show_some(player_hand,dealer_hand)
while playing:
'''
card instance creates a bound method
'''
Hit_or_stand(deck,player_hand)
show_some(player_hand,dealer_hand)
The issue is in the Hit function, you are trying to add a card to a hand but are passing the method deck.deal rather than the result of a call to deck.deal()
def Hit(deck,hand):
hand.add_card(deck.deal()) # <- here
hand.adjust_for_ace()

How to use have only one instance of a class in python

I can already tell that this question will be disliked and probably answered really quickly. Id like to preface this by letting you know that i have research this, but cant comprehend what to do.
So i have a python script that creates a game of cards. The card game in mind is 3's. A game that only (to my knowledge) my family knows how to play.
My script thus far is:
import math
import random
from itertools import product
def start_game():
print ("Game started")
deck = Deck()
deck.current_turn = random.randint(1,2)
print ("Player " + str(deck.current_turn) + " will go first.")
Round_Start()
def Round_Start():
deck = Deck()
p1down = Player1Down()
p2down = Player2Down()
p1up = Player1Up()
p2up = Player2Up()
if p1down.hidden == True:
print("P1: " + " - ".join(map(str,p1up.cards)))
print("P1: #/# - #/# - #/#")
else:
print("P1: " + " - ".join(map(str,p1up.cards)))
print("P1: " + " - ".join(map(str,p1down.cards)))
if p2down.hidden == True:
print("P2: " + " - ".join(map(str,p2up.cards)))
print("P2: #/# - #/# - #/#")
else:
print("P2: " + " - ".join(map(str,p2up.cards)))
print("P2: " + " - ".join(map(str,p2down.cards)))
Give_Turn()
def P1Turn():
print("It is now Player 1's turn.")
def P2Turn():
print("It is now Player 2's turn.")
def Give_Turn():
deck = Deck()
print(deck.current_turn)
if deck.current_turn == 2:
print("It is now Player 1's turn.")
P1Turn()
elif deck.current_turn == 1:
print("It is now Player 2's turn.")
P2Turn()
class Player1Down(object):
def __init__(self):
deck = Deck()
self.cards = deck.Deal(3)
self.hidden = True
class Player2Down(object):
def __init__(self):
deck = Deck()
self.cards = deck.Deal(3)
self.hidden = True
class Player1Up(object):
def __init__(self):
deck = Deck()
self.cards = deck.Deal(3)
class Player2Up(object):
def __init__(self):
deck = Deck()
self.cards = deck.Deal(3)
class Deck(object):
current_turn = 0
def __init__(self, ranks=None, suits=None):
if ranks is None:
ranks = range(2,15)
if suits is None:
suits = ["H","D","C","S"]
self.deck = []
for r in ranks:
for s in suits:
self.deck.append(Card(r,s))
def Deal(self, n):
return random.sample(self.deck,n)
class Card(object):
FACES = {11: 'J', 12: 'Q', 13: 'K', 14: 'A'}
def __init__(self, rank, suit):
self.suit = suit
self.rank = rank
def __str__(self):
value = self.FACES.get(self.rank, self.rank)
return "{0}/{1}".format(value, self.suit)
def __lt__(self, other):
return self.rank < other.rank
if __name__ == '__main__':
start_game()
Now some of the script is a direct copy paste from another users work, it was the only way i could get things to work up until this point.
My problem is that the
deck.current_turn
keeps resetting to 0. I figure this is because i have multiple instances of the Deck() class opened. But i do not know how to fix this.
My output from the current script is:
Game started
Player 2 will go first.
P1: 7/H - 9/H - J/H
P1: #/# - #/# - #/#
P2: 5/H - 3/S - 10/H
P2: #/# - #/# - #/#
0
This is my first Stack Exchange post, and I'm sorry if this is a dumb question.
The solutions proposed in comments are much better, but the quick and dirty approaches are Singleton and Borg.
The Singleton way:
class Deck(object):
_deck = None
def __new__(cls, *a, **k):
if not cls._deck:
cls._deck = object.__new__(cls, *a, **k)
return cls._deck
# and the rest as you have it above
The Borg way:
class Deck(object):
_dict = {}
def __init__(self, ranks=None, suits=None):
self.__dict__ = self._dict
# and the rest as you have it, inc. the rest of __init__
They both work. As the original inventor of Borg, I have a soft spot for it, of course, and you can still read my ancient essay about it at http://www.aleax.it/Python/5ep.html .

Blackjack game reshuffling problem-edited

I am trying to make a blackjack game where before each new round, the program checks to make sure that the deck has 7 cards per player. And if it doesn't, the deck clears, repopulates, and reshuffles. I have most of the problem down, but for some reason at the start of every deal it reshuffles the deck more than once, and I can't figure out why. Help, please.
Here's what I have so far:
(P.S. the imported cards and games modules aren't part of the problem, I'm fairly sure my problem lies in the deal() function of my BJ_Deck class.)
import cards, games
class BJ_Card(cards.Card):
""" A Blackjack Card. """
ACE_VALUE = 1
def get_value(self):
if self.is_face_up:
value = BJ_Card.RANKS.index(self.rank) + 1
if value > 10:
value = 10
else:
value = None
return value
value = property(get_value)
class BJ_Deck(cards.Deck):
""" A Blackjack Deck. """
def populate(self):
for suit in BJ_Card.SUITS:
for rank in BJ_Card.RANKS:
self.cards.append(BJ_Card(rank, suit))
def deal(self, hands, per_hand=1):
for rounds in range(per_hand):
if len(self.cards)>=7*(len(hands)):
print "Reshuffling the deck."
self.cards=[]
self.populate()
self.shuffle()
for hand in hands:
top_card=self.cards[0]
self.give(top_card, hand)
class BJ_Hand(cards.Hand):
""" A Blackjack Hand. """
def __init__(self, name):
super(BJ_Hand, self).__init__()
self.name = name
def __str__(self):
rep = self.name + ":\t" + super(BJ_Hand, self).__str__()
if self.total:
rep += "(" + str(self.total) + ")"
return rep
def get_total(self):
# if a card in the hand has value of None, then total is None
for card in self.cards:
if not card.value:
return None
# add up card values, treat each Ace as 1
total = 0
for card in self.cards:
total += card.value
# determine if hand contains an Ace
contains_ace = False
for card in self.cards:
if card.value == BJ_Card.ACE_VALUE:
contains_ace = True
# if hand contains Ace and total is low enough, treat Ace as 11
if contains_ace and total <= 11:
# add only 10 since we've already added 1 for the Ace
total += 10
return total
total = property(get_total)
def is_busted(self):
return self.total > 21
class BJ_Player(BJ_Hand):
""" A Blackjack Player. """
def is_hitting(self):
response = games.ask_yes_no("\n" + self.name + ", do you want a hit? (Y/N): ")
return response == "y"
def bust(self):
print self.name, "busts."
self.lose()
def lose(self):
print self.name, "loses."
def win(self):
print self.name, "wins."
def push(self):
print self.name, "pushes."
class BJ_Dealer(BJ_Hand):
""" A Blackjack Dealer. """
def is_hitting(self):
return self.total < 17
def bust(self):
print self.name, "busts."
def flip_first_card(self):
first_card = self.cards[0]
first_card.flip()
class BJ_Game(object):
""" A Blackjack Game. """
def __init__(self, names):
self.players = []
for name in names:
player = BJ_Player(name)
self.players.append(player)
self.dealer = BJ_Dealer("Dealer")
self.deck = BJ_Deck()
self.deck.populate()
self.deck.shuffle()
def get_still_playing(self):
remaining = []
for player in self.players:
if not player.is_busted():
remaining.append(player)
return remaining
# list of players still playing (not busted) this round
still_playing = property(get_still_playing)
def __additional_cards(self, player):
while not player.is_busted() and player.is_hitting():
self.deck.deal([player])
print player
if player.is_busted():
player.bust()
def play(self):
# deal initial 2 cards to everyone
self.deck.deal(self.players + [self.dealer], per_hand = 2)
self.dealer.flip_first_card() # hide dealer's first card
for player in self.players:
print player
print self.dealer
# deal additional cards to players
for player in self.players:
self.__additional_cards(player)
self.dealer.flip_first_card() # reveal dealer's first
if not self.still_playing:
# since all players have busted, just show the dealer's hand
print self.dealer
else:
# deal additional cards to dealer
print self.dealer
self.__additional_cards(self.dealer)
if self.dealer.is_busted():
# everyone still playing wins
for player in self.still_playing:
player.win()
else:
# compare each player still playing to dealer
for player in self.still_playing:
if player.total > self.dealer.total:
player.win()
elif player.total < self.dealer.total:
player.lose()
else:
player.push()
# remove everyone's cards
for player in self.players:
player.clear()
self.dealer.clear()
def main():
print "\t\tWelcome to Blackjack!\n"
names = []
number = games.ask_number("How many players? (1 - 7): ", low = 1, high = 8)
for i in range(number):
name = raw_input("Enter player name: ")
names.append(name)
print
game = BJ_Game(names)
again = None
while again != "n":
game.play()
again = games.ask_yes_no("\nDo you want to play again?: ")
main()
raw_input("\n\nPress the enter key to exit.")
Since someone decided to call this 'psychic-debugging', I'll go ahead and tell you what the modules are then.
Here's the cards module:
class Card(object):
""" A playing card. """
RANKS = ["A", "2", "3", "4", "5", "6", "7",
"8", "9", "10", "J", "Q", "K"]
SUITS = ["c", "d", "h", "s"]
def __init__(self, rank, suit, face_up = True):
self.rank = rank
self.suit = suit
self.is_face_up = face_up
def __str__(self):
if self.is_face_up:
rep = self.rank + self.suit
else:
rep = "XX"
return rep
def flip(self):
self.is_face_up = not self.is_face_up
class Hand(object):
""" A hand of playing cards. """
def init(self):
self.cards = []
def __str__(self):
if self.cards:
rep = ""
for card in self.cards:
rep += str(card) + "\t"
else:
rep = "<empty>"
return rep
def clear(self):
self.cards = []
def add(self, card):
self.cards.append(card)
def give(self, card, other_hand):
self.cards.remove(card)
other_hand.add(card)
class Deck(Hand):
""" A deck of playing cards. """
def populate(self):
for suit in Card.SUITS:
for rank in Card.RANKS:
self.add(Card(rank, suit))
def shuffle(self):
import random
random.shuffle(self.cards)
def deal(self, hands, per_hand = 1):
for rounds in range(per_hand):
for hand in hands:
if self.cards:
top_card = self.cards[0]
self.give(top_card, hand)
else:
print "Can't continue deal. Out of cards!"
if name == "main":
print "This is a module with classes for playing cards."
raw_input("\n\nPress the enter key to exit.")
And here's the games module:
class Player(object):
""" A player for a game. """
def __init__(self, name, score = 0):
self.name = name
self.score = score
def __str__(self):
rep = self.name + ":\t" + str(self.score)
return rep
def ask_yes_no(question):
"""Ask a yes or no question."""
response = None
while response not in ("y", "n"):
response = raw_input(question).lower()
return response
def ask_number(question, low, high):
"""Ask for a number within a range."""
response = None
while response not in range(low, high):
response = int(raw_input(question))
return response
if name == "main":
print "You ran this module directly (and did not 'import' it)."
raw_input("\n\nPress the enter key to exit.")
You're checking it again and again, inside the loop, and while you distribute the cards, the deck is being reduced, I think (can't see the Deck.give method on your code to know for sure).
You probably want to check only once, move the check to outside the loop.
def deal(self, hands, per_hand=1):
for rounds in range(per_hand):
if len(self.cards) <= 7 * len(hands):
print "Reshuffling the deck."
self.cards = []
self.populate()
self.shuffle()
for hand in hands:
top_card=self.cards[0]
self.give(top_card, hand)
Nosklo pointed out one problem (checking it inside the loop) but there is a second problem.
the condition
if len(self.cards)>=7*(len(hands)):
is checking if the number of cards is greater than the number needed and if so,clears the deck, populates and shuffles.
When combined with the check inside the loop, it will repopulate and shuffle the deck every time it starts another round.
So you probably want something like:
if len(self.cards) <= 7*(len(hands)):
print "Reshuffling the deck."
self.cards=[]
self.populate()
self.shuffle()
for rounds in range(per_hand):
for hand in hands:
top_card=self.cards[0]
self.give(top_card, hand)
for hand in hands:
Do you really want to run that logic for each hand?

Categories

Resources