Okay, I have implemented my code below. The wanted outcome would be:
Card Q Hearts, Card 9 Hearts, Card 7 Spades
Instead, the outcome is:
Card 12 Hearts, Card 9 Hearts, Card 7 Spades
I know that the mistake is somewhere in the if statement but I can't figure out how I should fix it. Can anyone help me with this? Thanks!
import random
class Card:
ranks = range(1, 14)
suits = ['Diamonds', 'Spades', 'Clubs', 'Hearts']
def __init__(self):
self.rank = random.choice(Card.ranks)
self.suit = random.choice(Card.suits)
def change(self):
self.rank = random.choice(Card.ranks)
self.suit = random.choice(Card.suits)
def __repr__(self):
letters = {1:'A', 11:'J', 12:'Q', 13:'K'}
if self.rank in letters:
rank_show = self.rank
else:
rank_show = self.rank
return "Card " + str(rank_show) + " " + self.suit
random.seed(1235)
card_1 = Card()
print(card_1)
card_2 = Card()
print(card_2)
card_2.change()
print(card_2)
letters = {1:'A', 11:'J', 12:'Q', 13:'K'}
if self.rank in letters:
rank_show = self.rank
else:
rank_show = self.rank
You forgot to change the show value: you do the same thing in both branches. Instead ...
if self.rank in letters:
rank_show = letters[self.rank]
Better yet, make sure that your return value is of a consistent type: just make them all characters:
rank_char = " A23456789TJQK" # 'T' for 10 is common for consistent formatting
rank_show = rank_char[self.rank]
Note the lack of an 'if' statement; you simply index the value list. If you want to include "10" instead of "T", you might use a list of strings instead:
rank_char = ["", "A", "2", ... "10", "J", "Q", "K"]
It is a minor mistake. You are accessing the numerical value of self.rank even though you have a dictionary which maps the corresponding alphabet for it. To fix this just use self.rank as key for the dictionary.
def __repr__(self):
letters = {1:'A', 11:'J', 12:'Q', 13:'K'}
if self.rank in letters:
rank_show = letters[self.rank] #change here - using self.rank as the key for letters
else:
rank_show = self.rank
return "Card " + str(rank_show) + " " + self.suit
Another method of doing it is to use the get() method of the dictionary data type.
def __repr__(self):
letters = {1:'A', 11:'J', 12:'Q', 13:'K'}
if self.rank in letters:
rank_show = letters.get(self.rank) #change here - use letters.get
else:
rank_show = self.rank
return "Card " + str(rank_show) + " " + self.suit
Just started learning Python and I am trying to create a blackjack game. I want to find the sum of the card values in a player's hand. My approach was to change the letters "J", "Q","K" into values of 10 and change "A" to value of 11. I have defined the class Card but when I run the code, I get an error saying "type object 'Card' has no attribute 'value'"
import random
DEFAULT_SUITS = ("Clubs","Hearts","Diamonds","Spades")
DEFAULT_VALUES = ("A",2,3,4,5,6,7,8,9,10,"J","Q","K")
class Card():
def __init__ (self, suit, value):
self.suit = suit
self.value = value
def show(self):
print(self.value, self.suit)
class Shoes():
def __init__(self, decks, suits=DEFAULT_SUITS, values=DEFAULT_VALUES):
self.cards = []
for deck in range(decks):
for suit in suits:
for value in values:
self.cards.append(Card(suit,value))
random.shuffle(self.cards)
def show(self):
for card in self.cards:
card.show()
def drawcard(self):
return self.cards.pop()
class Player():
def __init__ (self, name):
self.name = name
self.hand = []
def drawcard(self, shoes):
self.hand.append(shoes.drawcard())
return self
def totalvalue(self):
for card in self.hand:
if Card.value == "J":
self.hand = [10 if card=="J" else card for card in cards]
if Card.value == "Q":
self.hand = [10 if card=="Q" else card for card in cards]
if Card.value == "K":
self.hand = [10 if card=="K" else card for card in cards]
if Card.value == "A":
self.hand = [11 if card=="A" else card for card in cards]
self.totalvalue = sum(self.hand(Card.value))
def showhand(self):
for card in self.hand:
card.show()
shoe = Shoes(int(input("Enter the number of deck used in a shoes: ")))
bob = Player("bob")
bob.drawcard(shoe)
bob.showhand()
bob.totalvalue()
How can I change the values "J","Q","K","A" in hand and sum it up to get the total value?
you have used Card.value, where Card is a class instace, just change Card to card in totalvalue function.
and next thing, i will suggest to make a dictionary;
and take every value from that even numbers too.
dict = {'A':1, '2':2,.......}
and so on, like this
def totalvalue(self):
self.totalvalue =0;
dict = {'A':1, '2':2,.......};
for card in self.hand:
self.totalvalue = self.totalvalue +dict[card.value]
I see there is some confusion in using the list of Cards. Here what you should be doing
def totalvalue(self):
total = 0
for card in self.hand:
if card.value in ["J", "Q", "K"]:
total = total + 10
elif card.value == "A":
total = total + 11
else:
total = total + card.value
self.totalvalue = total
Code can be further simplified using the list comprehension as follows
def totalvalue(self):
return sum([10 if card.value in ['J', 'Q', 'K'] else 11 if card.value == 'A' else card.value for card in self.hand])
I'm doing this BlackJack program and when I ran it, Python tells me this:
Traceback (most recent call last):
File "<pyshell#17>", line 1, in <module>
c2.bj_value()
File "/Users/xuanruizhang/Desktop/lab_class_design.py", line 47, in bj_value
s = PlayingCard(a,b)
NameError: name 'a' is not defined
So the problem is with the function bj_value(self). I want to return corresponding value of the rank in the init function.
For example: If c2 = PlayingCard(11, "c"), then c2.bj_value() should return 10.
class PlayingCard:
def __init__(self, rank, suit):
if rank == 1:
self.rank = "Ace"
elif rank == (2 or 3 or 4 or 5 or 6 or 7 or 8 or 9 or 10):
self.rank = rank
elif rank == 11:
self.rank = "Jack"
elif rank == 12:
self.rank = "Queen"
elif rank == 13:
self.rank = "King"
if suit == "h":
self.suit = "Hearts"
elif suit == "s":
self.suit = "Spades"
elif suit == "c":
self.suit = "Clubs"
elif suit == "d":
self.suit = "Diamonds"
def get_rank(self):
if self.rank == (2 or 3 or 4 or 5 or 6 or 7 or 8 or 9 or 10):
return self.rank
elif self.rank == "Ace":
return 1
elif self.rank == "Jack":
return 11
elif self.rank == "Queen":
return 12
elif self.rank == "King":
return 13
def get_suit(self):
if self.suit == "Hearts":
return "h"
elif self.suit == "Jack":
return "j"
elif self.suit == "Clubs":
return "c"
elif self.suit == "Diamonds":
return "d"
def bj_value(self):
s = PlayingCard(a, b)
if s.a == 1 or 2 or 3 or 4 or 5 or 6 or 7 or 8 or 9 or 10:
return s.a
elif s.a == 11 or 12 or 13:
return 10
def __repr__(self):
return '%s of %s' % (self.rank, self.suit)
def main():
if __name__ == '__main__':
main()
Thank you!
No need to instantiate a new class. Store the ORIGINAL rank value as a variable (you should rename the variable storing the name values Jack, Queen, etc. Access self.rank within the bj_value function:
class PlayingCard:
def __init__(self, rank, suit):
self.rank = rank
if rank == 1:
self.card = "Ace"
elif rank in range(2, 11):
self.card = str(rank)
elif rank == 11:
self.card = "Jack"
elif rank == 12:
self.card = "Queen"
elif rank == 13:
self.card = "King"
if suit == "h":
self.suit = "Hearts"
elif suit == "s":
self.suit = "Spades"
elif suit == "c":
self.suit = "Clubs"
elif suit == "d":
self.suit = "Diamonds"
....
def bj_value(self):
if self.rank in range(1,11):
return self.rank
elif self.rank in range(11,14):
return 10
I am using a Book called Python programming: An introduction to computer programming and I am stuck in a programming exercise in chapter 10. It asks for a program that displays a playing card after the user inserts the value of the card and its suit. Also, I should be using 3 methods plus two constructors, here they are:
__init__(self, rank, suit):
getRank(self)
getSuit(self)
BJValue(self)
__str__(self)
However, as I run it an error is displayed.....
Here is my work:
from random import randrange
class Card:
def __init__(self, rank, suit):# This constructor creates the corresponding card according to their ranks:
self.rank = rank # "d"=diamonts, "c"=clubs, "h"=hearts, or
"s"=spades
self.suit = suit
def getRank(self):# Returns the rank of the card.
ranks = [None, "Ace", "2", "3",
"4", "5", "6", "7", "8",
"9", "King", "Queen", "Jack"]
self.rank = ranks[self.rank]
return self.rank
def getSuit(self):# Returns the suit of the card.
suits = ["diamons", "heart", "club", "spades"]
# TRY TO MAKE THIS PIECE OF CODE MORE ABSTRACT!!!!
if self.suit[0] == "d":
self.suit = suits[0]
elif self.suit[0] == "h":
self.suit = suits[1]
elif self.suit[0] == "c":
self.suit = suits[2]
elif self.suit[0] == "s":
self.suit = suits[3]
return self.suit# A suit in Blackjack means the symbol of the card.
def BJValue(self):# Returns the Blackjack value of a card.
# For example Aces count as 1 and face cards count as 10.
while 0 < self.rank <= 10:
if self.rank == "Ace":
self.rank = 1
self.bjvalue = self.rank
elif self.rank[0] == "King" or self.rank[0] == "Queen" or self.rank[0] == "Jack":
self.rank = 10
self.bjvalue = self.rank
else:
self.bjvalue = self.rank
return self.bjvalue
def __str__(self):# Returns a string that names the card. For example "Ace of Spade".
print("{0} of {1}".format(self.rank, self.suit)
I'm sorry for my Englis but is not my first language.
You're missing the close parentheses in the final print call.
You've missed to close parenthesis at the end of last line, there is one opening for print method, but not closing at the end.
Im making a simple blackjack program in python, but im getting a "ValueError: invalid literal for int() with base 10: ..." In order to get the total value of the player hands, after creating the card object, i try to get the rank of the card:
rank1 = Card.Card.getRank(card1)
heres the classs method:
def getRank(self):
if self.__rank == ('J'):
self.__rank = 10
return self.__rank
elif self.__rank == ('Q'):
self.__rank = 10
return self.__rank
elif self.__rank == ('K'):
self.__rank = 10
return self.__rank
elif self.__rank == ('A'):
self.__rank = 11
return self.__rank
else:
self.__rank = self.__rank
return int(self.__rank)`
the only time it returns the ValueError: invalid literal for int() with base 10 is if the rank is a 'Q' or 'K', it returns 10 for the 'J' and 11 for 'A'. I'm not getting why it returns an error for the 'Q' or 'K' since the code is the same for 'J' and 'A'... any help would be appreciated... if it helps, before that i had
heres the whole class
#Card class
#Class card holds ranks and suits of deck
#
TEN = 10
FOUR = 4
class Card():
#Create rank list
RANK= ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"]*FOUR
#Create list with rank names
rankNames=[None, 'Ace', 'Two', 'Three', 'Four', 'Five', 'Six',
'Seven', 'Eight', 'Nine', 'Ten', 'Jack', 'Queen', 'King']
#Create suit list
suitNames = ['CLUBS','DIAMONDS', 'HEARTS', 'SPADES']
#Takes in rank, suit to create a deck of cards
def __init__(self, rank, suit):
self.__rank = rank
self.__suit = suit
#Returns the rank of card
def getRank(self):
if self.__rank == ('J'):
print (repr(self.__rank))
self.__rank = 10
return self.__rank
elif self.__rank == ('Q'):
self.__rank = 10
print (repr(self.__rank))
return self.__rank
elif self.__rank == ('K'):
print (repr(self.__rank))
self.__rank = 10
return self.__rank
elif self.__rank == ('A'):
print (repr(self.__rank))
self.__rank = 11
return self.__rank
else:
self.rank = self.__rank
print (repr(self.__rank))
return int(self.__rank)
#Returns suit of card
def getSuit(self):
return self.__suit
#Returns number of points the card is worth
def BJVaue(self):
if self.rank < 10:
return self.rank
else:
return TEN
def __str__(self):
return "%s of %s" % ([self.__rank], [self.__suit])
Heres where i create the card objects
#Create a player hand
player = []
#Draw two cards for player add append
player.append(drawCard())
player.append(drawCard())
#Display players cards
print ("You currently have:\n" , player)
#Get the rank of the card
card1 = player[0]
card2 = player[1]
#Update players card status
print (card1)
print (card2)
#Get the total of the hand
rank1 = Card.Card.getRank(card1)
rank2 = Card.Card.getRank(card2)
#Get the ranks of players cards
playerRank = [rank1 , rank2]
#Get total of players hand
totalPlayer = getTotal(playerRank)
#Display players total
print ("Your current total is: ", totalPlayer)
the getTotal function
def getTotal(rank):
#Create and set accumulator to 0
total = 0
#for each value in the rank
for value in rank:
#add to total
total += value
#Return total
return total
hope this helps
This line isn't right:
if self.__rank == ('J' or 'Q' or 'K'):
('J' or 'Q' or 'K') evaluates to 'J', so this line just checks whether self.__rank == 'J'.
You actually want:
if self.__rank in ('J', 'Q', 'K'):
I think your first code example should work. Are you sure that you're actually running the new code? If you try to import the same module into a running Python instance it won't pick up the changes. Also, if you redefine a class, existing instances will still have the old method implementations.
You've got fairly stinky code here - bad indentation, unnecessary brackets (are those strings or tuples?), nasty mix of functional and OO, static calls to non-static methods, etc.
The initial problem, "ValueError: invalid literal for int() with base 10: ..." means you are passing int() a value which it doesn't know how to translate into an integer. The question, then, is: what is that value, and where is it coming from?
Try substituting
VALUE = {
'2':2, '3':3, '4':4, '5':5, '6':6, '7':7, '8':8, '9':9, '10':10,
'J':10, 'Q':10, 'K':10, 'A':11
}
def getValue(self):
try:
return Card.VALUE[self.__rank]
except KeyError:
print "%s is not a valid rank" % (self.__rank)
and see what you get. My guess would be that drawCard is generating rank values that Card.getValue doesn't know what to do with.
Other problems with your code:
TEN = 10
FOUR = 4
The whole point of using defined values is to provide semantic meaning and allow a single point of change; yet FOUR is no more contextually meaningful than 4, and I see no case in which changing the value of FOUR or TEN would make sense (indeed, if FOUR were ever to equal 3, it would be actively unhelpful in understanding your code). Try renaming them FACECARD_VALUE and NUMBER_OF_SUITS.
You are using "rank" to mean multiple different things: the character denoting a card and the value of a card to your hand. This will also increase confusion; try using face for one and value for the other!
You seem to be using drawCard() as a stand-alone function; how are you keeping track of what cards have already been dealt? Does it ever make sense to have, for example, two Ace of Spades cards dealt? I would suggest creating a Deck object which initializes 52 canonical cards, shuffles them, and then deck.getCard() returns a card from the list instead of creating it randomly.
See what you think of the following:
import random
class Deck():
def __init__(self):
self.cards = [Card(f,s) for f in Card.FACE for s in Card.SUIT]
self.shuffle()
def shuffle(self):
random.shuffle(self.cards)
def getCard(self):
return self.cards.pop()
class Card():
# Class static data
FACE = ('A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K')
NAME = ('Ace', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine', 'Ten', 'Jack', 'Queen', 'King')
RANK = (11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10)
SUIT = ('Clubs','Diamonds', 'Hearts', 'Spades')
def __init__(self, face, suit):
ind = Card.FACE.index(face)
self.__face = Card.FACE[ind] # the long way around, but keeps it consistent
self.__name = Card.NAME[ind]
self.__rank = Card.RANK[ind]
ind = Card.SUIT.index(suit)
self.__suit = Card.SUIT[ind]
def getFace(self):
return self.__face
def getName(self):
return self.__name
def getRank(self):
return self.__rank
def getSuit(self):
return self.__suit
def __str__(self):
return "%s of %s" % (self.__name, self.__suit)
def __repr__(self):
return "%s%s" % (self.__face, self.__suit[:1])
class Player():
def __init__(self):
self.cards = []
def drawCard(self, deck):
self.cards.append(deck.getCard())
def drawCards(self, deck, num=2):
for i in range(num):
self.drawCard(deck)
def getRank(self):
return sum( c.getRank() for c in self.cards )
def __str__(self):
cards = ', '.join(str(c) for c in self.cards)
return "%s: %d" % (cards, self.getRank())
def __repr__(self):
return ' '.join([repr(c) for c in self.cards])
class Game():
def __init__(self):
self.deck = Deck()
self.player1 = Player()
self.player2 = Player()
def test(self):
self.player1.drawCards(self.deck, 2)
print "Player 1:", self.player1
self.player2.drawCards(self.deck, 2)
print "Player 2:", self.player2
def main():
g = Game()
g.test()
if __name__=="__main__":
main()
rank1 = Card.Card.getRank(card1)
This looks like you're trying to call the getRank as a static method. getRank is expecting an instance of itself as the first parameter. This usually means you have a Card object, but the way you call it above, you don't have an object to pass it. I'ms urprised it even lets you call it like that. That should give you an incorrect number of arguments error.
Post more code, but it seems like you have serious fundamental problems with your design.
Update:
What's this?
RANK= ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"]*FOUR
Why do you need a list of 4 duplicates of your ranks?
Here is another approach to make a deck of cards
from itertools import product
card_values = (
("1", "1", 1),
("2", "2", 2),
("3", "3", 3),
("4", "4", 4),
("5", "5", 5),
("6", "6", 6),
("7", "7", 7),
("8", "8", 8),
("9", "9", 9),
("10" ,"10", 10),
("Jack", "J", 10),
("Queen", "Q", 10),
("King", "K", 10),
("Ace", "A", 11))
card_suits = ("Spades", "Clubs", "Hearts", "Diamonds")
class Card(object):
def __init__(self, name, short_name, rank, suit):
self.name = name
self.short_name = short_name
self.rank = rank
self.suit = suit
cards = []
for (name, short_name, rank), suit in product(card_values, card_suits):
cards.append(Card(name, short_name, rank, suit))
You could reduce the amount and complexity of your code by using a Python dictionary. If you did this, your getRank() function could look something like the following:
class Card(object):
RANK = {"A":1, "2":2, "3": 3, "4":4, "5": 5, "6": 6, "7":7,
"8":8, "9":9, "10":10, "J":10, "Q":10, "K":10}
def __init__(self, draw): # just for example
self.__rank = draw
def getRank(self):
self.__rank = Card.RANK[self.__rank]
return self.__rank
# ...
print Card('A').getRank()
# 1
print Card('4').getRank()
# 4
print Card('J').getRank()
# 10
print Card('K').getRank()
# 10