Deck card class in python - python

I am working on creating a class for the first time, and I am thinking that I have done every thing to get it run, but I still get bunch of issues which is 'list' object has no attribute 'shffule' so the problem here is it will not shuffle the cards, and it will not tell the remaining cards, can any one tell me what am I doing wrong? Thanks in advance
import random
class card_deck:
def __init__(self, rank, suite, card):
self.rank= rank
self.suite = suite
def ranks(self):
return self.rank
def suites(self):
return self.suite
def cards(self,card):
suit_name= ['The suit of Spades','The suit of Hearts', 'The suit of Diamonds','Clubs']
rank_name=['Ace','2','3','4','5','6','7','8','9','10','Jack','Queen','King']
def value(self):
if self.rank == 'Ace':
return 1
elif self.rank == 'Jack':
return 11
elif self.rank == 'Queen':
return 12
elif self.rank == 'King':
return 13
def shffule(self):
random.shuffle(self.cards)
def remove(self,card):
self.cards.remove(card)
def cardremaining(self):
self.suite-self.rank
def main():
try:
deck=[]
for i in ['Spades','Hearts', ' Diamonds','Clubs']:
for c in ['Ace','2','3','4','5','6','7','8','9','10','Jack','Queen','King']:
deck.append((c, i))
deck.shffule
hand = []
user =eval(input('Enter a number of cards: 1-7 '))
print()
while user <1 or user >7:
print ("Only a number between 1-7:")
return main()
for i in range(user):
hand.append(deck[i])
print (hand)
except ValueError:
print("Only numbers")
main()

Apart from your code containing many small errors; I will try to answer your main problems.
If you are going to use shffule[sic] method of card_deck class, then you first need to create an instance of that class(whereas you tried to call that method with a list). Like this:
deck = card_deck(some_rank,some_suit,some_card)
deck.shffule() #Now you can call the method
Now, since you made it a class instance, you cannot get items from it like hand.append(deck[i])
Unless you defined the method __getitem__ in your class definition, like this:
#this will be in your class definition
def __getitem__(self,i):
return self.card_list[i] #Of course you have to define a list of cards in your class too.
In my opinion, you should spend a little more time trying to understand how is a class defined, how does methods work and how to access members of a class. After that you will be doing much better here

You are never actually creating an instance of the card_deck class. The expression
deck=[]
creates a variable named deck referring to an empty list.
In python, [a, b, c,...] is the syntax for creating list literals.

from collections import namedtuple
Card = namedtuple('Card', 'sign, value') # no need to write class to represent card
SIGNS = ['Hearts', 'Diamonds', 'Spades', 'Clubs']
class Deck:
def __init__(self):
self.cards = [Card(sign, value) for sign in SIGNS for value in range(2,
11) +
'J Q K A'.split()]
def __repr__(self):
return str([str(card) for card in self.cards])
def __len__(self):
return len(self.cards)
def __getitem__(self, item):
return self.cards[item]
def __setitem__(self, key, value):
self.cards[key] = value
deck = Deck()
print deck[11] # indexing works, prints Card(sign='Hearts', value='K')
print len(deck) # prints 52
print deck[13:16] # slicing works
import random
random.shuffle(deck) # shuffle works using no extra code

Related

Python: How to compare elements within an array of cards

I am working on a texas hold-em game in python, and am looking to traverse an array containing a complete hand of 7 cards (2 in the hole + 5 on the board). The array contains elements of class Cards, where the Card class constructor is
class Card:
def __init__(self, suit, val):
self.suit = suit
self.value = val
So, I have a "hand" array within a "Player" class of 7 random cards, where the suit is one of 4 strings (spade, club, heart, diamond) and the value is one of 9 numbers (2-10) or 4 strings (jack-ace). I want to traverse the array to check if the list contains any of the hands in poker, but I'm failing to figure out how I can "extract" the suit/value of the cards from my array. I've started a method within my "Player" class to check for a suit, here that suit is a spade.
class Player:
def __init__(self, name):
self.name = name
self.pocket = []
self.hand = []
def spadeChecker(self):
card = Card("Blank", 0)
for i in self.hand:
card = self.hand[i]
if(card.suit == "Spade"):
print("Hi! you have a spade!")
else:
pass
When running the program from my terminal I receive a TypeError message:
in spadeChecker card = self.hand[i] TypeError: list indices must be integers or slices, not Card
I know my method is pretty bad but I'm very new to this and just can't figure out how to get it to work. Any advice?
Thanks
Here is the rewritten method, including an example with a 3 card hand.
class Card:
def __init__(self, suit, val):
self.suit = suit
self.value = val
class Player:
def __init__(self, name):
self.name = name
self.pocket = []
self.hand = [Card("Heart", 10), Card("Spade", 10), Card("Diamond", 10)]
def spadeChecker(self):
for card in self.hand:
if(card.suit == "Spade"):
print("Hi! you have a spade!")
#return True
else:
#return False
pass
p = Player("Bob")
p.spadeChecker()
Output is:
Hi! you have a spade!
In your code, your iterator is i and your iterable is self.hand, which is a list of Card objects. Thus, i will be a Card object each time the loop iterates. If you want to be able to get the index of the Card object as well as the Card object itself, I recommend using the enumerate() function. However, since you only reference the Card objects, you can just get the suit attribute directly.
class Player:
def __init__(self, name):
self.name = name
self.pocket = []
self.hand = []
def spadeChecker(self):
card = Card("Blank", 0)
for card_obj in self.hand:
if(card_obj.suit == "Spade"):
print("Hi! you have a spade!")
else:
pass
There's a Python library for generating, comparing & evaluating poker hands called tilted which can be found here: https://github.com/MaxAtkinson/tilted
I've used it myself before and it's really easy. This may allow you to avoid having to implement it yourself.

