Below is a class of a deck of cards from 'Fluent Python' by Luciano Romalho.
I hope it's ok that I have copied the code, I really don't have a better more concise class example than this one.
import collections
from random import choice
Card = collections.namedtuple('Card', ['rank', 'suit'])
class FrenchDeck:
ranks = [str(n) for n in range(2, 11)] + list('JQKA')
suits = 'spades diamonds clubs hearts'.split()
def __init__(self):
self._cards = [Card(rank, suit) for suit in self.suits
for rank in self.ranks]
def __len__(self):
return len(self._cards)
def __getitem__(self, position):
return self._cards[position]
so, an instance of this class will have 52 cards, each a namedtuple as defined in 'Card' object.
I wanted to draw a hand of n cards so that it will reflect in the deck.
I tried the following:
def a_hand(deck, size):
the_hand = []
for n in range(size):
c = choice(deck)
the_hand.append(c)
deck = [i for i in deck if i != c]
return the_hand
so when I try:
>> deck = FrenchDeck()
>> a = a_hand(deck, 5)
I get a hand but the deck is untouched:
>> hand
[Card(rank='9', suit='spades'),
Card(rank='A', suit='hearts'),
Card(rank='2', suit='diamonds'),
Card(rank='8', suit='clubs'),
Card(rank='10', suit='hearts')]
>> len(deck)
52
when I try directly in the interperter:
>> c = choice(deck)
>> alt = [i for i in deck if i != c]
it works:
>> len(alt)
51
I understand that this is due to the FrenchDeck's instance not being affected by what is happening in the scope of the function a_hand.
What would be the way to do it? I tried to define a dunder-delitem function in the class but didn't get it right, also wasn't sure if this was the right function to use and whether it was to be defined in the Card object or in the FrenchDeck object.
Really you just need to move a_hand to be a method of FrenchDeck:
class FrenchDeck:
# All previous code here, plus:
def a_hand(self, size):
the_hand = []
for n in range(size):
c = choice(self._cards)
the_hand.append(c)
self._cards.remove(c)
return the_hand
You're right that it's due to the fact that FrenchDeck instance is not modified inside a_hand function. Instead, you only override deck variable. To achieve your goal, you could e.g. add deal_hand method to FrenchDeck class, that will return a hand of given size and remove selected cards from deck itself.
You create a new deck instead of updating the existing deck.
deck = [i for i in deck if i != c]
This creates a new list, built by the list comprehension, and makes deck point to it, instead of pointing at the original list that was passed.
You need is to use deck.remove(...) if you are to alter the existing list.
(Also: try making the deck and hands sets, not lists. It matches the domain better.)
When you get a card from the deck, also remove it from the deck. Use list.pop in __getitem__.
class FrenchDeck:
ranks = [str(n) for n in range(2, 11)] + list('JQKA')
suits = 'spades diamonds clubs hearts'.split()
def __init__(self):
self._cards = [Card(rank, suit) for suit in self.suits
for rank in self.ranks]
def __len__(self):
print(f'__len__ called: {len(self._cards)}')
return len(self._cards)
def __getitem__(self, position):
print(f'getting item {position}')
return self._cards.pop(position)
def a_hand(deck, size):
the_hand = []
for n in range(size):
print('getting another card')
c = choice(deck)
the_hand.append(c)
return the_hand
deck = FrenchDeck()
a = a_hand(deck, 5)
Related
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().
So far I have this:
def make_deck():
deck = []
for suit in "HDSC":
for rank in "JQKA23456789T":
deck.append(rank + suit)
random.shuffle(deck)
return deck
def cards(deck, number_players): # What should I do for this function?
deck = make_deck()
for i in range:
hands = []
player_hand = [deck.pop(), deck.pop()]
return hands
I should be producing outputs that look like this:
hands = cards(deck, 3)
print(hands)
[['5H', '3H'], ['5S', '4S'], ['7H', '4H']]
So the user determines how many couple of cards are printed.
I see a couple of errors as noted in the code below:
def make_deck():
deck = []
for suit in "HDSC":
for rank in "JQKA23456789T":
deck.append(rank + suit)
random.shuffle(deck)
return deck
def cards(deck, number_players):
hands = [] # define hands outside of the for loop
for i in range(number_players): # You need to specify a range
hands.append([deck.pop(), deck.pop()]) # give each player a hand size of 2
return hands
# finally put it all together by creating a new deck and passing it into cards()
cards(make_deck(), number_players)
I tried my best to intuit what the program was meant to do. Is this what you were looking for?
You can try this, and deck argument is redundant in your defined function cards(). But you can rewrite the code if you want deck is changeable.
import random
def make_deck():
deck = []
for suit in "HDSC":
for rank in "JQKA23456789T":
deck.append(rank + suit)
random.shuffle(deck)
return deck
def cards(number_players):
deck = make_deck()
hands = []
for i in range(number_players):
hands.append([deck.pop(), deck.pop()])
return hands
Recall function:
hands = cards(3)
print(hands)
Create a class Deck that represents a deck of cards. Your class should have the following methods:
constructor: creates a new deck of 52 cards in standard order.
shuffle: randomnizes the order of the cards.
dealCard: returns a single card from the top of the deck and removes the card from the deck
cardsLeft: returns the number of cards remaining in the deck.
Test your program by having it deal out a sequence of n cards from a shuffle deck where n is the user input.
class Deck:
def __init__(self):
self.cardList=[]
for suit in ["d","c","h","s"]:
for rank in range(1,14):
card=PlayingCard(suit, rank)
self.cardList.append(card)
def shuffle(self):
#I DON'T KNOW HOW TO SHUFFLE MY CARDS PLEASE HELP.
#self.cardList[pos1] = self.cardList[pos2]
#self.cardList[pos2] = self.cardList[pos1]
#these two lines above are not working
def dealCard(self):
return self.cardList.pop()
def cardsLeft(self):
return len(self.cardList)
Read the docs on random.shuffle. It should help you greatly! :)
from collections import namedtuple
from random import shuffle
PlayingCard = namedtuple('PlayingCard', "suit rank")
class Deck:
def __init__(self):
self.cardList = [PlayingCard(suit, rank) for suit in"dchs" for rank in range(1,14)]
def shuffle(self):
shuffle(self.cardList)
def dealCard(self):
return self.cardList.pop()
def cardsLeft(self):
return len(self.cardList)
d = Deck()
d.shuffle()
print [d.dealCard() for _ in range(5)]
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
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)