I need to simplify my code without using anything new [closed] - python

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 days ago.
Improve this question
I need to be able to simplify my code because I know I over complicated this. I just can't figure out how. I am looking to not use anything new that is not used in the code but I need help simplifying this down. I am making a game of war by the way, this game can be played with 2-4 players and I would like to keep it that way.
players = []
class Card:
def __init__(self, suit, rank, value):
self.suit = suit
self.rank = rank
self.value = value
def printCard(self):
print(f'{self.rank} of {self.suit}')
class Deck:
def __init__(self):
self.deck = []
suits = ['Diamonds', 'Clubs', 'Hearts', 'Spades']
ranks = [2,3,4,5,6,7,8,9,10,'J','Q','K','A']
for s in suits:
v = 2
for r in ranks:
self.deck.append(Card(s,r,v))
v += 1
random.shuffle(self.deck)
def dealCard(self):
if (len(self.deck) > 0):
return self.deck.pop(-1)
else:
return
def printDeck(self):
for card in self.deck:
print(card.print_card())
def remainingCards(self):
remaining = len(self.deck)
print(f'There are {remaining} cards left in the deck.')
def randomSplit(self):
splitToDeck = 0
while len(self.deck) != 0:
if splitToDeck == len(players):
splitToDeck = 0
p = players[splitToDeck]
p.drawCard(deck.dealCard())
splitToDeck += 1
class Player:
global players
def __init__(self, name):
self.name = name
self.hand = []
self.playing = True
self.score = 0
players.append(self)
self.discardPile = []
self.drawnCard = ''
def updateScore(self, value):
self.score += value
def drawCard(self, card):
self.hand.append(card)
def cardValue(self,index):
return self.hand[index].value
def printHand(self):
print('='*40)
print(f"{self.name}'s Hand")
print('='*40)
for card in self.hand:
card.printCard()
deck = Deck()
#deck.remainingCards()
Asher = Player("Asher")
Johnny = Player("Johnny")
deck.randomSplit()
#bob.printHand()
#joe.printHand()
#billy.printHand()
playing = True
while playing:
drawn = {'':0}
winner = ''
for player in players:
drawn[player.name] = player.cardValue(-1)
player.drawnCard = player.hand.pop(-1)
if drawn.get(player.name) > drawn.get(winner):
winner = player.name
elif drawn.get(player.name) == drawn.get(winner):
winner = 'There is war between:'
drawn['There is war between:'] = drawn.get(player.name)
if len(player.hand) == 0:
playing = False
if winner == 'There is war between:':
print('='*40)
print (winner)
for k, v in drawn.items():
if v == drawn.get(winner):
if k != 'There is war between:':
print (f'> {k}')
else:
print('='*40)
print (f'The winner is {winner}')
for player in players:
if player.name == winner:
winner = player
else:
losers = []
losers.append(player)
for loser in losers:
winner.discardPile.append(loser.drawnCard[0])
winner.discardPile.append(winner.drawnCard[0])

Related

Python, modifying a blackjack game

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.

Python 2.7.10 AttributeError

