Simple card game in python - python

I am making a simple card game that deals the player two cards and if the cards are the same suit, the same rank (value), or a run the player wins. If the player's hand has none of these properties the player loses. The code I am using is as follows:
from itertools import product
import random
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
class Deck(object):
def __init__(self, ranks=None, suits=None):
if ranks is None:
ranks = xrange(2, 15)
if suits is None:
suits = ['Clubs', 'Diamonds', 'Hearts', 'Spades']
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)
ranks = xrange(2, 15)
suits = ['Clubs', 'Diamonds', 'Hearts', 'Spades']
deck = Deck()
hand = deck.deal(2)
print "Your hand is"
print " - ".join(map(str, hand))
suits_in_hand = []
for card in hand:
suits_in_hand.append(card.suit)
if all(suits_in_hand == suit for suit in suits):
print "\nAll cards are of the same suit"
print "You Win!"
elif all(suits_in_hand == rank for rank in ranks):
print "\nAll cards are of the same rank"
print "You Win!"
# I don't know how to test if the cards in the player's hand are a run
else:
print "\nYou Lose."
However, even if the cards are both the same suit (e.g. 'two of Spades' and 'three of Spades') or the same rank (e.g. 'two of Hearts' and 'two of Clubs') it outputs You Lose. What can I do to fix this and how can I add the elif statement to test whether or not the cards in the player's hand are a run.

To check if all elements in a collection are the same, a short and elegant solution is to use a set :
suits_in_hand = set(card.suit for card in hand)
if len(suits_in_hand) == 1:
print "\nAll cards are of the same suit"
print "You Win!"
Same for ranks.
For runs, you could compare the set of ranks to a set from range :
ranks_in_hand = set(card.rank for card in hand)
min_rank == min(ranks_in_hand)
if set(ranks_in_hand) == set(range(min_rank, min_rank + 2)):
print "\nGot a run !"

Your main issue is you're trying to compare a single entity to an array, which you can't do. Instead of
if all(suits_in_hand == suit for suit in suits):
print "\nAll cards are of the same suit"
print "You Win!"
do something like
if suit in suits_in_hand for suit in suits:
print "\nAll cards are of the same suit"
print "You Win!"
For the ranks, you'll need to do something similar, but build a ranks_in_hand object.

You want to compare the elements in suits_in_hand against each other. Comparing them to suits is comparing your hand to all possible suits, which isn't right. Similarly, you need a ranks_in_hand and compare the elements in it to each other.
To check for a run, just check if the difference between the card ranks in your hand is 1.

For checking if all of the suits in the hand are the same, you can check to see if the length of the set created from suits_in_hand is one.
if len(set(suits_in_hand)) == 1:
# do something
A similar thing could be done for checking if the hand contains all of the same card.
To check for a run, you could try sorting the list and checking that each element is one greater than the next (simplified, just check the difference if you only need to support a hand size of two).

Related

How to get a random card from a deck of cards?

