Why is my nested loop only picking up some items? - python

I'm trying to get the loop to go through all suits then all of the card numbers to create a deck of cards but it seems to be pulling alternating values. I have the range set at the bottom as 26 because I was getting out of range errors going any higher.
import random
# actual deck creation using Card class
class Deck:
def __init__(self):
suits = ["Spades", "Clubs", "Hearts", "Diamonds"]
numbers = {"two": ["Two", 2], "three": ["Three", 3], "four": ["Four", 4], "five": ["Five", 5],
"six": ["Six", 6],
"seven": ["Seven", 7], "eight": ["Eight", 8], "nine": ["Nine", 9], "ten": ["Ten", 10],
"jack": ["Jack", 10], "queen": ["Queen", 10], "king": ["King", 10], "ace": ["Ace", 1]}
self.cards = []
for suit in suits:
for number in numbers.values():
self.cards.append(Card(suit, number))
def shuffledeck(self):
random.shuffle(self.cards)
return self.cards
def cleardeck(self):
self.cards = []
return self.cards
class Card:
def __init__(self, suit, value):
self.suit = suit
self.value = value
# card print statement
def __str__(self):
return self.value + " of " + self.suit
class Game:
def __init__(self):
self.deck = []
def play(self):
self.deck = Deck()
#self.deck.shuffledeck()
game = Game()
game.play()
#testing area
blah = []
for i in range(26):
card = (game.deck.cards.pop(i))
print(card.suit)
blah.append(card.value)
print(str(blah))

You are popping an item at a specific index, while increasing the index; this will not exhaust all the items in game.deck.cards. Try instead, for example,
for i in range(52):
card = (game.deck.cards.pop())
Or pop(0) if you want to preserve the order, although this is said to be slower than pop(). If you really don't need to empty game.deck.cards, then the following might be simpler:
for card in game.deck.cards:
print(card.suit)
blah.append(card.value)

Related

Popping and appending values from one class object to another

I'm trying to create the card game War, where two players draw a card, and the player with the higher card rank "appends" the card from the opponent. Here is my code so far:
import random
class Card(object):
def __init__(self, val):
self.value = val
def __str__(self):
return("{}".format(self.value))
def show(self):
print("{}".format(self.value))
class Deck:
def __init__(self):
self.cards = []
self.build()
def build(self):
for v in {'2' : 0, '3' : 1, '4' : 2, '5' : 3, '6' : 4, '7' : 5, '8' : 6, '9' : 7 , '10' : 8, 'Jack' : 9, 'Queen' : 10, 'King' : 11, 'Ace' : 12}:
for i in range(0,2): #suits removed; only prints half of a deck
self.cards.append(Card(v))
def divide(self):
global half
half = len(self.cards)//2
def show(self):
for c in self.cards:
c.show()
def shuffle(self):
for i in range(len(self.cards)-1, 0, -1):
r = random.randint(0, i)
self.cards[i], self.cards[r] = self.cards[r], self.cards[i]
def drawCard(self):
return self.cards.pop()
class Player:
def __init__(self, name):
self.name = name
self.hand = []
def draw(self,deck):
self.hand.append(deck.drawCard())
return self
def showHand(self):
for card in self.hand:
print(f"{self.name} drew a {card}!")
def discard(self, opponent):
print("Card discarded!")
self.hand.pop()
self.hand.appendleft(opponent)
deck1 = Deck()
deck2 = Deck()
deck1.shuffle()
deck2.shuffle()
deck1.show()
print()
deck2.show()
print(input("This is a card game known as War"))
print(input("It is a luck-based game where you have to annihilate your opponent's deck"))
print(input("Each player draws a card, and whoever gets the higher value gets the card"))
print(input("Otherwise both players simultaneously draw four extra cards, where the final card determines the higher value, otherwise keep drawing four cards until a higher value is chosen"))
print(input("The winner is the one who gets all of their opponent's cards. Ready, begin!"))
player1 = Player(input('Player 1, pick a name: '))
player2 = Player(input('Player 2, Pick a name: '))
player1.draw(deck1)
player2.draw(deck2)
player1.showHand()
player2.showHand()
player1.discard(player2)
So I want to create the method within the Player class by utilizing stacks and queues. However, my issue is that I am not sure how appending and popping list indices would work between two objects (player1 and player2) and every method I tried so far resulted in an attribute error. Any ways to fix that?