I have the following code and cant seem to realized why I get this error: Traceback (most recent call last):
card_ranks = [c.rank for c in cards[i:i+5]]
AttributeError: 'str' object has no attribute 'rank'
Here's the code:
import random
import logging
from collections import OrderedDict
from const import __version__, suits, ranks, POS_TOP, POS_BOTTOM
logger = logging.getLogger(__name__)
def f_list(lst, sep=','):
return sep.join([str(x) for x in lst])
def f_lists(lst, sep=' / '):
return f_list(map(f_list, lst), sep)
class Card(object):
"""Represents a single french-design card with it's rank and suit.
Cards can be compared and ordered by rank. A card, relative to
a card of the same rank but different suit, is compared as neither
higher, lower nor equal.
:param rank: Either the rank (one of 'A', 'K', 'Q', 'J', 'T', '9', ... '2')
or rank and suit together (e.g. 'AS', '8H', etc.)
:type rank: str
:param suit: The suit, if not given as one string with rank
(one of 'S', 'H', 'C', 'D' for spade, heart, club or diamond)
:type suit: str
:raises: ValueError
"""
def __init__(self, rank, suit=None):
if suit is None:
suit = rank[1]
rank = rank[0]
if rank not in ranks:
raise ValueError('Card(): Invalid rank')
if suit not in suits:
raise ValueError('Card(): Invalid suit')
self.rank = rank
self.suit = suit
#classmethod
def card_list(cls, *args):
"""Create a list of new cards.
Each argument should describe one card with rank and suit together.
:param args: One or more cards.
:type rank: str
:returns: List of new cards, one for each input parameter.
:rtype: list of :class:`pokercards.cards.Card` objects
:raises: ValueError
"""
lst = []
for c in args:
lst.append(cls(c))
return lst
def __str__(self):
return self.rank + self.suit
def __repr__(self):
return 'Card(%s, %s)' % (self.rank, self.suit)
def __hash__(self):
return (ord(self.rank) << 8) + ord(self.suit)
def __eq__(self, obj):
return self.rank == obj.rank and self.suit == obj.suit
def __ne__(self, obj):
return self.rank != obj.rank or self.suit != obj.suit
def __lt__(self, obj):
return ranks.index(self.rank) > ranks.index(obj.rank)
def __gt__(self, obj):
return ranks.index(self.rank) < ranks.index(obj.rank)
def __le__(self, obj):
return ranks.index(self.rank) >= ranks.index(obj.rank)
def __ge__(self, obj):
return ranks.index(self.rank) <= ranks.index(obj.rank)
class Deck(object):
"""Represents a single deck of 52 :class:`card.Card` objects.
The deck could be imagined face down on a table. All internal lists
represent the cards in order from bottom up. So dealing the top
card means poping last item from the list.
"""
def __init__(self):
self.popped = []
self.discarded = []
self.active = []
for s in suits:
for r in ranks:
self.active.append(Card(r, s))
def shuffle(self):
"""Shuffle the deck."""
random.shuffle(self.active)
def pop(self):
"""Deal the top card from the deck.
:returns: :class:`pokercards.cards.Card` instance
"""
card = self.active.pop()
self.popped.append(card)
return card
def discard(self):
card = self.active.pop()
self.discarded.append(card)
def return_cards(self, cards, pos = POS_BOTTOM):
if pos not in (POS_BOTTOM, POS_TOP):
raise Exception('Deck.return_cards(): invalid pos parameter')
for card in cards[:]:
if card in self.discarded:
self.discarded.remove(card)
elif card in self.popped:
self.popped.remove(card)
else:
raise Exception('Deck.return_cards(): card not among removed cards')
if pos == POS_BOTTOM:
self.active[0:0] = [card]
else:
self.active.append(card)
def return_discarded(self, pos = POS_BOTTOM):
self.return_cards(self.discarded, pos)
def return_popped(self, pos = POS_BOTTOM):
self.return_cards(self.popped, pos)
def return_all(self, pos = POS_BOTTOM):
self.return_popped()
self.return_discarded()
def stats(self):
return (len(self.active), len(self.popped), len(self.discarded))
def __str__(self):
return '[%s]' % ' '.join((str(card) for card in self.active))
def __repr__(self):
return 'Deck(%s)' % self.__str__()
class PokerHand(object):
"""Compute the best hand from given cards, implementing traditional
"high" poker hand ranks.
The hand object can be given more than five cards (as in Texas
Hold'em or similar variants) and the evaluation will pick the best
hand.
Evaluated :class:`pokercards.cards.PokerHand` objects are
compared and sorted by the rank of the hand.
.. attribute:: cards
List of :class:`pokercards.cards.Card` objects to make the hand
from. The :meth:`pokercards.cards.PokerHand.evaluate` method
should be called after manual update to re-evaluate the updated
hand.
Following attributes are available after evaluating the hand.
.. attribute:: hand_rank
Readonly rank of the hand (0 = high card to 8 = straight flush)
.. attribute:: hand_cards
Readonly list of cards which complete the rank.
.. attribute:: kickers
Readonly list of extra cards which can break a tie.
:param cards: List of :class:`pokercards.cards.Card` objects.
:param evaluate: Evaluate the hand when creating.
:type evaluate: bool
"""
def __init__(self, cards, evaluate=True):
cards.sort(reverse=True)
self.cards = cards
if evaluate:
self.evaluate()
def evaluate(self):
"""Evaluate the rank of the hand.
Should be called either implicitly at start by leaving
parameter ``evaluate`` True when creating the hand or
explicitly by calling this method later, e.g. after changing
the :attr:`cards` attribute manually.
"""
self._eval_hand_rank()
self._fill_kickers()
def _by_rank(self, cards=None):
if cards is None:
cards = self.cards
ranked = OrderedDict()
for card in cards:
if card.rank in ranked:
ranked[card.rank].append(card)
else:
ranked[card.rank] = [card]
return ranked
def _by_suit(self, cards=None):
if cards is None:
cards = self.cards
suited = OrderedDict()
for card in cards:
if card.suit in suited:
suited[card.suit].append(card)
else:
suited[card.suit] = [card]
return suited
def _find_flushes(self, cards=None):
if cards is None:
cards = self.cards
flushes = []
for cards in self._by_suit(cards).values():
l = len(cards)
if l >= 5:
for i in xrange(0, l - 4):
flushes.append(cards[i:i+5])
return flushes
def _find_straights(self, cards=None):
if cards is None:
cards = self.cards
straights = []
for i in xrange(0, len(cards) - 4):
card_ranks = [c.rank for c in cards[i:i+5]]
j = ranks.index(card_ranks[0])
if card_ranks == ranks[j:j+5]:
straights.append(cards[i:i+5])
return straights
def _fill_kickers(self):
hand_count = len(self.hand_cards)
kicker_count = 5 - hand_count
if kicker_count > 0:
kickers = self.cards[:]
for card in self.hand_cards:
kickers.remove(card)
self.kickers = kickers[:kicker_count]
else:
self.kickers = []
logger.debug("kickers: %s", f_list(self.kickers))
logger.debug("--- -------------- ---")
def _eval_hand_rank(self):
logger.debug("--- Evaluating %s ---", f_list(self.cards))
straights = self._find_straights()
if straights: logger.debug( "straights: %s", f_lists(straights))
flushes = self._find_flushes()
if flushes: logger.debug("flushes: %s", f_lists(flushes))
pairs = []
threes = []
fours = []
for cards in self._by_rank().values():
l = len(cards)
if l >= 4:
fours.append(cards[0:4])
elif l == 3:
threes.append(cards)
elif l == 2:
pairs.append(cards)
if pairs: logger.debug("pairs: %s", f_lists(pairs))
if threes: logger.debug("threes: %s", f_lists(threes))
if fours: logger.debug("fours: %s", f_lists(fours))
# straight flush
for cards in straights:
if cards in flushes:
self.hand_rank = 8
self.hand_cards = cards
logger.debug("* straight flush: %s", f_list(self.hand_cards))
return
# four of a kind
if len(fours) > 0:
self.hand_rank = 7
self.hand_cards = fours[0]
logger.debug("* four of a kind: %s", f_list(self.hand_cards))
return
# full house
if len(threes) > 1:
self.hand_rank = 6
self.hand_cards = threes[0] + threes[1][:2]
logger.debug("* full house: %s", f_list(self.hand_cards))
return
elif len(threes) == 1 and len(pairs) > 0:
self.hand_rank = 6
self.hand_cards = threes[0] + pairs[0]
logger.debug("* full house: %s", f_list(self.hand_cards))
return
# flush
if len(flushes) > 0:
self.hand_rank = 5
self.hand_cards = flushes[0]
logger.debug("* flush: %s", f_list(self.hand_cards))
return
# straight
if len(straights) > 0:
self.hand_rank = 4
self.hand_cards = straights[0]
logger.debug("* straight: %s", f_list(self.hand_cards))
return
# three of a kind
if len(threes) > 0:
self.hand_rank = 3
self.hand_cards = threes[0]
logger.debug("* three of a kind: %s", f_list(self.hand_cards))
return
# two pair
if len(pairs) > 1:
self.hand_rank = 2
self.hand_cards = pairs[0] + pairs[1]
logger.debug("* two pairs: %s", f_list(self.hand_cards))
return
# one pair
if len(pairs) == 1:
self.hand_rank = 1
self.hand_cards = pairs[0];
logger.debug("* two of a kind: %s", f_list(self.hand_cards))
return
# high card
self.hand_rank = 0
self.hand_cards = [self.cards[0]]
logger.debug("* high card: %s", f_list(self.hand_cards))
def __str__(self):
return '[%s]' % f_list(self.cards)
def __repr__(self):
return '%s(%s)' % (self.__class__.__name__, self.__str__())
def __cmp__(self, other):
if self.hand_rank > other.hand_rank:
return 1
elif self.hand_rank < other.hand_rank:
return -1
else:
# same rank
for c1, c2 in zip(self.hand_cards, other.hand_cards):
if c1 > c2:
return 1
elif c1 < c2:
return -1
else:
# same cards, check kickers
for c1, c2 in zip(self.kickers, other.kickers):
if c1 > c2:
return 1
elif c1 < c2:
return -1
# really, a tie
return 0
deck = Deck()
deck.shuffle()
player = []
computer = []
cmoney = 500
money = 500
pot = 0
for i in range(5):
card = deck.pop()
player.append(str(card))
player.sort()
for i in range(5):
card = deck.pop()
computer.append(str(card))
computer.sort()
pot += 10
money -= 5
cmoney -= 5
print "All players have anted $5."
print "Your Hand:", player
print "Your Money: $" + str(money)
print "Pot: $" + str(pot)
discard = []
ask = raw_input("Bet or check? ")
if ask.lower() == "bet":
ask2 = int(raw_input("How much? "))
if ask2 > money:
print "You don't have that much money!"
else:
money -= ask2
cmoney -= ask2
pot += ask2 * 2
print("Pot: $" + str(pot))
ui = raw_input("Do you want to discard some cards? ")
if ui.lower() == "yes":
ui2 = int(raw_input("How many? "))
for i in range(ui2):
ui3 = raw_input("Card " + str(i + 1) + ": ")
discard.append(ui3)
player.pop()
for i in range(ui2):
card = deck.pop()
player.append(str(card))
print "Your Hand:", player
print "Your Money: $" + str(money)
ask3 = raw_input("Bet or check? ")
if ask3.lower() == "bet":
ask4 = int(raw_input("How much? "))
if ask4 > money:
print "You don't have that much money!"
else:
money -= ask4
pot += ask4
pval = PokerHand(player, True)
cval = PokerHand(computer, True)
if pval > cval:
print "YOU WIN!"
money += pot
pot = 0
else:
print "YOU LOSE!"
cmoney += pot
pot = 0
print "Pot: $" + str(pot)
print "Your Hand:", player
print "Computer\'s Hand:", computer
You are constructing the PokerHand with an array of strings, not an array of cards. The code is here:
for i in range(5):
card = deck.pop()
player.append(str(card))
player.sort()
for i in range(5):
card = deck.pop()
computer.append(str(card))
computer.sort()
Instead of str(card), try just using append(card). Hopefully that should work, unless you use the string elsewhere.

