#๐ how to add the total sum of a list of class objects
282 messages ยท Page 1 of 1 (latest)
@wet vortex
Remember to:
- Ask your Python question, not if you can ask or if there's an expert who can help.
- Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
- Explain what you expect to happen and what actually happens.
:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.
card class and deck making bits if useful
class Card:
def __init__(self, rank, suit):
self.rank = rank
self.suit = suit
def __repr__(self,):
return f"{self.rank}{self.suit}"
deck = [Card(rank, suit) for rank in range(1, 14) for suit in suits]
is each card worth its rank?
its blackjack so j q k 10 and ace 1 or 11 im also figuring out how to get that to translate but i havnt hit a roadblock w that yet
Something like
sum(card.rank for card in deck) ?
this won't quite work if it's blackjack scoring
I would start by creating a function that can score a hand of cards
you probably will also want a mapping (dict) so you know what rank is what card
im kinda mkaing a dict atm but idk how to add values from the list if theyre class objects
you would use the rank attribute of the card
Something like
sum(scores[card.rank] for card in deck) ?
still doesn't quite handle ace logic
def royal2value(facecard, total):
royals = ["J", "Q", "K"]
if (facecard == "A"):
if (total >= 21):
return 11
else:
return 1
while True:
if any(item == facecard for item in royals):
return 10
this is what i have atm for royals
Why the while True ?
return breaks and if its an ace it doesnt get that far
a simple function that takes in a list of cards
But nothing changes in the loop, either it breaks at the first iteration or it loops infinelty
Would you know how to make a hand of cards from that deck?
not sure if it'd be too complex, but I'd make a childclass for royal cards and aces to simplify the logic for me
basically, deal 2 cards to a hand?
I think an ace can be either 1 point or 11, thats why its a little more complex
I wouldn't. A card is a card. It's the game that gives it purpose
def deal(player):
player.append(deck[0])
discard.append(deck[0])
del deck[0]
while (len(player) !=2):
deal(player)
deal(dealer)
this is what i have just to deal the inital hands
is there a reason you need to keep track of discarded cards?
recycle
just reinitialize the deck at the start of the round
you never need to interact with discarded cards in blackjack
true but i wanna do other card games that might take from discard like trash figured it could be useful to use
but now the same card is in the player's hand AND the discard
that doesn't quite make sense
at the end of the round of blackjack, you could take every players' cards and put them into the discard list instead
but not until the round is over
good call
!e
import random
suits = ['hearts', 'spades', 'clubs', 'diamonds']
class Card:
def __init__(self, rank, suit):
self.rank = rank
self.suit = suit
def __repr__(self,):
return f"{self.rank}{self.suit}"
deck = [Card(rank, suit) for rank in range(1, 14) for suit in suits]
random.shuffle(deck)
hand = [deck.pop(), deck.pop()]
print(hand)
:white_check_mark: Your 3.14 eval job has completed with return code 0.
[11spades, 4diamonds]
ill just reinitialize the deck for rn
have a look at this code
and also make sure when you deal the card you remove it from the deck
using pop like Fashoomp
does this make sense for dealing the card to hand? This is just so we can eventually test the scoring function
remind me what .pop is again
it removes the last item from a list
so here, we're treating the end of the list as the "top" of the deck
if you want the first you do .pop(0)
way better than shoving 0 in everything i like it
I typically wouldn't though
true
ok, do you know how to loop through the cards in the hand?
depends on what you mean by it but wait pop would take from deck and put it in hand no deal func needed
it would be nice to have a specific deal function, but we're just using this as an example for now. I just needed a hand of cards to test with
fair
How would you look at each card's rank in the hand using a loop?
not really thats what i was needing help w
do you know how to loop through a list of strings?
for item in list?
yes, it's the exact same for a list of cards
a list can hold anything
str
int
Card
for card in hand
would something like this owrk?
total = for item in hand + Card.rank
let's not try and do it all in one line
</3
start with a basic for loop
this is what hand looks like. It's just a list of card instances
for item in player:
total += Card.rank
eh?
use the variables from my example
for card in hand
do you understand the difference between "class" and "instance"?
ill be honest i barely understand classes as they are
ye
!e
print(str)
print(int)
:white_check_mark: Your 3.14 eval job has completed with return code 0.
001 | <class 'str'>
002 | <class 'int'>
did not know they were classes only knew them to be datatypes
datatypes/classes are "blueprints" for how we create data
so if str is a class, what's an instance?
an instance is the actual creation of data based on that datatype
"hello" is an instance of str
123 is an instance of int
[] is an instance of list
we can have many instances from a single class
x = "foo"
y = "bar"
here we have 2 str instances
following along so far
ok, so making str and int instances is simple
if we want str, we just use ""
if we want int, we just type a number
but for custom classes, it's slightly different
class Animal:
pass
dog = Animal()
if we want an instance of the Animal class, we have to call it like we would a function
Animal is the class
Animal() is the instance
does that make sense?
yeah
btw if ur not already u should be a teacher im following along better than the free harvard cs50 lectures
I've done some mentoring/tutoring in the past
ok so just like any other class, we can have multiple instances from 1 class
dog = Animal()
cat = Animal()
class Card:
def __init__(self, rank, suit):
self.rank = rank
self.suit = suit
now let's look at the simple Card class
do you understand what __init__ does?
initialize but honestly what that means is just kinda magic to me
do you know the term "method"?
like class function
yes, it's a function that is called from an instance
like list.append
or str.upper
those are methods
they are functions, but more specifically, they are called methods
any method name with __ before/after the name is called a "dunder method"
"dunder" because "double underscore"
silly
dunder methods are reserved named by python. Simply defining them into your class gives your class new behaviour
There's many dunder methods, but there's only a few keys ones you really need to worry about
__init__ is "initialize", yes. It kinda does 2 things
It is automatically called when an instance is created
!e
class Animal:
def __init__(self):
print("I am born!")
dog = Animal()
:white_check_mark: Your 3.14 eval job has completed with return code 0.
I am born!
lol
so simply by doing Animal(), we are automatically calling the class __init__
!e
class Animal:
def __init__(self):
print("I am born!")
dog = Animal()
cat = Animal()
:white_check_mark: Your 3.14 eval job has completed with return code 0.
001 | I am born!
002 | I am born!
make 2 instances, get 2 prints
the other thing it does is receive the arguments of the instance
!e
class Animal:
def __init__(self, colour):
print(f"I am a {colour} animal!")
dog = Animal('brown')
cat = Animal('green')
:white_check_mark: Your 3.14 eval job has completed with return code 0.
001 | I am a brown animal!
002 | I am a green animal!
so if we add a parameter to __init__, then we must also provide an argument when creating our instance
does that make sense?
yeah and btw i did not know you do anything other than initialize variables with __init__
it's entirely up to you what you put inside __init__
whatever sort of "setup" you think your instance will need before it is ready to use
that makes sense i just never saw it in examples when looking into classes
well, I haven't quite finished initializing here
what we want is to create "attributes"
any data that belongs to an instance is an attribute of that instance
we need to make use of self to store it as an attribute
class Animal:
def __init__(self, colour):
self.colour = colour
attributes can be accessed from any other method in the class
and directly from the instance outside of the class (if necessary)
dog = Animal('brown')
so if I make an instance named dog and I want to know what colour it is, I can do dog.colour
!e
class Animal:
def __init__(self, colour):
self.colour = colour
dog = Animal('brown')
print(dog.colour)
:white_check_mark: Your 3.14 eval job has completed with return code 0.
brown
any questions?
nop
ok, so using your Card class, give me an example of making a Card instance
just 1 Card
card = Card(7, 'Hearts')
nice ๐
yippie
how would you print out the rank of that card?
Card.rank
๐
wait no
be careful with card and Card
capital for the class name
never capital for instance variables
that probably explains why this wasnt working
for card in player:
total += Card.rank
yes exactly
but, there's still some logic issues there
do you understand what __repr__ does in your class?
represent to my knowledge just makes the data readable to users
!e
class Card:
def __init__(self, rank, suit):
self.rank = rank
self.suit = suit
card = Card(7, 'Hearts')
print(card)
:white_check_mark: Your 3.14 eval job has completed with return code 0.
<__main__.Card object at 0x7fe80d8086e0>
without __repr__, our instance looks like this
this is the default output if we try and print an instance
yeah i got 52 of those when printing the deck before adding the repr bit
let's clean up the __repr__ first to match actual card ranks
CARD_LOOKUP = {
1: 'Ace'
2: '2',
3: '3',
4: '4'
}
create a dict like this (but fill in the rest of it)
suits = ["โฅ", "โ ", "โข", "โง"]
ranks = ["A", 2, 3, 4, 5, 6, 7, 8, 9, 10, "J", "Q", "K"]
ive got this already
that works too
instead of range
now, with repr, the goal is to return a string that represents the instance
yeee i had to change that when i got the face card func working
so if we do this
card = Card('A', 'Hearts')
our repr should return
Card('A', 'Hearts')
that should be what ive got atm
not quite
!e
class Card:
def __init__(self, rank, suit):
self.rank = rank
self.suit = suit
def __repr__(self,):
return f"{self.rank}{self.suit}"
card = Card('A', 'Hearts')
print(card)
:white_check_mark: Your 3.14 eval job has completed with return code 0.
AHearts
do you mean like a space inbetween cuz rn i have the symbols in stead of words that i think look cleaner when theres no space so it would look like
Aโฅ
it should look like this
with the word Card and the ()
o
def __repr__(self,):
return f"Card({self.rank}, {self.suit})"
cant imagine this is what you mean
why can't you imagine?
that's 99% right
__repr__ is meant to be a representation of the instance
figured the card() bit was something on its own
!e
text = 'abc'
print(text)
print(repr(text))
:white_check_mark: Your 3.14 eval job has completed with return code 0.
001 | abc
002 | 'abc'
if we look at str, the repr returns including the ''
the only thing missing here is the quotes, but there's a neat way to add that with f-strings
B) thought it said "thats a neat way"
!e
class Card:
def __init__(self, rank, suit):
self.rank = rank
self.suit = suit
def __repr__(self,):
return f"Card({self.rank!r}, {self.suit!r})"
card = Card('A', 'Hearts')
print(card)
:white_check_mark: Your 3.14 eval job has completed with return code 0.
Card('A', 'Hearts')
check out the !r in the f-string now
oh fun
ranks = ["A", 2, 3, 4, 5, 6, 7, 8, 9, 10, "J", "Q", "K"]
I would also update this list to be all strings, even the digits
it's not a good idea to have a list of mixed types
and just because something is a digit doesn't mean it has to be int
true i figured it would make it easier to only have to deal w face cards if they came up but i can imagine just sending them all through the translator func isnt a bad idea
ok, let's get back to having a deck and a hand now
since hopefully you better understand instances
!e
import random
class Card:
def __init__(self, rank, suit):
self.rank = rank
self.suit = suit
def __repr__(self,):
return f"Card({self.rank!r}, {self.suit!r})"
suits = ["โฅ", "โ ", "โข", "โง"]
ranks = ["A", '2', '3', '4', '5', '6', '7', '8', '9', '10', "J", "Q", "K"]
deck = [Card(rank, suit) for rank in ranks for suit in suits]
random.shuffle(deck)
hand = [deck.pop(), deck.pop()]
print(hand)
:white_check_mark: Your 3.14 eval job has completed with return code 0.
[Card('5', 'โข'), Card('7', 'โ ')]
here we now have a hand of 2 cards
make a loop to go through the hand and print out the value rank
like total?
!e
import random
class Card:
def __init__(self, rank, suit):
self.rank = rank
self.suit = suit
def __repr__(self,):
return f"Card({self.rank!r}, {self.suit!r})"
suits = ["โฅ", "โ ", "โข", "โง"]
ranks = ["A", '2', '3', '4', '5', '6', '7', '8', '9', '10', "J", "Q", "K"]
deck = [Card(rank, suit) for rank in ranks for suit in suits]
random.shuffle(deck)
hand = [deck.pop(), deck.pop()]
print(hand)
for card in hand:
print(card.rank)
:white_check_mark: Your 3.14 eval job has completed with return code 0.
001 | [Card('9', 'โฅ'), Card('2', 'โง')]
002 | 9
003 | 2
ok, so to score a blackjack hand, we have 3 possibilities for a card
it's worth it's number value
it's worth 10
it's an ace
you can do this using if/elif
if card.rank.isdigit()
are you asking me to?
yes
ignore ace for a moment
now make a total var
and if the rank is a number, add that number
if the rank is j, q, k, then add 10
total = 0
if (card.rank == "J" or "Q" or "k"):
total += 10
else:
total += card.rank
feels wrong
what about perchance?
if only
xd
true
total = 0
for card in hand:
if card.rank.isdigit(): # numbers
total += int(card.rank)
elif card.rank in {'J', 'Q', 'K'}: # royals
total += 10
have a look at this
does this make sense?
other than discovering .isdigit and in {} yeah
.isdigit() let's us check if a string is numerical
and if it is, we know we can safely convert it using int()
I don't want to use else for the Ace here even though you probably good
idk, maybe you got dealt the instructions card or a joker
let's use elif for Ace still
total = 0
aces = 0
for card in hand:
if card.rank.isdigit(): # numbers
total += int(card.rank)
elif card.rank in {'J', 'Q', 'K'}: # royals
total += 10
elif card.rank == 'A':
total += 11
aces += 1
here's how we're going to handle it
if it's an ace, we'll assume it's worth 11, but we'll also keep track of how many aces we have in our hand
kinda wanna throw the instruction card in 1 in every 10 shuffles for funny
if we have a jack and an ace, that's 21. 10 for jack, 11 for ace
we ONLY want Ace to be 1 if 11 would cause a bust
so, after we're done scoring our hand, we can check if we busted
did not think to do this
if we busted AND we have an ace in our hand, we can subtract 10 from our score
subtracting 10 basically says "treat that ace as 1 instead of 11"
also better solution than i had though to do
we can repeat this until we're either out of aces, or we no longer bust
I'll quickly show you the logic, but then I need to go!
for card in hand:
if card.rank.isdigit(): # numbers
total += int(card.rank)
elif card.rank in {'J', 'Q', 'K'}: # royals
total += 10
elif card.rank == 'A':
total += 11
aces += 1
while total > 21 and aces > 0:
total -= 10
aces -= 1
this while loop takes care of it
alright youve been great hopefully i catch ur eye when i eventually run into issues making scoundrel lol
Alright gtg, good luck!
thanks!!
This help channel has been closed. Feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.