I have code of a generator that generates a deck of cards.
Now I want to get 1 random card from the deck and print it,
but it seems I can't do it.
Random.choice doesn't work for it.
i´ve tried to manually add the value + suit + color, but that doesnt work either.
Im new to coding and please forgive me for not understanding coding.
edit: translated to english.
from random import random
values = list(range(2,15))
suits = ["♣","♦","♥","♠"]
colors = ["black","red"]
#making the high value cards to the face of king, qeen, etc
face_cards = {
"J": 11,
"Q": 12,
"K": 13,
"A": 14,
11: "J",
12: "Q",
13: "K",
14: "A"
}
class card:
def __init__(self,value,suit,color):
self.value = value
self.suit = suit
self.color = color
#Makes the deck of cards in a cards []
def deck_of_cards(values, suits,colors):
cards = []
for value in values:
for suit in suits:
for color in colors:
if value in face_cards:
card_value = face_cards[value]
cards.append(card(card_value,suit,color))
else:
cards.append(card(value, suit,color))
return cards
ask = input("do you want a random card from the deck ?(yes or no): ")
cards = deck_of_cards(values,suits,colors)
if ask == "yes":
print("The random card is: ",random.choice(cards)) # This line is suposed to print 1 random card from the list cards,
# but the list doesnt seem to work the way i wanted it to work
else:
cards = deck_of_cards(values,suits,colors)
for card in cards: #This function is required to print the deck
print(card.value, card.suit,card.color)
You need to replace from random import random to import random, since the choice() function is located directly in the "random" module.
Also, for a good display of the selected map, you can override the __str__() method in the class card:
class card:
def __init__(self, value, suit, color):
self.value = value
self.suit = suit
self.color = color
def __str__(self):
return f'{self.color} {self.value} {self.suit}'
I tried out your code, and then made a few tweaks to provide a random selection of cards in the spirit of your project. Following is the code with the tweaks.
import random # Changed the import declaration
values = list(range(2,15))
suits = ["♣","♦","♥","♠"]
colors = ["black","red"]
#making the high value cards to the face of king, qeen, etc
face_cards = {
"J": 11,
"Q": 12,
"K": 13,
"A": 14,
11: "J",
12: "Q",
13: "K",
14: "A"
}
class card:
def __init__(self,value,suit):
self.value = value
self.suit = suit
if self.suit == "♣" or self.suit == "♠": # Stick to standard colors for suits
self.color = colors[0]
else:
self.color = colors[1]
#Makes the deck of cards in a cards []
def deck_of_cards(values, suits):
cards = []
for value in values:
for suit in suits:
if value in face_cards:
card_value = face_cards[value]
cards.append(card(card_value,suit))
else:
cards.append(card(value, suit))
return cards
cards = deck_of_cards(values,suits)
while True: # Allow for multiple selections
ask = input("do you want a random card from the deck ?(yes/no/quit): ") # Added a quit option
if ask == "quit":
break
if ask == "yes":
chosen = random.randint(0, 51) # Generate a random number
print("The random card is: ", cards[chosen].value, "of", cards[chosen].suit) # Then, get the card associated with that index
else:
cards = deck_of_cards(values,suits)
for card in cards: #This function is required to print the deck
print(card.value, card.suit,card.color)
First off, to make a random selection, a variable was added that would contain a random value between "0" and "51". This value would then be used as an index to your card deck to display the card. Also, in keeping with standard card deck colors, I removed the need to pass a color onto the card deck creation and just based the color on the usual and customary color of suits (e.g. "hearts" are red, "spades" are black). And I added a "while" loop so that a user can make multiple selections.
Give that a try and see if it meets the spirit of your project.

Trying To Develop a Scoring System for Blackjack Game