Why the result is always None?

class Deck(object):
def __init__(self,starting_cards = None):
self._cards = starting_cards
def get_cards(self):
if self._cards==None:
return []
else:
return self._cards
def add_cards(self,new_cards):
if self._cards == None:
self._cards = []
self._cards.extend(new_cards)
else:
self._cards.extend(new_cards)
class Player(object):
def __init__(self,name):
self._name= name
def get_deck(self):
return Deck()
So if I input:
a = Player('a')
b = [1,2,3,4]
a.get_deck.add_cards(b)
a.get_deck.get_cards
It just return [], but is should be [1,2,3,4], why?
But if I change
'def init(self,starting_cards = None):'
to
'def init(self,starting_cards = []):'
it could give the '[1,2,3,4]'
That's because you always returned new Deck instance in get_deck() function.
You should have Deck instance as member variable of Player.
It seems like you're never storing a players deck. Every time you call getDeck it looks to be creating a new deck object.
Second Aran-Fey's comment. Your get_deck function returns a deck, so callinga.get_deck.add_cards(b) will first return a deck, and add b cards to this deck, but this deck is not stored anywhere.
You could do
xyqrz = a.get_deck() then xyqrz.add_cards(b) and call xyqrz.get_cards().

Questions about prinitng python deck of cards?

So, I've got the basic deck of cards, but I am having trouble with the printing process. My professor is having us use the eq and str method, hence the reason I used that in my code. Any suggestions for where I am going wrong? How do I change the main section to convert each card in a returned hand to a string and only print it then?
import random
class Deck(object):
"""Represent a deck of 52 playing cards."""
def __init__(self, start_shuffled):
"""Initializes a deck with 52 cards."""
suits=["H","S","D","C"]
ranks= list ( range(2, 11)) + ["J", "Q", "K", "A"]
self.cards=[]
for suit in suits:
for rank in ranks:
self.cards.append(Card(suit, rank))
if start_shuffled:
random.shuffle(self.cards)
def __str__(self):
res = []
for card in self.cards:
res.append(str(card))
return '\n'.join(res)
def has_card(self, card):
return card in self.cards
def draw_random_card(self):
card=random.choice(self.cards)
self.cards.remove(card)
return card
def draw_hand(self, num_cards):
cards=[ ]
for _ in range(num_cards):
cards.append(self.draw_random_card())
return cards
class Card(object) :
def __init__(self, s , r):
self.suit=s
self.rank=r
def __str__(self):
rep = self.rank + self.suit
return rep
def __eq__(self, other_card):
t1 = self.suit, self.rank
t2 = other_card.suit, other_card.rank
return eq(t1, t2)
def main():
deck1=Deck(True)
print("All the cards in the deck:")
print(deck1.cards)
print("Does the deck have the Queen of Hearts? True or False")
print(deck1.has_card(Card("H", "Q")))
card=deck1.draw_random_card()
print("A random card from the deck:")
print(card)
if deck1.has_card(card):
print("Something bad happened...")
print(card, "Shouldn't be in the deck anymore.")
print("A hand of six random cards:")
print (deck1.draw_hand(6))
if __name__=="__main__":
main()
You're getting a NameError on this line:
return eq(t1, t2)
Because there's no such function, eq. Just use the equality operator.
return t1 == t2
Then, you're getting a TypeError on this line:
rep = self.rank + self.suit
Because sometimes rank is an integer, and you can't add an integer and a string together. Convert rank to a string before concatenating.
rep = str(self.rank) + self.suit
Then, when you print the whole deck, it shows something like <__main__.Card object at 0x00000000024A19E8>, because objects don't use __str__ when you print them inside a collection. Implement a __repr__ method for your cards.
def __repr__(self):
return self.__str__()
Now you should be getting nicer output.
All the cards in the deck:
[10H, QS, 9D, 10C, 5S, AS, 5C, 10D, AC, 9C, 3H, 3D,
6H, JH, AD, 7D, KC, 7H, JD, 9H, 8H, 3C, 3S, 4H, 8C,
QD, 6C, 9S, QC, 6D, JS, 7S, 5H, 10S, KH, 2C, 7C, JC,
6S, 4D, 4S, 5D, 4C, AH, 2S, 8S, 8D, KS, 2D, KD, 2H, QH]
Does the deck have the Queen of Hearts? True or False
True
A random card from the deck:
3H
A hand of six random cards:
[3D]
Couple things:
Check your indentation on draw_hand. You're never putting more than one card in the hand to return.
Change __str__ to __repr__. I did this and it starting printing out fairly normally for me. There is a good discussion on the difference between__str__ and __repr__ here
There are a few other compile type issues, such as a direct called to __eq__, but Kevin already addressed those.