Is there a way to sort objects created through classes that is made up of both strings and integers in Python?

I have an assignment to create a deck of cards through the use of a class with methods that deal, shuffle, fan, order and checks if the deck is in order but I am having trouble creating the last one. The deck must be ordered by their values in each suit, and the suits ordered as Clubs, Diamonds, Hearts, and then Spades. My code up to this point is found below:
import random
class Card():
def __init__(self, value, suit):
self.value = value
self.suit = suit
def show_card(self):
print(str(self.value)+ " of " + str(self.suit))
class Deck():
deck_of_cards = []
cards_in_play = []
draw_card = None
def __init__(self):
self.make_deck()
def make_deck(self):
for suit in ['Clubs', 'Diamonds', 'Hearts', 'Spades']:
for value in [2, 3, 4, 5, 6, 7, 8, 9, 10, 'Jack', 'Queen', 'King', 'Ace']:
self.deck_of_cards.append(Card(value,suit))
self.cards_in_play.append(Card(value, suit))
def shuffle(self):
self.shuffled_deck = random.shuffle(self.cards_in_play)
def fan(self):
for card in self.cards_in_play:
card.show_card()
def deal(self):
draw_card=self.cards_in_play.pop()
draw_card.show_card()
def order(self):
for suit in ['Club', 'Diamonds', 'Hearts', 'Spades']:
for value in [2, 3, 4, 5, 6, 7, 8, 9, 10, 'Jack', 'Queen', 'King', 'Ace']:
self.deck_of_cards.append(Card(value, suit))
self.cards_in_play.append(Card(value, suit))
Some code fixes before we go on:
Universalize the suits and values list so that it can be used by all classes if needed.
Move deck_of_cards and cards_in_play inside the __init__ function. If you do not, this is called a "class attribute" and will make it so every class has that value if not initialized (likely something you do not intend).
class Test:
a = 10
t1 = Test
t2 = Test
t1.a = 11
print(t2.a) # >>> 11
random.shuffle() is a function that runs in place. In other words, it returns None, but modifies the list given to it.
import random
l = ["a", "b", "c"]
print(random.shuffle(l)) # >>> None
print(l) # >>> [b, c, a]
Don't print things -- return them. It will make your code not only clearer, but also more useful. If you want to print something that a function returns, just simply print the return.
def deal(self):
draw_card = self.cards_in_play.pop()
return draw_card
Familiarize yourself with sort and the __lt__ (detail below).
import random
suits = ['Clubs', 'Diamonds', 'Hearts', 'Spades']
values = [2, 3, 4, 5, 6, 7, 8, 9, 10, 'Jack', 'Queen', 'King', 'Ace']
class Card:
def __init__(self, value, suit):
self.suit = suit
self.value = value
def __lt__(self, other):
if suits.index(self.suit) > suits.index(other.suit):
return False
if values.index(self.value) > values.index(other.value):
return False
return True
def __repr__(self):
return f"{self.value} of {self.suit}"
class Deck:
def __init__(self):
self.deck_of_cards = []
self.cards_in_play = []
self.make_deck()
def make_deck(self):
for suit in suits:
for value in values:
self.deck_of_cards.append(Card(value,suit))
self.cards_in_play.append(Card(value, suit))
def shuffle(self):
random.shuffle(self.cards_in_play)
def fan(self):
for card in self.cards_in_play:
print(card)
def deal(self):
draw_card = self.cards_in_play.pop()
return draw_card
def order(self):
self.cards_in_play.sort()
def __repr__(self):
return repr(self.cards_in_play)
Utilizing the magic method __lt__ (less than), we can use the function sort to automatically sort a class. To make the point more clear, notice the following:
# Your new `order` function.
def order(self):
self.cards_in_play.sort()
# Implementing __lt__ now allows us to do the following comparison (which is what sort will use to sort your list of Card objects):
print(Card("Clubs", 2) > Card("Clubs", 3)) # True
# If you notice on docs, __ge__ (greater than), __eq__ (equal than), etc. can also be implemented to give you full flexibility.
Notice I also added the __repr__ function to both Deck and Card so that you can instead more simply do:
card = Card("Clubs", 2)
print(card) # >>> 2 of Clubs
Edit: #Discussion below.
suits = ['Clubs', 'Diamonds', 'Hearts', 'Spades']
values = [2, 3, 4, 5, 6, 7, 8, 9, 10, 'Jack', 'Queen', 'King', 'Ace']
class Card:
def __init__(self, value, suit):
self.suit = suit
self.value = value
def __lt__(self, other):
if suits.index(self.suit) > suits.index(other.suit):
return False
if values.index(self.value) > values.index(other.value):
return False
return True
def __eq__(self, other):
if self.suit == other.suit and self.value == other.value:
return True
else:
return False
def __repr__(self):
return f"{self.value} of {self.suit}"
With the new __eq__ method, we can use the == sign between classes.
c1 = Card(2, "Clubs")
c2 = Card(2, "Diamonds")
c3 = Card(2, "Diamonds")
print(c1 == c2) # False
print(c1 > c2) # False
print(c1 < c2) # True
print(c2 == c3) # True
This allows us to compare the Cards with ease.
You can initialize your Card class as follows:
values = [2, 3, 4, 5, 6, 7, 8, 9, 10, 'Jack', 'Queen', 'King', 'Ace']
suits = ['Clubs', 'Diamonds', 'Hearts', 'Spades']
class Card:
def __init__(self, value, suit):
self.suit = suit
self.value = value
#if value order matters in first place
self.rank = 4*values.index(self.value) + suits.index(self.suit)
#else
self.rank = 13*suits.index(self.suit) + values.index(self.value)
and create the check function as follows:
class Deck:
def check(self):
rank_before = self.cards_in_play[0].rank
for card in self.cards_in_play[1:]:
rank = card.rank
if rank > rank_before:
rank_before = rank
else:
return False
return True
The canonical way to handle this is to realize that you have two identities for the card: its play value and its display value. You need a simple cognate to the __repr__ function.
Very simply, value value with a simple rank integer, card_rank, 0-12. The display value, what you print any time a human refers to it, is handled with a trivial translation list:
print_value = (
'2', '3', '4', '5', '6', '7', '8', '9', '10',
'Jack', 'Queen', 'King', 'Ace'
)
Whenever you need to output a value, you simply use print_value[card_rank]. Put this into the __repr__ function of your Card class.
With this partitioning of functionality, sorting by card_rank solves your problem without further ado.