so I'm trying to make a scoring system using my current code for blackjack. The game is versus the computer and a player and the rules are a bit different , but that has all been setup. I need to purpose the code for scoring both player and computer's cards. I also should make it so an ace is set to be the value of 1, if to avoid busting. I was thinking of doing so as cards are drawn, but I'm not entirely sure. I tried cross class variables and I didn't find much success. Maybe I could fuse the player and deck classes?
Anyways, here is what I have, I'll provide any more information you need and there should be fairly thorough comments.
# This is a game of blackjack versus a computer.
# ------------------------------------------------------------------------------------------------------
# importing necessary files
import random
# A couple global variables for any necessary repeats and scoring.
RepeatCardChoice = 0
YourScore = 0
ComputerScore = 0
HitCount = 0 # The amount of times the player hits. Used for showing cards.
# Our deck itself.
class Card: # This is for developing the cards in the first place.
def __init__(self, suit, rank):
self.suit = suit
self.rank = rank
def show(self):
print(str(self.rank) + str(self.suit))
class Deck: # This is for deck behaviors and creating a deck.
def __init__(self):
self.cards = []
self.Cards()
def Cards(self):
for suit in ["S", "C", "D", "H"]: # S = Spades, C = Clubs, D = Diamonds, and H = Hearts
for rank in range(1, 14):
value = rank
if rank == 1:
rank = 'A' # Makes all 1 values = to ace.
elif rank == 11:
rank = 'J' # Makes all 11 values = to jack or j.
elif rank == 12:
rank = 'Q' # Makes all 12 values = to queen or Q.
elif rank == 13:
rank = 'K' # Makes all 13 values = to king or K.
if rank == (11) or (12) or (13):
value = 10
elif rank == 1:
value == 11
self.value = value
self.cards.append(Card(suit, rank))
def show(self): # Shows each card individually.
for card in self.cards:
card.show() # Really just reusing another function to display results.
def shuffle(self):
random.shuffle(self.cards)
def drawCard(self):
return self.cards.pop()
class Player: # This class is for player behaviors such as drawing and showing your hand.
def __init__(self, name):
self.name = name # Allows the player to choose their name.
self.hand = [] # Assigns their cards to a list, to be saved.
self.Deck = Deck()
def draw(self, deck, CardCount): # How the player draws one card at a time. It wasn't necessary to allow more.
count = 0
while count != CardCount:
count += 1
self.hand.append(deck.drawCard())
return self
def showHand(self, showCount): # Shows each card in the player's hand.
count = 0 # A counter is used to limit how much is drawn.
for card in self.hand: # This is so "card" doesn't stay an unresolved reference.
if count == showCount:
return
count += 1
card.show()
# Below is where we apply the classes and play the game. The computer will operate without input, unlike the player.
# Here is the deck.
deck = Deck()
deck.shuffle() # Shuffling the deck in preparation.
PlayerName = str(input('What is your name?')) # Just so the player can choose their name.
# Setting up the players.
Computer = Player("The Computer")
You = Player(PlayerName)
# Giving both players their hand to start off with.
Computer.draw(deck, 2)
You.draw(deck, 2)
# Here is where one card in each hand is shown.
print('You are showing:')
You.showHand(1)
print('The computer is showing:')
Computer.showHand(1)
# Here is where you decide to hit or stand.
while RepeatCardChoice == 0:
CardChoice = str(input('Hit (H) or Stand (S)?'))
if CardChoice == 'H':
You.draw(deck, 1)
HitCount += 1
You.showHand(1+HitCount)
RepeatCardChoice = 0 # This is so the player can keep deciding whether they still want to hit?
elif CardChoice == 'S':
RepeatCardChoice = 21 # Get it, because the winning score in blackjack is 21?
HitCount = 0
else:
RepeatCardChoice = 0
# Here is where we check your score.
if YourScore > 21:
exit('You busted and the computer wins!')
elif YourScore == 21:
exit('Blackjack, you win!')
# Here is where the computer hits or stands.
while ComputerScore <= 17:
Computer.draw(deck, 1)
HitCount +=1
Computer.showHand(1+HitCount)
if ComputerScore>21:
exit('The computer busted and you win!')
elif ComputerScore == 21:
exit('Blackjack, the computer wins!')
# Here is where we compare the scores to decide the winner.
if ComputerScore > YourScore:
exit('The computer wins!')
elif YourScore > ComputerScore:
exit('You win!')
elif ComputerScore == YourScore:
exit('You tied')
The output shouldn't provide any errors if the scoring system is successful, and I setup some variables that I might use to assign the score, however this can be changed as needed. Here is the output anyways.
What is your name?Sample
You are showing:
KC
The computer is showing:
JS
Hit (H) or Stand (S)?H
KC
8S
Hit (H) or Stand (S)?S
JS
...
Traceback (most recent call last):
File "Censored", line 119, in <module>
Computer.draw(deck, 1)
File "Censored", line 66, in draw
self.hand.append(deck.drawCard())
File "Censored", line 54, in drawCard
return self.cards.pop()
IndexError: pop from empty list
Essentially, what is happening is that the computer hits infinitely due to a lack of scoring, until there is nothing left to draw, this is after you stand. I skipped a lot of lines in the output, as they're just a bunch of cards getting drawn.

Global variable playing keeps getting name error