Create a function that consumes a list of cards and produces a list of those cards which are red and odd

I have to write the function red_odd, which consumes a list of cards, hand, and produces a list of those cards which are red (i.e., "diamonds" or "hearts") and have an odd value, in the order they appear in the consumed list. The consumed list cannot be mutated.
For example,
red_odd([card1, card2, card3, card4]) => [card2]
So I have this so far:
class card:
'Fields: suit, value'
def __init__(self, suit, value):
self.suit = suit
self.value = value
card1 = card('spades', 8)
card2 = card('hearts', 5)
card3 = card('diamonds', 6)
card4 = card('clubs', 5)
def red_odd(hand):
card_list = []
for c in hand:
if (c.suit == 'diamonds' or c.suit == 'hearts') and (c.value / 2 != 0):
card_list.append(c)
return card_list
It doesn't run and I'm not sure where I went wrong. Thanks for any help.
You just need to call your function:
odd_red_cards = red_odd([card1,card2,card3,card4])
print(odd_red_cards)
That'll give you a little more to debug.
Note that it might be useful to add a __str__ or __repr__ function to allow your cards to print a little more naturally which could be useful for finding other bugs down the road. e.g.:
class card(object):
...
def __repr__(self):
return '{suit} {value}'.format(suit=self.suit,value=self.value)

Accessing a class/method from another program in Python

I have a program (blackjack.py) and it accesses another program's (cards.py and games.py) within its code. Most of this is from a book, so I'm having trouble understanding how it works.
Heres the code for cards.py:
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 round 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.")
I'm writing an error check for the blackjack.py and I need to gather the number of cards that have been used so far. I think I can do that by accessing the number of values in cards[]. The problem is, I am not sure on how to do that.
This is all in theory though. I will include the `blackjack.py' code as well, so you all can see what I am trying to do, and help me determine if my logic is flawed.
blackjack.py code
Any and all input is appreciated.
While I'm not entirely clear on your intended structure here, you have a couple of options.
First, in order to use any functions or classes from cards.py in your blackjack.py module, you can use the import statement to import them. There are two styles of doing this:
# blackjack.py
import cards
Would give you access to everything in the cards module, and you'd call each function/class by prefacing it with cards.<name>. So, if you wanted to initialize an instance of the Deck class,
# blackjack.py
import cards
mydeck = cards.Deck()
The other way is the from <X> import <Y>, which gives you access to the functions and classes without having to add the prefix. Example:
# blackjack.py
from cards import Deck # or, to import everything, "from cards import *"
mydeck = Deck()
Either of these methods would give you an instance of the cards.Deck class.
Option 0
You can already tell this within your Deck class, since it subclasses from Hand, so every time you give a card it's taking out out of the Deck's cards attribute. Thus, the number of cards given out would simply be:
class Deck(Hand):
# ...
def number_cards_used(self):
return 52 - len(self.cards)
Alternatively, if you can't edit cards.py, you can simply get the number of cards left from your given Deck by:
# blackjack.py
def get_number_cards_used_from_deck(deck):
return 52 - len(deck.cards)
In use:
# blackjack.py
import cards
mydeck = cards.Deck()
# ...
# Do other operations with deck
# ...
cards_used = get_number_cards_used_from_deck(mydeck)
Option 1
If you can isolate all of and only those hands being played simultaneously, you can implement a method card_count:
class Hand(object):
# ...
# other code
# ....
def card_count(self):
return len(self.cards)
Then, if you have a list of all the hands, for example, you could do something like:
sum(map(lambda h: h.card_count(), list_of_hands))
Option 2
Within your Deck class, since it subclasses Hand, you could simply keep another running list of the cards that have been given out that would often be refreshed. This would look like:
class Deck(Hand):
# ...
# other code
# ...
def __init__(self):
self.populate()
self.used_cards = []
def give(self, card, other_hand):
self.used_cards.append(card)
super(Deck, self).give(card, other_hand)
def number_cards_used(self):
return len(self.used_cards)
There are other methods, of course.

Categories