Running the program will cause an error message:
TypeError: unsupported operand type(s) for +=: 'int' and 'NoneType'
The problem is with the line value += values.get(card.get_rank)
I think there may be a problem with the get_rank method? Does it not return an integer?
ranks = ('A','2','3','4','5','6','7','8','9','10','J','Q','K')
values = {'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}
suits = ('Diamonds','Hearts','Clubs','Diamonds')
class Card:
def __init__(self, suit, rank):
self.suit = suit
self.rank = rank
def __str__(self, suit, rank):
print (self.rank + 'of' + self.rank)
def get_rank(self):
return self.rank
class Hand:
def __init__(self):
self.hand = []
def __str__(self):
hand = ''
for card in self.hand:
hand = hand + str(card)
return hand
def get_value(self):
value = 0
aces = 0
for card in self.hand:
if card.get_rank == 'A':
aces += 1
value += values.get(card.get_rank)
if (aces>0) and (value + 10 <= 21):
value += 10
return value
values.get(card.get_rank) tries to use the instance method as the key for the dictionary. This is not a valid key in the dictionary, so dict.get() returns the default None.
Instead you want to call the method, and use the return value as the key:
value += values.get(card.get_rank())
or, as trivial getters and setters are unpythonic, just access the attribute directly:
value += values.get(card.rank)
Note that you can also pass a default to dict.get() to ensure you always get a sensible return value:
value += values.get(card.rank, 0)
Now if there is no value for that card rank in values, its value is assumed to be zero.
Also, it's not clear where values is coming from. I would suggest you make it a class attribute:
class Hand:
VALUES = {...}
...
def get_value(self):
...
value += self.VALUES.get(card.rank, 0)
...
Or an explicit argument to get_value:
class Hand:
...
def get_value(self, values):
...
value += self.values.get(card.rank, 0)
...
Related
I am creating an object that represents the hand of a blackjack player. One of the methods of the hand is to add a new Card to it. However, my Hand object always returns None when I attempt to print it.
Here is my code of the Hand object.
class Hand:
'''An object representing the Card objects that the player has in their hands'''
def __init__(self, name):
self.name = name
self.list = []
def addCard(self, card):
self.list = self.list.append(card)
return self.list
def __str__(self):
return f'Your hand has {self.list}.'
myHand = Hand('Henry')
myHand.addCard(str(myCard))
print (myHand)
myCard is an object that returns "Four of Diamonds" I created previously. Below is the whole code if you are interested.
class Card:
''' A class for representing a single playing card. '''
def __init__(self, value, suit):
''' Creates Card object with given suit and value. '''
self.value = value
self.suit = suit
def getSuit(self):
''' Returns the suit of the Card. '''
return self.suit
def getValue(self):
''' Returns the value of the Card. '''
return self.value
def getBlackjackValues(self):
''' Get a list of possible Blackjack values for the card. '''
# IMPLEMENT ME
if 1 < self.value:
BlackjackValue = self.value
return [BlackjackValue]
else:
BlackjackValue = [self.value, 11]
return BlackjackValue
def __str__(self):
''' #Return a string representation of the Card. '''
# IMPLEMENT ME
# Convert numerical values into letters
if self.value == 2:
Value = 'Two'
elif self.value == 3:
Value = 'Three'
elif self.value == 4:
Value = 'Four'
elif self.value == 5:
Value = 'Five'
elif self.value == 6:
Value = 'Six'
elif self.value == 7:
Value = 'Seven'
elif self.value == 8:
Value = 'Eight'
elif self.value == 9:
Value = 'Nine'
elif self.value == 10:
Value = 'Ten'
elif self.value == 11:
Value = 'Jack'
elif self.value == 12:
Value = 'Queen'
elif self.value == 13:
Value = 'King'
elif self.value == 1:
Value = 'Ace'
# Convert suit values into letter
if self.suit == 'S':
Suit = 'Spades'
elif self.suit == 'H':
Suit = 'Hearts'
elif self.suit == 'D':
Suit = 'Diamonds'
elif self.suit == 'C':
Suit = 'Clubs'
# The card is
return f'Your card is {Value} of {Suit}.'
myCard = Card (4, 'D')
print (myCard)
class Hand:
'''An object representing the Card objects that the player has in their hands'''
def __init__(self, name):
self.name = name
self.list = []
def getName(self):
return self.name
def getList(self):
return self.list
def addCard(self, card):
self.list = self.list.append(card)
return self.list
def __str__(self):
return f'Your hand has {self.list}.'
myHand = Hand('Henry')
myHand.addCard(str(myCard))
print (myHand)
Here is the screenshot of the output:
Output
list.append() method works in place, i.e. it returns None. That is what you assign to self.list. Note that if you try to add second card it will raise an error, because None has no append attribute.
All I need to do is use .append() at the return statement in the addCard method.
Also, credits to #Nja for pointing out that I do not need to update myHand object again, but simply initiate the method.
Try this:
class Hand:
'''An object representing the Card objects that the player has in their hands'''
def __init__(self, name):
self.name = name
self.list = []
def addCard(self, card):
self.list.append(card)
def __str__(self):
return 'Your hand has ' + ' '.join(self.list)
myCard = "ciao"
myHand = Hand('Henry')
myHand.addCard(str(myCard))
print (myHand)
I am trying to figure out how to make the values of t, j, q, and k to the int value of 10. Can someone explain where I went wrong with this?
class Card:
def __init__(self, value , suit):
self.value = value
self.suit = suit
def __repr__(self):
return "The " + self.value + " of " + self.suit
def intValue(self):
if int(self.value) > 2 or int(self.value) < 9:
return self.value
elif str(self.value) == 'a':
return 1
elif str(self.value) == 'j' or str(self.value) == 'q' or str(self.value) == 'k' or str(self.value) == 't':
return 10
Although I agree with the comments about using a dictionary to represent the values, let's fix what you have. It's mostly a matter of keeping it simple and remembering the type of your data (str) and not randomly imposing str() and int() calls when they're not needed:
class Card:
def __init__(self, value, suit):
self.value = value
self.suit = suit
def __repr__(self):
return "The {} of {}".format(self.value, self.suit)
def intValue(self):
if self.value.isdigit():
return int(self.value)
elif self.value == 'a':
return 1
else:
return 10
I don't understand what is wrong. I keep getting that I'm missing a required positional argument.
class CoinToss(object):
def __init__(self, flip, ID_Num, Value):
self.flip = flip
self.ID_Num = ID_Num
self.Value = Value
def Flip(self):
"""
Method is important in determining the number of flips and simulating the coin
"""
data = []
Num_flip = int(input("how many times do you want to flip the coin? :"))
print("the ball at the start: ball: d%, state: d% value: d% " %(self.ID_Num))
for i in range(Num_flip):
self.flip = self.flip = 1
if randint(0,1) == 0:
self.Value = self.Value + 1
data.append(self.value)
else:
self.Value = self.Value - 1
data.append(self.Value)
Apparently, when you use CoinToss, you call it with only 2 arguments, flip and ID_NUM. This would cause an error, because you did not provide CoinToss.__init__() with the required Value argument.
Why is it giving me an error " 'int' object is not subscriptable " when i run the program? I looked if i was doing anything wrong, i understand it has to be an integer on line 24, but when I'm changing capacity[1] to capacity(int[1]) , it gives me the same error. Any hint would be appreciated.
class Bag():
__slots__=('name', 'weight', 'value')
def mkBag(name, weight, value):
thisBag = Bag()
thisBag.name = name
thisBag.weight = weight
thisBag.value = value
return thisBag
def ratio(treasure):
print(treasure)
print(treasure)
return treasure[2]//treasure[1]
def plunder(treasure, capacity):
treasure = sorted(treasure, key=ratio, reverse=True)
bagLst = []
current = 0
while current < capacity:
if capacity != 0:
if capacity > current[1]:
bagLst.append(mkBag(treasure[0],weight[1],current[2]))
capacity = capacity - current[1]
else:
bagLst.append(mkBag(current[0], capacity, (current[2]/current[1]), capacity))
capacity = 0
return bagLst
def main():
capacity = 10
name = ''
weight = 0
value = 0
treasure = [('silver', 20, 100), ('platinum', 10, 400), ('paladium',10,800), ('diamonds',5,900), ('gold', 10,60)]
bagLst = plunder(treasure, capacity)
for line in bagLst:
print('bagLst')
current is an int:
current = 0
but you are trying to use it as a list:
if capacity > current[1]:
bagLst.append(mkBag(treasure[0],weight[1],current[2]))
capacity = capacity - current[1]
else:
bagLst.append(mkBag(current[0], capacity, (current[2]/current[1]), capacity))
everywhere you use current[index] you are trying to index the integer value.
If you expected current to be a sequence instead, you'd need to set it to one.
I suspect you want to inspect the current treasure to add to the bag; you didn't pick any treasure item however. Something along the lines of:
current = 0
while capacity and current < len(treasure):
item = treasure[current]
current += 1
if capacity > item[1]:
bagLst.append(mkBag(item[0], item[1], item[2]))
capacity = capacity - item[1]
else:
bagLst.append(mkBag(item[0], capacity, (item[2]/item[1]), capacity))
capacity = 0
"int" object not subscriptable means you're trying to do 1234[1]. That doesn't make any sense! You can subscript a string ('abcdefg'[1] == 'b') and a list ([1,2,3,4,5][1] == 2) but you can't get the "nth element" of an integer.
In your line:
# in def plunder(...):
if capacity > current[1]:
You're trying to access the 2nd element of current, which is currently equal to the integer 0. Are you trying to make that a list? What are you expecting to be in current[1]?
Here's a substantially better way to accomplish this
Hey there, so I figured you meant that current[1] was actually item[1], meaning the weight of the item you were looking at. Instead, current was intended to be the running-weight of the bag. Understood! That said, I wrote up a better solution for this: take a look see!
class Treasure(object):
def __init__(self,name,weight=0,value=0,id_=0):
self.name = name
self.weight = weight
self.value = value
self.id = id_ # bootstrap for further development
#property
def ratio(self):
return self.value/self.weight
class BagFullError(ValueError):
pass
class Bag(object):
def __init__(self,owner=None,capacity=10):
self.owner = owner
self.capacity = capacity
self.contents = list()
def __str__(self):
return_value = "CONTENTS:"
for item in self.contents:
return_value += "\n ${0.value:4} {0.name:10}{0.weight} lb".format(item)
return return_value
def add(self,other):
if not isinstance(other,Treasure):
raise TypeError("Must pick up Treasure")
if self.weight + other.weight > self.capacity:
raise BagFullError("Bag cannot fit {}({} lb) ({} lb/{} lb)".format(
other.name,other.weight,self.weight,self.capacity))
self.contents.append(other)
def remove(self,other):
self.contents.remove(other)
# may throw ValueError if `other` not in `self.contents`
#property
def weight(self):
return sum(item.weight for item in self.contents)
treasure = [Treasure('silver', 20, 100), Treasure('platinum', 10, 400),
Treasure('paladium',10,800), Treasure('diamonds',5,900),
Treasure('gold', 10,60)]
## map(lambda x: Treasure(*x), [('silver',20,100), ... ])
def plunder(treasure_list,bag=None):
_bag = bag or Bag()
treasures = sorted(treasure_list,
key = lambda x: x.ratio,
reverse = True)
while True:
for treasure in treasures:
try: _bag.add(treasure)
except BagFullError as e:
print(e)
return _bag
bag = Bag("Adam",100)
print(bag)
plunder(treasure,bag)
print(bag)
print("Total Value: {}".format(sum(item.value for item in bag.contents)))
I have a class with many attributes, and when I give a number, I would like it to subtract that from one attribute, but if the amount is greater than the attribute subtracted from, move to the next attribute with what is left over. Example:
def subt(self, amount):
self.attr1 += amount
if self.attr1 < 0:
self.attr2 += self.attr1
self.attr1 = 0
if self.attr2 < 0:
# etc...
It feel like there should be a concise recursive way to accomplish the same thing, but I don't know how with the all the different attributes.
You can access the attributes using .__dict__ You need a list for the order you want to subtract. Something like this works.
class A():
def __init__(self):
self.foo = 100
self.bar = 200
self.baz = 300
self.sub_stack = ['foo', 'baz', 'bar']
def subt(self, amount):
tmp_stack = self.sub_stack[:]
while tmp_stack and amount:
key = tmp_stack.pop(0)
val = self.__dict__[key]
if val > amount:
self.__dict__[key] -= amount
amount = 0
else:
amount -= self.__dict__[key]
self.__dict__[key]=0
return amount
return value is the remainder on amount after iterating through your attributes
Does making a list out of all the attributes work?
def subt(self, amount):
i = 0
while i<self.attrlist.len:
if attrlist[i] < amount:
attrlist[i] -= amount
break
Yes, the best way is to create a list of all your attributes - do it either manually,
or, if your attribute names follow a pattern (like the attrN series on the example),
you can automate the creation of such a list.
def subt(self, amount):
#all_attrs = ["attr1", "attr2", "attr3"]
# or this step can be automated by something like:
all_attrs = sorted(attr_name for attr_name in self.__class__.__dict__.keys() if attr_name.startswith("attr"))
for i, attr_name in all_attrs:
self.__setattr__(getattr(self, attr_name) + amount)
if gettattr(self, attr_name) < 0:
amount = gettattr(self, attr_name)
self.__setattr__(self, attr_name, 0)
else:
break