declared playing in my hit_or_stay function as a global variable but keep getting an error when i run my program saying "name error: playing is not defined" How do i fix this?
I used global playing in hit_or_stand() to control the gameflow depending on the player's input. When I run the code I get error "NameError: name playing is not defined." I tried to move "global playing" outside of hit_or_stay() but nothing seems to work.
import random
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}
class Deck:
'''
CREATES DECK, SHUFFLES DECK, DEALS CARDS.
'''
#CREATES DECK BY ADDING EACH SUIT TO EACH RANK AND STORING IN LIST SELF.DECK
def __init__(self):
self.deck = []
for s in suits:
for r in ranks:
self.deck.append(r + ' of ' + s)
#SHUFFLE DECK CREATED IN __init__()
def shuffle(self):
random.shuffle(self.deck)
#DEALS CARD FROM SELF.DECK AT GAME START AND IF PLAYER CHOOSES TO HIT
def deal(self):
single_card = self.deck.pop()
return single_card
#PRINTS CARDS IN SELF.DECK (FOR TROUBLESHOOTING)
def __str__(self):
for card in self.deck:
return str(self.deck)
#print('\n')
##create an instance of Deck class and print the deck
#test_deck = Deck()
#print(test_deck)
#print('\n')
##shuffle and print the deck
#test_deck.shuffle()
#print(test_deck)
#print('\n')
class Card:
'''
CREATES CLASS FOR INDIVIDUAL CARDS, PRINTS INIDIVIDUAL CARDS "SUIT OF RANK"
'''
#CREATES CHARACTERISITCS OF class Card; self.suit and self.rank
def __init__(self,suit,rank):
self.suit = suit
self.rank = rank
class Hand:
'''
HOLDS CARD OBJECT FROM self.deck USING Deck.deal() method
CALCULATES THE VALUE OF THE CARDS IN HAND
ADJUST FOR ACES WHEN APPROPRIATE
'''
#CREATE CHARATERISTICS FOR CARDS IN HAND; self.card = cards in hand, self.value = value of cards in hand, self.aces = counts aces in hand
def __init__(self):
self.cards = []
self.value = 0
self.aces = 0
#ADDS CARDS TO HANDS ONCE DEALT
def add_card(self,card):
#ADDS CARD TO HAND
self.cards.append(card)
#HOLDS THE VALUE OF THE HAND
key = ''
key = card.split()
self.value += values[key[0]]
#ACCOUNT FOR ACE
if key[0] == 'Ace':
self.aces += 1
#KEEPS TRACK OF ACES; ADJUSTS VALUE FOR ACE WHEN APPROPARIATE
def adjust_for_ace(self,card):
if self.value > 21 and self.aces:
self.value -= 10
self.aces -= 1
class Chips:
def __init__(self):
self.total = 100
self.bet = 0
#ADD CHIPS TO TOTAL IF WIN
def win_bet(self):
self.total += self.bet
#TAKE AWAY CHIPS FORM TOTAL IF LOSE
def lose_bet(self):
self.total -= self.bet
#TAKE BET FROM USER
def take_bet(Chips):
while True:
try:
Chips.bet = int(input("How many chips do you want to bet?: "))
except:
print("There was an error! Enter an integer!\n")
continue
else:
if Chips.bet > Chips.total:
print("You don't have enough chips!\n")
else:
print("Your bet is {} chips\n".format(Chips.bet))
break
#IF PLAYER CHOOSES TO HIT
def hit(deck,hand):
#USE IN hit_or_stay function; ADDS CARD DEALT FROM DECK TO THE HAND and ADJUSTS FOR ACES
Hand.add_card(deck.deal())
Hand.adjust_for_ace()
#DETERMINE WHETHER PLAYER WANTS TO HIT OR STAY
def hit_or_stay(deck,hand):
global playing #controls upcoming loop
while True:
h_or_s = raw_input("Would you like to hit or stay? Enter 'hit' or 'stay': ")
if h_or_s[0].lower() == "h":
hit(deck,hand)
elif h_or_s[0].lower() == "s":
playing = False
else:
print("\nThere was an error. Try again.\n")
continue
break
def show_some(player,dealer):
print("Dealer's Hand:")
print(dealer.cards[0])
print("< card hidden >\n")
print("\nPlayer's hand value: {}".format(player.value))
print("Player's Hand:", *player.cards, sep='\n')
def show_all(player,dealer):
print("\nDealer's hand value: {}".format(dealer.value))
print("\nDealer's Hand:", *dealer.cards, sep='\n')
print("\nPlayer's hand value: {}\n".format(player.value))
print("Player's Hand:", *player.cards, sep='\n')
#GAME ENDING FUNCTIONS
def player_busts(player,dealer,Chips):
#PRINT PLAYER BUSTS; TAKE AWAY CHIPS BET FROM TOTAL CHIPS
print("Dealer's hand value: {}\n Player's hand value: {}\n".format(dealer_hand.value,player_hand.value))
print("Player busts! Dealer Wins\n")
Chips.lose_bet()
print("You lost {} chips!\n You have {} chips remaining.".format(Chips.bet,Chips.total))
def player_wins(player,dealer,Chips):
print("Dealer's hand value: {}\n Player's hand value: {}\n".format(dealer_hand.value,player_hand.value))
print("Player wins!\n")
Chips.win_bet()
print("You won {} chips!\n You have {} chips remaining.".format(Chips.bet,Chips.total))
def dealer_busts(player,dealer,Chips):
print("Dealer's hand value: {}\n Player's hand value: {}\n".format(dealer_hand.value,player_hand.value))
print("Dealer busts! Player wins!\n")
Chips.lose_bet()
print("You won {} chips!\n You have {} chips remaining.".format(Chips.bet,Chips.total))
def dealer_wins(player,dealer,Chips):
print("Dealer's hand value: {}\n Player's hand value: {}\n".format(dealer_hand.value,player_hand.value))
print("Dealer wins!\n")
Chips.lose_bet()
print("You lost {} chips!\n You have {} chips remaining.".format(Chips.bet,Chips.total))
def push(player,dealer,Chips):
print("Player and Dealer tie, its a push!\n")
#GAMEPLAY
while True:
print("Welcome to Black Jack. Get as close to 21 as you can without going over 21.\n")
print("Dealer hits until he reaches 17. Aces count as 1 or 11\n")
#create an instance of Deck class and print the deck
game_deck = Deck()
#shuffle and print the deck
game_deck.shuffle()
#CREATE PLAYER HAND AND DEAL TWO CARDS
player_hand = Hand()
player_hand.add_card(game_deck.deal())
player_hand.add_card(game_deck.deal())
#CREATE DEALER HAND AND DEAL TWO CARDS
dealer_hand = Hand()
dealer_hand.add_card(game_deck.deal())
dealer_hand.add_card(game_deck.deal())
#TAKE BET FROM PLAYER
#player_chips = take_bet(Chips())
#SHOW ONE OF DEALER'S CARDS AND ALL OF PLAYER'S CARDS
show_some(player_hand,dealer_hand)
while playing: #THIS IS WHERE THE NAME ERROR OCCURS!!
if player_hand.value < 21:
#PLAYER CHOOSES HIT OR STAY
hit_or_stay(game_deck(),player_hand)
#SHOW PLAYERS CARDS AND KEEP ONE DEALER CARD HIDDEN
show_some(player_hand,dealer_hand)
NameError: name 'playing' is not defined
global in Python doesn't create a variable, it is defining the existing variable as global. So you are trying to state that a some variable is global (but it is still not exists) and then call it. So you get an error.
Please, never use global in Python! In 99.999% cases you can easily replace your code without any global variables! For example, add playing = True after this part of your code:
#GAMEPLAY
while True:
print("Welcome to Black Jack. Get as close to 21 as you can without going over 21.\n")
print("Dealer hits until he reaches 17. Aces count as 1 or 11\n")
#create an instance of Deck class and print the deck
game_deck = Deck()
#shuffle and print the deck
game_deck.shuffle()
The problem is that playing is defined in hit_or_stay, which isn't called until after the while loop begins.
Define playing as True to start, or include an explicit break condition
while True:
print("Welcome to Black Jack. Get as close to 21 as you can without going over 21.\n")
print("Dealer hits until he reaches 17. Aces count as 1 or 11\n")
# ~snip~
# define here
playing = True
while playing:
# rest of your code
Furthermore, it looks like hit_or_stay also has a while loop in it. I'd suggest taking a look at how you've structured your code so far and maybe refactoring it. Instead of just break in hit_or_stay, maybe you could return playing:
def hit_or_stay(deck,hand):
# no need for global playing anymore, as you return the proper bool
h_or_s = raw_input("Would you like to hit or stay? Enter 'hit' or 'stay': ")
if h_or_s[0].lower() == "h":
hit(deck,hand)
return True
elif h_or_s[0].lower() == "s":
return False
else:
raise ValueError("\nThere was an error. Try again.\n")
playing = True
while playing:
try:
playing = hit_or_stay(deck, hand)
# Catch the error for unexpected input and retry
except ValueError as e:
print(e)
continue