Python random shuffle not working in my even though it should

Hello guys first time posting here.
I have a problem i cant explain. I am trying to replicate poker but my deck shuffle function isnt working
First my code
class Start(object):
openCards = []
def __init__(self, numofplayer):
print("started")
finished = False
self.deck = Deck()
self.deck.shuffle()
for card in self.deck:
card.isshowing = True
print(card)
self.players = []
i = 0
while i < numofplayer:
player = Player()
self.players.append(player)
i = i + 1
class Deck(list):
def __init__(self):
self.cards = []
suits = ["Herz", "Piek", "Karo", "Kreuz"]
values = {
"zwei": 2,
"drei": 3,
"vier": 4,
"fünf": 5,
"sechs": 6,
"sieben": 7,
"acht": 8,
"neun": 9,
"zehn": 10,
"bube": 11,
"dame": 12,
"könig": 13,
"ass": 14
}
for value in values:
for suit in suits:
self.cards.append(Card(value, suit))
def shuffle(self):
random.shuffle(self)
print("Karten gemischt")
def __repr__(self):
cardsleft = len(self.cards)
return "Es sind noch {0} karten übrig".format(cardsleft)
def deal(self):
return self.cards.pop(0)
Ok so my problem at self.deck.shuffle() as i think this should randomize the order of my deck but if i take a look at the variable in debug mode its still in ist standard order. why?
As everyone is saying, you probably don't want to inherit from list if your cards are defined as a list within your class.
import random
class Card:
def __init__(self, value, suit):
self.suit = suit
self.value = value
def __repr__(self):
return f'{self.value} von {self.suit}'
class Start:
openCards = []
def __init__(self, numofplayer):
self.deck = Deck()
self.deck.shuffle()
# here we iterate through the cards rather than the deck object
for card in self.deck.cards:
card.isshowing = True
print(card)
self.players = []
class Deck():
def __init__(self):
self.cards = []
suits = ["Herz", "Piek", "Karo", "Kreuz"]
values = {
"zwei": 2,
"drei": 3,
"vier": 4,
"fünf": 5,
"sechs": 6,
"sieben": 7,
"acht": 8,
"neun": 9,
"zehn": 10,
"bube": 11,
"dame": 12,
"könig": 13,
"ass": 14
}
for value in values:
for suit in suits:
self.cards.append(Card(value, suit))
def shuffle(self):
# we also shuffle the cards sins that's what they're assigned to
random.shuffle(self.cards)
print("Karten gemischt")
def __repr__(self):
# we also show the length of the cards
cardsleft = len(self.cards)
return "Es sind noch {0} karten übrig".format(cardsleft)
Start(5)
If you really want to inherit from list you can do it like so.
import random
class Card:
def __init__(self, value, suit):
self.suit = suit
self.value = value
def __repr__(self):
return f'{self.value} von {self.suit}'
class Start:
openCards = []
def __init__(self, numofplayer):
self.deck = Deck()
self.deck.shuffle()
# inheriting from list allows you to iterate through the deck object
# since it inherits a __next__ method from list
for card in self.deck:
card.isshowing = True
print(card)
self.players = []
class Deck(list):
def __init__(self):
# we send a super call to lists constructor
super().__init__()
suits = ["Herz", "Piek", "Karo", "Kreuz"]
values = {
"zwei": 2,
"drei": 3,
"vier": 4,
"fünf": 5,
"sechs": 6,
"sieben": 7,
"acht": 8,
"neun": 9,
"zehn": 10,
"bube": 11,
"dame": 12,
"könig": 13,
"ass": 14
}
for value in values:
for suit in suits:
# here we simply use the append method we inherited from list
self.append(Card(value, suit))
def shuffle(self):
# doing it this way allows us to shuffle self
random.shuffle(self)
print("Karten gemischt")
def __repr__(self):
# we also need to show the length of self
cardsleft = len(self)
return "Es sind noch {0} karten übrig".format(cardsleft)
Start(5)

