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)
Related
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])
I'm trying to make a simplified version of the card game War. In this game, there are two players. Each starts with half of a deck. The players each deal the top card from their decks and whoever has the higher card wins the other player's cards and adds them to the bottom of his deck. If there is a tie, the two cards are eliminated from play. The game ends when one player runs out of cards.
However, I'm having an issue with the pop argument, in that it gives me an error with "pop from empty list".
How can I fix that?
import random
class Card:
def __init__(self, value, suit):
self.value = value
self.suit = suit
def __str__(self):
names = ['Jack', 'Queen', 'King', 'Ace']
if self.value <= 10:
return '{} of {}'.format(self.value, self.suit)
else:
return '{} of {}'.format(names[self.value-11], self.suit)
class CardGroup:
def __init__(self, cards = []):
self.cards = cards
def shuffle(self):
random.shuffle(self.cards)
class StandardDeck(CardGroup):
def __init__(self):
self.cards = []
for s in ['Hearts', 'Diamonds', 'Clubs', 'Spades']:
for v in range(2,15):
self.cards.append(Card(v, s))
def deal_out(self, num_cards, num_players):
deal = [[0 for x in range(num_cards)] for y in range(num_players)]
for i in range(num_cards):
for k in range(num_players):
deal[k][i] = self.cards.pop()
self.deal = deal
deck = StandardDeck()
deck.shuffle()
print("\n===== shuffled deck =====\n")
player1_list = []
player2_list = []
for i in range(26):
p1_temp = deck.deal_out(26, 2)
player1_list.append(p1_temp)
p2_temp = deck.deal_out(26, 2)
if (p2_temp.__init__() == 1):
player1_list.append(p2_temp)
player2_list.append(player1_list.pop(0))
else:
player2_list.append(p2_temp)
# Card dealt to Player #1
player1_card = player1_list.pop(0)
print("===== player #1 =====")
print("Card dealt to player #1: \n", player1_card)
print(player1_list)
#Card dealt to Player #2
player2_card = player2_list.pop(0)
print("\n===== player #2 =====")
print("Card dealt to player #2: \n", player2_card)
print(player2_list)
# Compare the two cards using overloaded operators
if player1_card == player2_card:
print("Tie: ", player1_card, "and", player2_card,\
"are of equal rank")
elif player1_card > player2_card:
print("Player #1 wins: ", player1_card, \
"is of higher rank than", player2_card)
else:
print("Player #2 wins: ", player2_card, \
"is of higher rank than", player1_card)
print()
Rather than self.deal = deal in deal_out() you likely want to return the deal.
If you do, some code related to for i in range(26): can be removed as your player hands get populated from deal_out(). You also have some issues of comparing cards when you want to compare card values.
Here are some slight modifications to get you going again:
import random
class Card:
def __init__(self, value, suit):
self.value = value
self.suit = suit
def __str__(self):
names = ['Jack', 'Queen', 'King', 'Ace']
if self.value <= 10:
return '{} of {}'.format(self.value, self.suit)
else:
return '{} of {}'.format(names[self.value-11], self.suit)
class CardGroup:
def __init__(self, cards = []):
self.cards = cards
def shuffle(self):
random.shuffle(self.cards)
class StandardDeck(CardGroup):
def __init__(self):
self.cards = []
for s in ['Hearts', 'Diamonds', 'Clubs', 'Spades']:
for v in range(2,15):
self.cards.append(Card(v, s))
def deal_out(self, num_cards, num_players):
deal = [[0 for x in range(num_cards)] for y in range(num_players)]
for i in range(num_cards):
for k in range(num_players):
deal[k][i] = self.cards.pop()
## self.deal = deal
return deal
deck = StandardDeck()
deck.shuffle()
print("\n===== shuffled deck =====\n")
'''
player1_list = []
player2_list = []
for i in range(26):
p1_temp = deck.deal_out(26, 2)
player1_list.append(p1_temp)
p2_temp = deck.deal_out(26, 2)
if (p2_temp.__init__() == 1):
player1_list.append(p2_temp)
player2_list.append(player1_list.pop(0))
else:
player2_list.append(p2_temp)
'''
player1_list, player2_list = deck.deal_out(26, 2)
# Card dealt to Player #1
player1_card = player1_list.pop(0)
print("===== player #1 =====")
print("Card dealt to player #1: \n", player1_card)
#print(player1_list)
#Card dealt to Player #2
player2_card = player2_list.pop(0)
print("\n===== player #2 =====")
print("Card dealt to player #2: \n", player2_card)
#print(player2_list)
# Compare the two cards using overloaded operators
if player1_card.value == player2_card.value:
print("Tie: ", player1_card, "and", player2_card,\
"are of equal rank")
elif player1_card.value > player2_card.value:
print("Player #1 wins: ", player1_card, \
"is of higher rank than", player2_card)
else:
print("Player #2 wins: ", player2_card, \
"is of higher rank than", player1_card)
print()
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()
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.
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/