Randomly swapping instance objects from one list to another

I think I need help with my code, I can't tell what the error is or where to fix it. The following are a number of classes that handle a basic deck of playing cards and what it's suppose to do is randomly pick cards from the deck object and put them in the hand object, and then delete the objects from the hand object, so that the next hand I create won't pick up duplicates. Maybe this is an obtuse way of thinking about it, but it seemed to be the best way of managing a deck of cards as it would be in the real world.
The problem is either in the logging method, or in the create_hand() method. When I look at my hand after I run my code, I see the cards in my hand are still in the deck, if I go to the report in the log. Instead, there are different cards that have been removed. It reports the right number of cards taken out of the deck, but it also only reports that hearts are taken out in the tallies that count the number of cards according to suit. However, my hand has a random assortment of unique cards, with unique values and suits. So that part works.
class Suit(Enum):
HEARTS = "Hearts"
CLUBS = "Clubs"
DIAMONDS = "Diamonds"
SPADES = "Spades"
class Card:
def __init__(self, suit, value):
self.suit = suit
self.value = value
if self.suit == 1:
self.suit = Suit.HEARTS
elif self.suit == 2:
self.suit = Suit.CLUBS
elif self.suit == 3:
self.suit = Suit.DIAMONDS
else:
self.suit = Suit.SPADES
#and a host of magic methods that are irrelevant
class Deck:
def __init__(self, deck_size):
self.deck_size = deck_size
self.deck = []
card_suit = 1
card_value = 2
while len(self.deck) < self.deck_size:
self.deck.append(Card(suit=card_suit, value=card_value))
card_value += 1
if card_value > 14:
card_suit += 1
card_value = 2
def log_deck(self):
logging.info("Deck cards: {}".format(len(self.deck)))
hearts = clubs = diamonds = spades = 0
for card in self.deck:
if card.suit == Suit.HEARTS:
hearts += 1
elif card.suit == Suit.CLUBS:
clubs += 1
elif card.suit == Suit.DIAMONDS:
diamonds += 1
else:
spades += 1
logging.info("{} |".format(str(card)))
logging.info("Hearts: {}, Clubs: {}, Diamonds: {}, Spades: {}".format(hearts, clubs, diamonds, spades))
logging.info("*"*20)
class Hand:
def __init__(self, size=2):
self.size = size
self.cards = []
def create_hand(self, deck):
self.cards = []
while len(self.cards) < self.size:
card = random.sample(deck.deck_cards, k=1)
card_value = card[0].value
card_suit = card[0].suit
if card not in self.cards:
self.cards.append(card)
for card in deck.deck_cards:
if card.value == card_value and card.suit == card_suit:
deck.deck_cards.remove(card)
deck.log_deck()
return self.cards
And here's a sample of what the log looks like. For conciseness I cut out most of the cards from the listing:
INFO:root:Deck cards: 47
INFO:root:|2 of Hearts| |
INFO:root:|3 of Hearts| |
INFO:root:|5 of Hearts| |
INFO:root:|6 of Hearts| |
....
INFO:root:|King of Spades| |
INFO:root:|Ace of Spades| |
INFO:root:Hearts: 8, Clubs: 13, Diamonds: 13, Spades: 13
INFO:root:********************
The tallies at the bottom seem to always show that there are only eight hearts after a hand was generated, even if my hand doesn't have hearts, and even if the cards that are missing aren't hearts.
Essentially, I can't figure out if my log is logging things incorrectly, or if I'm not removing cards correctly. Or both. Some testing with creating two hands using the same deck is showing duplicate cards, which is what I'm trying to avoid.
Thanks
Your outer variable card is a list rather than a Card instance.
You append the list containing one item (your sampled card) to your self.cards list, rather than the item itself. I believe that is causing some disruption trying to remove the card in your last line.
I recommend changing card to card[0] in
if card not in self.cards
and
self.cards.append(card)
to see if that fixes the issue.
Moreover, you seem to be sampling from deck.deck_cards; I assume deck is a Deck object, but your given Deck implementation does not seem to have a deck_cards attribute. I would imagine that would throw an AttributeError, though.
Also, to save yourself (and anyone reading your code) some undue confusion, maybe you would want to not overwrite the card variable name in your inner loop.
I got some help from /u/Zigity_Zagity at /r/learnpython at reddit. A slight rewrite of my code, thanks to him:
def create_hand(self, deck):
self.cards = random.sample(deck.deck_cards, k=self.size)
deck.deck_cards = [card for card in deck.deck_cards if card not in self.cards]
deck.log_deck()
return self.cards
And fixing the Card object's __eq__ method:
def __eq__(self, other):
return self.value == other and self.suit.value == other