Creating a card game with Python classes

I am trying to practice programming classes in Python by creating a card game. Right now what I want to achieve is to get a player to draw a card from the deck. I have the code as follows:
class Deck():
def __init__(self):
#create the deck
self.deck = []
self.discard_pile = []
def create_deck(self):
#assign the number of cards for each type to a card (dict)
deck_stats = {"A":4, "B":6, "C":5, "D":5, "E":5, "F":5, "G":5, "H":5, "I":5, 'J':5}
for card in deck_stats.keys():
for i in range(0,deck_stats[card]):
self.deck.append(card)
return self.deck
def shuffle(self):
#randomise the deck or for when the shuffle card is played
random.shuffle(self.deck)
return self.deck
def pickup(self):
#picks up the first card on the draw pile
picked_up = self.deck.pop(0)
print(picked_up)
return picked_up
And the player class:
class Player(Deck):
def __init__(self):
self.player_hand = ["defuse"]
for i in range(6):
self.draw_card()
def draw_card(self):
#draw pile reduces by one
deck = Deck()
deck.create_deck()
deck.shuffle()
self.player_hand.append(deck.pickup())
return self.player_hand
In the draw_card()method from the Player class I've called the pickup method from the Deck class. Which I believe is the wrong thing to do but I'm not sure how else to pickup a card from the Deck object.
Also, the draw_card method obviously doesn't work the way it's supposed to as it is creating a new deck every time and then picking up from the new deck (at least that's what I think it is doing right now). This brings me back to my original question, how do I get a player to pickup a card from the same Deck such that I don't need to create a new Deck every time?
Try something like
class Deck():
def __init__(self):
# create the deck
self.discard_pile = []
self.deck = self.create_deck()
self.shuffle()
def create_deck(self):
deck = []
# assign the number of cards for each type to a card (dict)
deck_stats = {"A": 4, "B": 6, "C": 5, "D": 5, "E": 5, "F": 5, "G": 5, "H": 5, "I": 5, 'J': 5}
for card in deck_stats.keys():
for i in range(0, deck_stats[card]):
deck.append(card)
return deck
def shuffle(self):
# randomise the deck or for when the shuffle card is played
random.shuffle(self.deck)
return self.deck
def pickup(self):
# picks up the first card on the draw pile
picked_up = self.deck.pop(0)
print(picked_up)
return picked_up
class Player:
def __init__(self):
self.player_hand = ["defuse"]
self.deck = Deck()
for i in range(6):
self.draw_card()
def draw_card(self):
# draw pile reduces by one
self.player_hand.append(deck.pickup())
return self.player_hand

Python Blackjack game: Issues with dictionary for values

I have been following the python course on udemy by Jose Portilla, and for one of our projects, we have to create a text-based Blackjack game. I have an error with a part of the code that looks like the following.
I have created a dictionary of values for the cards so I can easily see how much a card is worth (ex. If I have a King of Clubs, I want it to be equal to 10).
rankValues = {'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}
I then have a class that deals with the player hand. I had trouble with this part, so the solution looks like this.
class Hand:
def __init__(self):
self.cards = [] # start with an empty list as we did in the Deck class
self.value = 0 # start with zero value
self.aces = 0 # add an attribute to keep track of aces
def add_card(self,card):
self.cards.append(card)
self.value += rankValues[card.rank] #Where I need help!#
if card.rank == 'Ace':
self.aces += 1 # add to self.aces
def adjust_for_ace(self):
while self.value > 21 and self.aces:
self.value -= 10
self.aces -= 1
I don't understand this line at all. Help would be extremely appreciated!
Edit - Full Code
import random
import time
suits = ['Clubs', 'Spades', 'Diamonds', 'Hearts']
ranks = ['Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine', 'Ten', 'Jack', 'Queen', 'King', 'Ace']
rankValues = {'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 Card:
def __init__(self, suit, rank):
self.suit = suit
self.rank = rank
def __str__(self):
return(f'{self.rank} of {self.suit}')
class Deck:
def __init__(self):
self.deck = []
for suit in suits:
for rank in ranks:
self.deck.append(Card(rank, suit))
def __str__(self):
comp = ''
for card in self.deck:
comp += '\n' + card.__str__()
return comp
def shuffle(self):
random.shuffle(self.deck)
def deal(self):
single_card = self.deck.pop()
return single_card
class Chips:
def __init__(self):
self.chips = 100
def win_bet(self, opponent_bet):
self.chips += opponent_bet
def lose_bet(self, my_bet):
self.chips -= my_bet
def __str__(self):
return(str(self.chips))
class Hand:
def __init__(self):
self.cards = []
self.points = 0
self.aces = 0
def add_card(self, card):
self.cards.append(card)
self.points += rankValues[card.rank] #error
def adjust_for_aces(self):
if self.points > 21 and self.aces:
self.aces -= 1
self.points -= 10
def __str__(self):
strversion = ' '
for card in self.cards:
strversion.append(card)
After the EDIT, it is still unclear what you don't understand. You have a dictionary with the values of the cards defined in a class card:
class Card:
def __init__(self, suit, rank):
self.suit = suit
self.rank = rank
rankValues = {'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}
Example:
c1 = Card("Clubs", "Queen")
# To find the value, you need to look at what a Queen is worth:
rankValues["Queen"] # Returns 10. The key if place between [].
# Same as:
rankValues[c1.rank] # Because the attribute rank of c1 is "Queen"
Now the Hand:
class Hand:
# Init an empty hand
def __init__(self):
self.cards = []
self.points = 0
self.aces = 0
# Add an object card to the hand
def add_card(self, card):
self.cards.append(card)
self.points += rankValues[card.rank]
Example with c1:
my_hand = Hand()
my_hand.add_card(c1) # Enters the method add_card()
# What it does:
# self.cards.append(card) => my_hand.cards is a list() and will have the card c1 appended.
# self.points += rankValues[card.rank]
# => self.points is a value that will be incremented by the value of the card added.
# The value is given by the dictionnary rankValues, and is fetch by the rank of the card as the key.

Categories

Resources