How to make cards work in python [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
This is my code so far:
import sys
import os
import random
Question():
os.system('cls')
SQ=input('Do you want to play blackjack y/n')
if(SQ == y or SQ == Y):
StartGame()
if(SQ == n or SQ == N):
sys.exit()
if(SQ != n and SQ != N and SQ != y and SQ != Y):
print('You did answer the question with a y or a n which correspond to yes and no accordingly')
Question()
Question()
StartGame():
slot1=False
slot2=False
slot3=False
slot4=False
slot5=False
slot6=False
slot7=False
slot8=False
slot9=False
slot10=False
slot11=False
slot12=False
slot13=False
slot14=False
slot15=False
slot16=False
slot17=False
slot18=False
slot19=False
slot20=False
slot21=False
slot22=False
slot22=False
slot23=False
Slot24=False
slot25=False
slot26=False
slot27=False
Slot28=False
slot29=False
slot30=False
slot31=False
slot32=False
slot33=False
slot34=False
slot35=False
slot36=False
slot37=False
slot38=False
slot39=False
slot40=False
slot41=False
slot42=False
slot43=False
slot44=False
slot45=False
slot46=False
slot47=False
slot48=False
slot49=False
slot50=False
slot51=False
slot52=False
aceHEART = randrange(1, 52)
aceHEART
I don't understand the correct way to make the slots and a random number generator together to make a random shuffle. How can i make it so it does not try to put more than one card in one slot. I also do not know how to manage these cards in a more efficient way. I am making a blackjack game in python and i do not know the correct way to approach this. Please help me in the best way you can.
Not sure what you're trying to do, but here is a way to generate a shuffled deck of cards:
ranks = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']
suite = ['clubs', 'hearts', 'spades', 'diamonds']
deck = [r + ' ' + s for r in ranks for s in suite]
random.shuffle(deck)
Or with objects:
class Card(object):
def __init__(self, rank, suite):
self.rank = rank
self.suite = suite
deck = [Card(r,s) for r in ranks for s in suite]
random.shuffle(deck)
Learn to love lists, and use numbers to represent cards, not strings. Here's a simple card class that should work nicely:
class Card(object):
def __init__(self, rank, suit):
self.rank = rank
self.suit = suit
def __str__(self):
return "23456789TJQKA"[self.rank] + "cdhs"[self.suit]
Then create decks and hands that are just lists of cards:
deck = [ Card[r,s] for r in range(13) for s in range(4) ]
random.shuffle(deck)
Why you want to use lists for hands and decks, for example, is that dealing a card is simply:
hand.append(deck.pop())
Why you want to use numbers for card ranks instead of strings is to make it possible to add and compare them. You could add a "value" member to Mihai's code above, that would help. WIth mine, you just have to adjust the numbers a bit:
def bjTotal(hand):
total = 0
hasAce, isSoft = False, False
for card in hand:
if card.rank == 12:
hasAce = True
total += 1
elif card.rank > 7:
total + 10
else:
total += card.rank + 2
if hasAce and total < 12:
isSoft = True
total += 10
return total, isSoft
classes do a good job of representing cards and games
import random
class Card:
def __init__(self,rank,suit):
self.rank = rank
self.suit = suit
def rankName(self):
return "A23456789TJQK"[self.rank]
def suitName(self):
return "HCDS"[self.suit]
def __int__(self):
if self.rank > 8: return 10
if self.rank == 0:return 11
return self.rank + 1
def __eq__(self,other):
try:
return self.rank == other.rank
except:
return self.rank == other
def __str__(self):
return self.rankName() +self.suitName()
def __repr__(self):
return "<Card: %s>"%self
class Deck:
def __init__(self,cards=None):
if cards is None:
cards = [Card(rank,suit) for rank in range(13) for suit in range(4)]
self.cards = cards
random.shuffle(self.cards)
def draw(self):
return self.cards.pop(0)
def __add__(self,other):
return Deck(self.cards+other.cards)
class Hand:
def __init__(self):
self.cards = []
def __int__(self):
total = sum(map(int,self.cards))
aces = self.cards.count(0)
while aces > 0 and total > 21:
aces -= 1
total -= 10
return total
def put(self,card):
self.cards.append(card)
def __str__(self):
return ", ".join(map(str,self.cards))
def __repr__(self):
return "<Hand %s>"%self.cards
once you have your classes you can now start constructing your game
class Game:
def __init__(self,n_players=1,use_dealer=True):
self.main_deck = Deck()+Deck() # 2 deck shoe
self.n_players = n_players
self.dealer = use_dealer
def play_hand(self,hand):
while int(hand) <= 21 and raw_input("%r\nHit?"%hand)[0].lower() == "y" :
hand.put(self.main_deck.draw())
if int(hand) > 21:
print "BUST!!!"
def play_game(self):
current_player = 0
hands = [Hand() for _ in range(self.n_players+self.dealer)]
for i in range(2):
for hand in hands:
hand.put(self.main_deck.draw())
while current_player < len(hands) - self.dealer:
self.play_hand(hands[current_player])
current_player += 1
if self.dealer:
while int(hands[-1]) < 17:
hands[-1].put(self.main_deck.draw())
print "DEALER HITS:",hands[-1]
print "FINAL SCORES:"
print "\n".join("%s. %r %d"%(i,h,h) for i,h in enumerate(hands))
game = Game()
game.play_game()
(something like that anyway)

Python Simple Card Game to Learn Classes

I am trying to create a simple card game to better understand OOP and classes.
The game is as follows: Two cards are dealt from a deck. Then a third card is dealt. If the third card is between the first two cards, then the player wins. If the third card is equal to either of the first two cards, or is outside of the set, then the player loses.
This is what I have so far:
class Deck(object):
def __init__(self):
self.deck = []
def PopulateDeck(self):
suits = ["Hearts", "Diamonds", "Clubs", "Spades"]
for suit in suits:
for rank in range(2, 15):
if rank == 11:
value = "Jack"
elif rank == 12:
value = "Queen"
elif rank == 13:
value = "King"
elif rank == 14:
value = "Ace"
self.deck.append(str(value) + " of " + suit)
class Card(object):
def __init__(self, rank, value):
self.rank = rank
self.value = value
self.card = self.rank + self.value
I am having a difficult time with classes and OOP, and I'm not sure if this is a good start, or where I should go next. Much of this was created by reading other sources and examples. Can anyone please provide advice on what other classes I may want to make to run my game, and how those classes may interact with/inherit from each other? Thank you.
This is more of a code/approach review. A card game is a case for composition, not inheritance; the Deck contains Cards, but isn't in itself a type of Card, and vice versa.
I think you are duplicating information in the Card. Just store suit and rank, and use __str__ to create 'x of y'. You can also implement the rich comparison methods:
class Card(object):
FACES = {11: 'Jack', 12: 'Queen', 13: 'King', 14: 'Ace'}
def __init__(self, rank, suit):
self.suit = suit
self.rank = rank
def __str__(self):
value = self.FACES.get(self.rank, self.rank)
return "{0} of {1}".format(value, self.suit)
def __lt__(self, other):
return self.rank < other.rank
Now e.g. str(Card(13, 'Clubs')) == "King of Clubs". This way you don't duplicate the rank and value in card.
Next, I think the Deck should incorporate the population generation in __init__; you can provide optional arguments for a non-standard deck. I have included two implementations; the commented-out version is a list comprehension using itertools to do the same job in one line. I also provide a function to pick n different random cards from self.deck.
from itertools import product
import random
class Deck(object):
def __init__(self, ranks=None, suits=None):
if ranks is None:
ranks = range(2, 15)
if suits is None:
suits = ['Clubs', 'Diamonds', 'Hearts', 'Spades']
## self.deck = [Card(r, s) for r, s in product(ranks, suits)]
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)
Now the game is simple; you can deal three cards per hand, and compare the cards naturally (using e.g. <) because of the comparison methods.
deck = Deck()
hand = deck.deal(3)
print(" - ".join(map(str, hand)))
if min(hand[0], hand[1]) < hand[2] < max(hand[0], hand[1]):
print("Winner!")
else:
print("Loser.")
As #tobias_k have pointed out in the comments + some of my thoughts
class Deck(object):
def __init__(self):
self.deck = []
self.dealt = [] #Prevents from dealing the same card
def PopulateDeck(self):
suits = ["Hearts", "Diamonds", "Clubs", "Spades"]
for suit in suits:
for rank in range(2, 15):
if rank == 11:
value = "Jack"
elif rank == 12:
value = "Queen"
elif rank == 13:
value = "King"
elif rank == 14:
value = "Ace"
else:
value = str(rank)
self.deck.append(Card(value, suit))
def deal(self):
#Randomly select card
remaining_cards = [card for card in self.deck if card not in self.dealt]
card_index = random.randrange(0, len(remaining_cards)-1)
card = remaining_cards[card_index]
self.dealt.append(card)
return card
def shuffle(self):
self.dealt = []
class Card(object):
def __init__(self, rank, suit):
self.rank = rank
self.suit = suit
self.card = str(self.rank) + " " + str(self.suit)
def __eq__(self, other):
return self.rank == other.rank and self.suit == other.suit
def play():
deck = Deck()
card1 = deck.deal()
card2 = deck.deal()
card3 = deck.deal()
#And here you will compare the cards to see if the player wins or not. Not sure
#what exact criterion you're using.
deck.shuffle() #And leave your deck nicely shuffled for next game
play()
Random documentation
I have not run this code, and it likely contains errors. But it is an illustration of what you can do.
I am also learning opps using card games as i find that is most easy way to understand the concepts. I have come accross this code sometime back, but not sure about the link. I am pesting this code with few usefull comments. This may be helpful.
from random import shuffle
class Card:
suits = ['spades', 'hearts', 'diamonds', 'clubs']
values = [None, None, '2','3','4','5','6','7','8','9','10','Jack', 'Queen', 'King', 'Ace']
def __init__(self, v, s):
'''suits + values are ints'''
self.value = v
self.suit = s
def __lt__(self, c2): # allows to compare two objects cards in this case
if self.value < c2.value:
return True
if self.value == c2.value: # value is what user is putting while creating object of class
if self.suit < c2.suit: # c2 is with what we are comapring
return True
else:
return False
return False
def __gt__(self, c2): # allows to compare two objects cards in this case,
if self.value > c2.value: # c2 is with what we are comapring
return True
if self.value == c2.value:
if self.suit > c2.suit: # suits comes into picture if values are same suit number is given importance
return True
else:
return False
return False
def __repr__(self):
v = self.values[self.value] + ' of ' + self.suits[self.suit]
return v
# defining the class which represent the deck of card
class Deck:
def __init__(self):
self.cards = []
for i in range(2,15):
for j in range(4):
self.cards.append(Card(i,j))
shuffle(self.cards)
def rm_card(self):
if len(self.cards) == 0:
return # if block it return to None object when condition is satisfied
return self.cards.pop()
class Player:
def __init__(self, name):
self.name = name # name of the player
self.card = None # current card player holding
self.wins = 0
class Game:
def __init__(self):
name1 = input('p1 name ')
name2 = input('p2 name ')
self.deck = Deck()
self.p1 = Player(name1)
self.p2 = Player(name2)
def wins(self, winner):
w = "{} wins this round"
w = w.format(winner)
print(w)
def draw(self, p1n, p1c, p2n, p2c):
d = "{} drew {} {} drew {}"
d = d.format(p1n, p1c, p2n, p2c)
print(d)
def play_game(self):
cards = self.deck.cards # self.deck = Deck() and cards = self.deck.cards is list of card
print('Beginning War!!!')
while len(cards) > 2:
m = 'q to quit. Any' + ' key to play'
response = input(m)
if response == 'q':
break
p1c = self.deck.rm_card() # removing first card from deck by player 1
p2c = self.deck.rm_card() # removing second card from deck by player 2
p1n = self.p1.name
p2n = self.p2.name
self.draw(p1n, p1c, p2n, p2c)
if p1c > p2c:
self.p1.wins +=1
self.wins(self.p1.name)
else:
self.p2.wins += 1
self.wins(self.p2.name)
win = self.winner(self.p1, self.p2)
print("War is over. {} wins".format(win))
def winner(self, p1, p2):
if p1.wins > p2.wins:
return p1.name
if p1.wins < p2.wins:
return p2.name
return 'Its Tie!'
game = Game()
game.play_game()
Source: https://thecleverprogrammer.com/2020/10/04/card-game-with-python/

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