Go Fish in Python

For my class i have to make a working Go fish game. i got this far in class but I'm stuck i cant figure out how send player back to Hand so i can make a check statement to see if he has any four of a kind. Any suggestions?
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):
self.rank = rank
self.suit = suit
def __str__(self):
rep = self.rank + self.suit
return rep
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) + " "
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)
def check(self,player):
print(player1)
for self.cards in rep:
print("i")
#####################
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 ("Out of cards!")
def main():
deck1 = Deck()
deck1.populate()
deck1.shuffle()
player1 = Hand()
player2 = Hand()
hands = [player1, player2]
deck1.deal(hands, per_hand = 5)
print(player1)
player1.check(player1)
main()
What you said doesn't really make sense . Hand is a class; player1 is an instance of that class. Translating into personal terms, this is parallel to asking how to send Brandon back to human so you can count his teeth. You don't: you simply use the tooth-counting procedure that works on all humans.
Looking specifically at your code, I think this deals with the line
player1.check(player1)
All it should need is
player1.check()
player1 is a Hand; this call goes to Hand's check method. Here, the object that invoked the method automatically shows up as the first argument, self. Get rid of the second one and just use
def check(self):
Does that clarify the point of confusion?
Check this code out, which is a working version of Go Fish executable and playable from the console. See how they use:
def makeTurn(self):
print '%s\'s hand: %s' % (self.name,self.displayHand())
chooseCard = raw_input('What card do you ask for? ').strip()
if chooseCard == 'quit':
sys.exit(0)
if chooseCard not in self.hand:
print 'You don\'t have that card. Try again! (or enter quit to exit)'
chooseCard = self.makeTurn()
return chooseCard
Here is the complete Python Go Fish game.
import random
import sys
from collections import defaultdict
class HumanPlayer(object):
def __init__(self,deck):
self.hand = defaultdict(int)
self.book = []
self.deck = deck #making a copy of deck, all changes within
#this class should affect the global deck
self.score = 0
self.name = raw_input('Name yourself: ')
def Draw(self): #assuming that deck is a global
cardDrawn = self.deck.pop() #removes the last card from deck
self.hand[cardDrawn] += 1 #adds card to hand
print '%s drew %s.' % (self.name,cardDrawn)
self.checkForBooks()
def checkForBooks(self):
# Removes all items of which are 4.
for key,val in self.hand.items(): #can't use iteritems() because we are modifying hand in loop
if val == 4: #completed a book
self.book.append(key)
print '%s completed the book of %s\'s.' % (self.name,key)
self.score += 1
del self.hand[key]
self.emptyCheck()
def emptyCheck(self):
if len(self.deck)!=0 and len(self.hand)==0: #checks if deck/hand is empty
self.Draw()
def displayHand(self): #Displays current hand, cards separated by spaces
return ' '.join(key for key,val in self.hand.iteritems()
for i in range(val)) #meh, make it prettier
def makeTurn(self):
print '%s\'s hand: %s' % (self.name,self.displayHand())
chooseCard = raw_input('What card do you ask for? ').strip()
if chooseCard == 'quit':
sys.exit(0)
if chooseCard not in self.hand:
print 'You don\'t have that card. Try again! (or enter quit to exit)'
chooseCard = self.makeTurn()
return chooseCard
def fishFor(self,card):
if card in self.hand: # if card in hand, returns count and removes the card from hand
val = self.hand.pop(card)
self.emptyCheck()
return val
else:
return False
def gotCard(self,card,amount):
self.hand[card] += amount
self.checkForBooks()
class Computer(HumanPlayer):
def __init__(self,deck):
self.name = 'Computer'
self.hand = defaultdict(int)
self.book = []
self.deck = deck
self.opponentHas = set()
self.score = 0
def Draw(self): #assuming that deck is a global
cardDrawn = self.deck.pop() #removes the last card from deck
self.hand[cardDrawn] += 1 #adds card to hand
print '%s drew a card.' % (self.name)
self.checkForBooks()
##AI: guesses cards that knows you have, then tries cards he has at random.
##Improvements: remember if the card was rejected before, guess probabilities
def makeTurn(self):
# print self.displayHand(),self.opponentHas
candidates = list(self.opponentHas & set(self.hand.keys())) #checks for cards in hand that computer knows you have
if not candidates:
candidates = self.hand.keys() #if no intersection between those two, random guess
move = random.choice(candidates)
print '%s fishes for %s.' % (self.name,move)
return move
def fishFor(self,card): #Same as for humans players, but adds the card fished for to opponentHas list.
self.opponentHas.add(card)
if card in self.hand: # if card in hand, returns count and removes the card from hand
val = self.hand.pop(card)
self.emptyCheck()
return val
else:
return False
def gotCard(self,card,amount):
self.hand[card] += amount
self.opponentHas.discard(card)
self.checkForBooks()
class PlayGoFish(object):
def __init__(self):
self.deck = ('2 3 4 5 6 7 8 9 10 J Q K A '*4).split(' ')
self.deck.remove('')
self.player = [HumanPlayer(self.deck),Computer(self.deck)] #makes counting turns easier
def endOfPlayCheck(self):#checks if hands/decks are empty using the any method
return self.deck or self.player[0].hand or self.player[1].hand
def play(self):
random.shuffle(self.deck)
for i in xrange(9): # Deal the first cards
self.player[0].Draw()
self.player[1].Draw()
turn = 0
while self.endOfPlayCheck():
print '\nTurn %d (%s:%d %s:%d) %d cards remaining.' % (turn,self.player[0].name,
self.player[0].score,self.player[1].name,self.player[1].score,len(self.deck))
whoseTurn = turn%2
otherPlayer = (turn+1)%2
while True: #loop until player finishes turn
cardFished = self.player[whoseTurn].makeTurn()
result = self.player[otherPlayer].fishFor(cardFished)
if not result: #Draws and ends turn
self.player[whoseTurn].Draw()
break
print '%s got %d more %s.' % (self.player[whoseTurn].name,result, cardFished)
self.player[whoseTurn].gotCard(cardFished,result)
if not self.endOfPlayCheck(): break
turn+=1
print '\nScores: \n%s: %d\n%s: %d\n' % (self.player[0].name,self.player[0].score,
self.player[1].name,self.player[1].score)
if self.player[0].score>self.player[1].score:
print self.player[0].name,'won!'
elif self.player[0].score==self.player[1].score:
print 'Draw!'
else:
print self.player[1].name,'won!'
if __name__=="__main__":
game = PlayGoFish()
game.play()

Categories