TOTAL STEPS: 140 You are going to build a blackjack card game in Python. Every card in blackjack has a suit, rank, and value. For example, the king of hearts has a rank of "king", a suit of "hearts", and a value of 10 (In blackjack, face cards are worth 10). --- ```py suit = "hearts" ``` --- **FIRST TEST** Let's represent the king of hearts with Python code. Variables store data. The code already has a variable named `suit` that is set to the value of "hearts". Add a variable named `rank` and set it to the value of "K" (for king). --- ```py suit = "hearts" rank = "K" ``` --- When variables are set to equal a string, the string should be surounded by quotation marks. If a variable equals a number, quotation marks are not used around the number. Add a variable named `value` and set it to 10. --- ```py suit = "hearts" rank = "K" value = 10 ``` --- The code `print("Hello world")` calls the `print()` function and to prints the text "Hello World" to the console. Print the the text "Your card is:" to the console. --- ```py suit = "hearts" rank = "K" value = 10 print("Your card is:") ``` --- Instead of passing in a string to the `print()` function (i.e. "Your card is:"), you can also pass in a variable and the value of the variable will print to the console. Print the value of the `rank` variable to the console. --- ```py suit = "hearts" rank = "K" value = 10 print("Your card is:") print(rank) ``` --- The `+` operator can concatenate strings and/or variables together. Update your code so that the `print()` function is only called one time. It should print the following text to the console, using a variable for the rank: "Your card is: K" Hints: ``` name = "Quincy" print("My name is " + name) ``` That would print "My name is Quincy" to the console. --- ```py suit = "hearts" rank = "K" value = 10 print("Your card is: " + rank) ``` --- You can concatenate as many strings and variables as you want. Update your code so that the `print()` function prints the following text to the console, using variables for the rank and suit: "Your card is: K of hearts" --- ```py suit = "hearts" rank = "K" value = 10 print("Your card is: " + rank + " of " + suit) ``` --- You can use a list in python to store multiple values or items at a time. Here is an example of a list of strings: `place = ["first", "second", "third"]`. Below the `suit` variable, create a `suits` variable and assign it to a list of suits (spades, clubs, hearts, diamonds). --- ```py suits = ["spades", "clubs", "hearts", "diamonds"] suit = "hearts" rank = "K" value = 10 print("Your card is: " + rank + " of " + suit) ``` --- The bracket operator can be used to access a specific element in a list. The number inside the bracket specifies the index of the list to access (indices start at 0). For example, the following code prints "first" to the console: ``` place = ["first", "second", "third"] which = place[0] print(which) ``` Update the `suit` variable so that the value of "hearts" comes from the `suits` list. --- ```py suits = ["spades", "clubs", "hearts", "diamonds"] suit = suits[2] rank = "K" value = 10 print("Your card is: " + rank + " of " + suit) ``` --- 10. You can use a `for` loop go through each item in a list: ```py friends = ['Kris', 'Tom', 'Oliver'] for friend in friends: print(friend) ``` The above code goes through each item in the `friends` list, stores the value in the `friend` variable on each iteration, then prints it. Add a `for` loop to the end of your code that prints each suit. --- ```py suits = ["spades", "clubs", "hearts", "diamonds"] suit = suits[2] rank = "K" value = 10 print("Your card is: " + rank + " of " + suit) for suit in suits: print(suit) ``` --- Let's add another item to the `suits` list, just to see how it works. You can add a new value at the end of a list with `append`. For instance, here is how to add a new name to the `friends` list: `friends.append('Beau')`. Add the string "snakes" to the end of the `suits` list using `append`. Add the new line of code before the `for` loop so the loop will print the list with the new element. --- ```py suits = ["spades", "clubs", "hearts", "diamonds"] suit = suits[2] rank = "K" value = 10 print("Your card is: " + rank + " of " + suit) suits.append("snakes") for suit in suits: print(suit) ``` --- Now you will start the process of representing a full deck of cards with Python code. Keep the first line and the last two lines but delete everything else. It won't be needed for the deck. Changing or improving previously written code is called refactoring. --- ```py suits = ["spades", "clubs", "hearts", "diamonds"] for suit in suits: print(suit) ``` --- You have the list of suits. After that line create a list of ranks. (A, 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K) --- ```py suits = ["spades", "clubs", "hearts", "diamonds"] ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] for suit in suits: print(suit) ``` --- Before the `suits` list, create a new variable called `cards` and assign an empty list (`[]`) to the variable. --- ```py cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] for suit in suits: print(suit) ``` --- In the `cards` list, there should be an item for each card in the deck. Each item in the `suits` list should be combined with each item in the `ranks` list for a total of 52 items (cards). We'll work our way up to that. Update the `print` statement in the `for` loop so that it prints a list with two elements. The first element should be `suit` and the second should be the first element of the `ranks` list. This will print an ace ("A") in every suit. --- ```py cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] for suit in suits: print([suit, ranks[0]]) ``` --- Now, instead of just printing an ace in every suit, let's print every rank in every suit. This can be done easily with a `for` loop nested within another `for` loop. Inside the `for` loop, add another `for` loop that loops through the `ranks`. The `print` command should then be inside the second `for` loop instead of the first `for` loop (the `print` command should be indented 8 spaces from the beginning of the line, instead of 4). --- ```py cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] for suit in suits: for rank in ranks: print([suit, ranks[0]]) ``` --- If you run the code, you will see that it isn't quite what we want. It doesn't print all the ranks because the print command specifies the exact same rank in every iteration. Change `ranks[0]` to `rank`. --- ```py cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] for suit in suits: for rank in ranks: print([suit, rank]) ``` --- Great! Now all 52 cards are printed as two-item lists. An element in a list can be another list. Instead of printing 52 two-item lists, `append` those 52 lists to the `cards` list. --- ```py cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] for suit in suits: for rank in ranks: cards.append([suit, rank]) ``` --- Check what the `cards` list looks like by printing it out at the end of your code. If you run the code, you can see the result. --- ```py cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] for suit in suits: for rank in ranks: cards.append([suit, rank]) print(cards) ``` --- You may notice that all the cards are in order in the `cards` list. For a game like this, the cards must be shuffled. To help with this, add `import random` as the first line in your code. This imports the `random` module, which contains a variety of things related to random number generation. When you import a Python module, it allows you to use additional commands in your code. --- ```py import random cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] for suit in suits: for rank in ranks: cards.append([suit, rank]) print(cards) ``` --- Now you can call the `random.shuffle()` function. Call that function right above the `print` command and put `cards` in between the parenthesis to pass the `cards` list into the function. If you run your code afterwards, you should notice that the cards have been shuffled. --- ```py import random cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] for suit in suits: for rank in ranks: cards.append([suit, rank]) random.shuffle(cards) print(cards) ``` --- Let's remove a single element from the `cards` list. This is similar to dealing a card from a deck. This can be done with the `pop` method. Consider this code: ``` people = ["abbey", "mrugesh", "miya"] person = people.pop() ``` After running that code, `person` equals "miya" and `people` equals `["abbey", "mrugesh"]`. After shuffling the cards, remove the last item from the `cards` list and store it in a variable named `card`. --- ```py import random cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] for suit in suits: for rank in ranks: cards.append([suit, rank]) random.shuffle(cards) card = cards.pop() print(card) ``` --- When you call the `random.shuffle()` function, the program is running a sequence of statements (i.e. lines of code) to performs a computation. You can't see the sequence of statements but they are there inside the `random` module. You can create your own functions that will run the same sequence of statements everytime they are called. Here is an example of how to define a function called `greeting` that prints "Hi" everytime it is called (`def` is short for "define"). ```py def greeting(): print("Hi") ``` Put the line that shuffles the cards into a function called `shuffle`. --- ```py import random cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] for suit in suits: for rank in ranks: cards.append([suit, rank]) def shuffle(): random.shuffle(cards) card = cards.pop() print(cards) ``` --- Right before the `print` statement, call the `shuffle` function. The code inside a function will not run until it is called. Here is how you would call a function named "greeting": `greeting()` --- ```py import random cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] for suit in suits: for rank in ranks: cards.append([suit, rank]) def shuffle(): random.shuffle(cards) card = cards.pop() shuffle() print(cards) ``` --- Create a function named `deal` and put the line `card = cards.pop()` into the function. --- ```py import random cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] for suit in suits: for rank in ranks: cards.append([suit, rank]) def shuffle(): random.shuffle(cards) def deal(): card = cards.pop() shuffle() print(cards) ``` --- Variables can only be accessed in the context they were created. The `card` variable will not be available ouside of the `deal` function. You can get a value out of a function by returning a result using the `return` statement. At the end of the `deal` function add `return card`. Every line in a function must be indented the same number of spaces (in this case, 4 spaces). --- ```py import random cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] for suit in suits: for rank in ranks: cards.append([suit, rank]) def shuffle(): random.shuffle(cards) def deal(): card = cards.pop() return card shuffle() print(cards) ``` --- After the `shuffle` function is called, call the `deal` function and assign the returned value to a variable named `card`. Then update the `print` function to print `card` instead of `cards`. --- ```py import random cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] for suit in suits: for rank in ranks: cards.append([suit, rank]) def shuffle(): random.shuffle(cards) def deal(): card = cards.pop() return card shuffle() card = deal() print(card) ``` --- What if you want the `deal` function to deal more than one card? Let's refactor the `deal` function to accept an argument. Any number of arguments can apear inside the parentheses when a function is created, seperated by commas. Inside the function, the arguments are assigned to variables called parameters. Here is an example of a function that takes an argument: ```py def print_twice(bruce): print(bruce) print(bruce) ``` This function assigns the argument to a parameter named `bruce`. When the function is called, it prints the value of the parameter (whatever it is) twice. Make it so the `deal` function takes an argument named `number`. Then, call the function with the new parameter by upadating the last two lines of your code to: ``` cards_dealt = deal(2) print(cards_dealt) ``` --- ```py import random cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] for suit in suits: for rank in ranks: cards.append([suit, rank]) def shuffle(): random.shuffle(cards) def deal(number): card = cards.pop() return card shuffle() cards_dealt = deal(2) print(cards_dealt) ``` --- The `deal` function is now going to return a list of cards instead of a single card. In the first line of the function create an empty list named `cards_dealt`. Then update the last line of the function to `return cards_dealt`. --- ```py import random cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] for suit in suits: for rank in ranks: cards.append([suit, rank]) def shuffle(): random.shuffle(cards) def deal(number): cards_dealt = [] card = cards.pop() return cards_dealt shuffle() cards_dealt = deal(2) print(cards_dealt) ``` --- The `range` function can be used in a `for` loop to determine the number of loops. The following code will print "Hi" six times: ``` for x in range(6): print("Hi") ``` Put the line `card = cards.pop()` into a for loop that also `append`s the `card` onto the `cards_dealt` list. The loop should run the amount of times equal to the `number` parameter. --- ```py import random cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] for suit in suits: for rank in ranks: cards.append([suit, rank]) def shuffle(): random.shuffle(cards) def deal(number): cards_dealt = [] for x in range(number): card = cards.pop() cards_dealt.append(card) return cards_dealt shuffle() cards_dealt = deal(2) print(cards_dealt) ``` --- Let's seperate out a single card from the two cards dealt. At the end of your code create a variable called `card` and set it equal to the first item in the `cards_dealt` list. Then print the card. --- ```py import random cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] for suit in suits: for rank in ranks: cards.append([suit, rank]) def shuffle(): random.shuffle(cards) def deal(number): cards_dealt = [] for x in range(number): card = cards.pop() cards_dealt.append(card) return cards_dealt shuffle() cards_dealt = deal(2) print(cards_dealt) card = cards_dealt[0] print(card) ``` --- Let's seperate out the rank part of the single card. After the line where the variable `card` is created, create a variable named `rank` and assign it the rank from `card`. (Tip: The rank is at index 1.) --- ```py import random cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] for suit in suits: for rank in ranks: cards.append([suit, rank]) def shuffle(): random.shuffle(cards) def deal(number): cards_dealt = [] for x in range(number): card = cards.pop() cards_dealt.append(card) return cards_dealt shuffle() cards_dealt = deal(2) print(cards_dealt) card = cards_dealt[0] rank = card[1] print(card) ``` --- Each rank has a different value. The value of "A" is 11 (or sometimes 1, but we'll get to that later). "J", "Q", and "K" have the value of 10. The numbers have the value of the number. You need to check what the rank is and set the value depending on the rank. This is the perfect time for a conditional statement, specifically, an `if` statement. Here is an example: ```py if x == y: print('x and y are equal') ``` That code will only print 'x and y are equal' IF the variables names `x` and `y` are equal to the same value. Take special note of the doulble equal sign (`==`). This is used to check if two values are equal. Make sure to not confuse it with a single equal sign (`=`), which is used to assign a value to a variable. Before the `print` statement, add an `if` statement to check if `rank == "A"`. If so, assign 11 to a variable named `value`. --- ```py import random cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] for suit in suits: for rank in ranks: cards.append([suit, rank]) def shuffle(): random.shuffle(cards) def deal(number): cards_dealt = [] for x in range(number): card = cards.pop() cards_dealt.append(card) return cards_dealt shuffle() cards_dealt = deal(2) print(cards_dealt) card = cards_dealt[0] rank = card[1] if rank == "A": value = 11 print(card) ``` --- If `rank` does not equal "A", you'll want to check if it equals "J", "Q", or "K". That can be done with `elif`, which is an abbreviation of “else if.” For example: ``` if age < 13: print("You are a kid") elif age > 17: print("You are an adult") ``` Notice in that example that you can use the greater than (`>`) and less than (`<`) signs in conditional statements. Some other comparison operators include `=!` (not equal to), `<=` (less that or equal to), and `>=` (greater than or equal to). After the `if` statement, add the line `elif rank == "J":`. Then inside the `elif` statement assign 10 to `value`. --- ```py import random cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] for suit in suits: for rank in ranks: cards.append([suit, rank]) def shuffle(): random.shuffle(cards) def deal(number): cards_dealt = [] for x in range(number): card = cards.pop() cards_dealt.append(card) return cards_dealt shuffle() cards_dealt = deal(2) print(cards_dealt) card = cards_dealt[0] rank = card[1] if rank == "A": value = 11 elif rank == "J": value = 10 print(card) ``` --- There are three logical operators: `and`, `or`, and `not`. You can use these operators in conditional statements to check multiple conditions at once. Update `elif rank == "J":` to `elif rank == "J" or rank == "Q" or rank == "K":` ```py import random cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] for suit in suits: for rank in ranks: cards.append([suit, rank]) def shuffle(): random.shuffle(cards) def deal(number): cards_dealt = [] for x in range(number): card = cards.pop() cards_dealt.append(card) return cards_dealt shuffle() cards_dealt = deal(2) print(cards_dealt) card = cards_dealt[0] rank = card[1] if rank == "A": value = 11 elif rank == "J" or rank == "Q" or rank == "K": value = 10 print(card) ``` --- There can be any number of `elif` statements after an `if` statement. At the end, there can be an `else` statement. The block of code in an `else` statement executes if the `if` and all `elif` statements evaluate to `False`. Here is an example: ``` if age < 13: print("You are a kid") elif age > 17: print("You are an adult") else: print("You are a teenager") ``` After the `elif` statement, add an `else` statement. Inside, assign `rank` to `value`. --- ```py import random cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] for suit in suits: for rank in ranks: cards.append([suit, rank]) def shuffle(): random.shuffle(cards) def deal(number): cards_dealt = [] for x in range(number): card = cards.pop() cards_dealt.append(card) return cards_dealt shuffle() cards_dealt = deal(2) print(cards_dealt) card = cards_dealt[0] rank = card[1] if rank == "A": value = 11 elif rank == "J" or rank == "Q" or rank == "K": value = 10 else: value = rank print(card) ``` --- Update the `print` statement at the end to `print(rank, value)`. Then try running the code a few times. You should see a different result each time. (Note: When mutiple values in a print statement are listed with a comma speraing them, both values are printed with a space in between.) --- ```py import random cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] for suit in suits: for rank in ranks: cards.append([suit, rank]) def shuffle(): random.shuffle(cards) def deal(number): cards_dealt = [] for x in range(number): card = cards.pop() cards_dealt.append(card) return cards_dealt shuffle() cards_dealt = deal(2) print(cards_dealt) card = cards_dealt[0] rank = card[1] if rank == "A": value = 11 elif rank == "J" or rank == "Q" or rank == "K": value = 10 else: value = rank print(rank, value) ``` --- A Python dictionary is like a list, but more general. You can think of a dictionary as a mapping between a set of indices (which are called keys) and a set of values. Each key maps to a value. The association of a key and a value is called a key-value pair or sometimes an item. Here is a dictionary that maps from English to Spanish. They keys are the English words and the values are the Spanish words. ```py eng2sp = {"one": "uno", "two": "dos", "three": "tres"} ``` Above the `print` statement, create varialbe called `rank_dict` and assign to it this dictionary: `{"rank": rank, "value": value}`. --- ```py import random cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] for suit in suits: for rank in ranks: cards.append([suit, rank]) def shuffle(): random.shuffle(cards) def deal(number): cards_dealt = [] for x in range(number): card = cards.pop() cards_dealt.append(card) return cards_dealt shuffle() cards_dealt = deal(2) print(cards_dealt) card = cards_dealt[0] rank = card[1] if rank == "A": value = 11 elif rank == "J" or rank == "Q" or rank == "K": value = 10 else value = rank rank_dict = {"rank": rank, "value": value} print(rank, value) ``` --- ```py eng2sp = {"one": "uno", "two": "dos", "three": "tres"} print(eng2sp["one"]) ``` The code above will print "uno". Just like you access an item in a list by specifiying the index inside `[]`, you can access an item in a dictionary by specifying the key inside `[]`. Update the `print` statement so that you are accessing the rank and value from `rank_dict` instead of directly from the variables. --- ```py import random cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] for suit in suits: for rank in ranks: cards.append([suit, rank]) def shuffle(): random.shuffle(cards) def deal(number): cards_dealt = [] for x in range(number): card = cards.pop() cards_dealt.append(card) return cards_dealt shuffle() cards_dealt = deal(2) print(cards_dealt) card = cards_dealt[0] rank = card[1] if rank == "A": value = 11 elif rank == "J" or rank == "Q" or rank == "K": value = 10 else value = rank rank_dict = {"rank": rank, "value": value} print(rank_dict["rank"], rank_dict["value"]) ``` --- When writing a program, there are many ways to do almost everthing. Now you will refactor your code to get the value of each rank without using an `if` statement. Instead, you will store both the rank name and value in the `ranks` list using dictionaries. Delete all the lines of code after `shuffle()`. --- ```py import random cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] for suit in suits: for rank in ranks: cards.append([suit, rank]) def shuffle(): random.shuffle(cards) def deal(number): cards_dealt = [] for x in range(number): card = cards.pop() cards_dealt.append(card) return cards_dealt shuffle() ``` --- Get a single card not in a list by adding the following line at the end of your code: `card = deal(1)[0]`. --- ```py import random cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] for suit in suits: for rank in ranks: cards.append([suit, rank]) def shuffle(): random.shuffle(cards) def deal(number): cards_dealt = [] for x in range(number): card = cards.pop() cards_dealt.append(card) return cards_dealt shuffle() card = deal(1)[0] ``` --- Now, update the `ranks` list. Each element in the list should be a dictionary. When lists or list elements are long, it is common to put each element on it's own line. Here is the beginning of the new `ranks` list: ```py ranks = [ {"rank": "A", "value": 11}, {"rank": "2", "value": 2}, {"rank": "3", "value": 3}, ... ] ``` Update `ranks` in your code using the section above as a starting point. Replace "..." with the other ranks and values. (Remember, "J", "K", and "Q" have a value of 10 and the numers have the value of the number.) --- ```py import random cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = [ {"rank": "A", "value": 11}, {"rank": "2", "value": 2}, {"rank": "3", "value": 3}, {"rank": "4", "value": 4}, {"rank": "5", "value": 5}, {"rank": "6", "value": 6}, {"rank": "7", "value": 7}, {"rank": "8", "value": 8}, {"rank": "9", "value": 9}, {"rank": "10", "value": 10}, {"rank": "J", "value": 10}, {"rank": "Q", "value": 10}, {"rank": "K", "value": 10}, ] for suit in suits: for rank in ranks: cards.append([suit, rank]) def shuffle(): random.shuffle(cards) def deal(number): cards_dealt = [] for x in range(number): card = cards.pop() cards_dealt.append(card) return cards_dealt shuffle() card = deal(1)[0] ``` --- At the end of your code, print `card`. Try running your program to see what prints now that you have updated the `ranks` list. --- ```py import random cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = [ {"rank": "A", "value": 11}, {"rank": "2", "value": 2}, {"rank": "3", "value": 3}, {"rank": "4", "value": 4}, {"rank": "5", "value": 5}, {"rank": "6", "value": 6}, {"rank": "7", "value": 7}, {"rank": "8", "value": 8}, {"rank": "9", "value": 9}, {"rank": "10", "value": 10}, {"rank": "J", "value": 10}, {"rank": "Q", "value": 10}, {"rank": "K", "value": 10}, ] for suit in suits: for rank in ranks: cards.append([suit, rank]) def shuffle(): random.shuffle(cards) def deal(number): cards_dealt = [] for x in range(number): card = cards.pop() cards_dealt.append(card) return cards_dealt shuffle() card = deal(1)[0] print(card) ``` --- If you want to get just the rank of `card`, you will first have to access the second element in the list, then you will have to access the `"rank"` item in the dictionary. Because you are accessing something two times, there will be two sets of brackets. Look at this example: ```py card = ["clubs", {"rank": "J", "value": 10}] rank = card[1]["rank"] ``` In that code, `rank` now equals "J". Think about the code until you understand why. Update your code so the `print` statement will print just the value in `card`. --- ```py import random cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = [ {"rank": "A", "value": 11}, {"rank": "2", "value": 2}, {"rank": "3", "value": 3}, {"rank": "4", "value": 4}, {"rank": "5", "value": 5}, {"rank": "6", "value": 6}, {"rank": "7", "value": 7}, {"rank": "8", "value": 8}, {"rank": "9", "value": 9}, {"rank": "10", "value": 10}, {"rank": "J", "value": 10}, {"rank": "Q", "value": 10}, {"rank": "K", "value": 10}, ] for suit in suits: for rank in ranks: cards.append([suit, rank]) def shuffle(): random.shuffle(cards) def deal(number): cards_dealt = [] for x in range(number): card = cards.pop() cards_dealt.append(card) return cards_dealt shuffle() card = deal(1)[0] print(card[1]["value"]) ``` --- Now you will start defining classes that will be used in order to separate out different aspects of the game. Classes provide a way of bundling data and functionality together. Creating a new class creates a new type of object, allowing new instances of that type to be made. An object can contain a number of functions (which we call methods) as well as data that is used by those functions (called attributes). You will use classes to model three parts of the game: Card, Deck, and Hand. So far, you've mainly worked on elements of the `Deck` class. Right after the `import` statement at the top, add this line: `class Deck:`. Then, highlight all the code after that line and hit the "Tab" key on your keyboard. This will indent all the code and make it part of the `Deck` class. --- ```py import random class Deck: cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = [ {"rank": "A", "value": 11}, {"rank": "2", "value": 2}, {"rank": "3", "value": 3}, {"rank": "4", "value": 4}, {"rank": "5", "value": 5}, {"rank": "6", "value": 6}, {"rank": "7", "value": 7}, {"rank": "8", "value": 8}, {"rank": "9", "value": 9}, {"rank": "10", "value": 10}, {"rank": "J", "value": 10}, {"rank": "Q", "value": 10}, {"rank": "K", "value": 10}, ] for suit in suits: for rank in ranks: cards.append([suit, rank]) def shuffle(): random.shuffle(cards) def deal(number): cards_dealt = [] for x in range(number): card = cards.pop() cards_dealt.append(card) return cards_dealt shuffle() card = deal(1)[0] print(card[1]["value"]) ``` --- Remove the uneeded code in the `Deck` class by removing the last three lines of code. --- ```py import random class Deck: cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = [ {"rank": "A", "value": 11}, {"rank": "2", "value": 2}, {"rank": "3", "value": 3}, {"rank": "4", "value": 4}, {"rank": "5", "value": 5}, {"rank": "6", "value": 6}, {"rank": "7", "value": 7}, {"rank": "8", "value": 8}, {"rank": "9", "value": 9}, {"rank": "10", "value": 10}, {"rank": "J", "value": 10}, {"rank": "Q", "value": 10}, {"rank": "K", "value": 10}, ] for suit in suits: for rank in ranks: cards.append([suit, rank]) def shuffle(): random.shuffle(cards) def deal(number): cards_dealt = [] for x in range(number): card = cards.pop() cards_dealt.append(card) return cards_dealt ``` --- A class is like a template. You can use that class to create an instance of the class, called an object. Then you can use the instance. Each instance keeps it's own state so you can update an instance created from a class and it won't impact other objects created from the same class. Soon, you will see an example of what all this means so it will be easier to understand. First, let's prepare our class to create an instance from it. When you create an instance of a class, Python automatically calls a funtion (also called a method) in the class named `__init__`. The contents of this method shoud be code that is run one time to initialize the instance. Define this function by adding the following line of code directly under `class Deck:`: `def __init__(self):`. Now indent all the code that is not part of the `shuffle` or `deal` functions so the code will be part of this new function. --- ```py import random class Deck: def __init__(self): cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = [ {"rank": "A", "value": 11}, {"rank": "2", "value": 2}, {"rank": "3", "value": 3}, {"rank": "4", "value": 4}, {"rank": "5", "value": 5}, {"rank": "6", "value": 6}, {"rank": "7", "value": 7}, {"rank": "8", "value": 8}, {"rank": "9", "value": 9}, {"rank": "10", "value": 10}, {"rank": "J", "value": 10}, {"rank": "Q", "value": 10}, {"rank": "K", "value": 10}, ] for suit in suits: for rank in ranks: cards.append([suit, rank]) def shuffle(): random.shuffle(cards) def deal(number): cards_dealt = [] for x in range(number): card = cards.pop() cards_dealt.append(card) return cards_dealt ``` --- Notice the word "self" in the parenthesis of the function you just added. When defining a function, anything inside the parentheses is called an argument. These are variables passed in from the caller to the function. All functions in a class should recieve `self` as an argument. `self` represents the instance of the class. By using the `self` keyword, the function can access the attributes and methods of the class. For example, this would allow you to call the `shuffle` function from within the `__init__` function. Add the `self` as the first item inside the parentheses on the definitions of the `shuffle` and `deal` functions. --- ```py import random class Deck: def __init__(self): cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = [ {"rank": "A", "value": 11}, {"rank": "2", "value": 2}, {"rank": "3", "value": 3}, {"rank": "4", "value": 4}, {"rank": "5", "value": 5}, {"rank": "6", "value": 6}, {"rank": "7", "value": 7}, {"rank": "8", "value": 8}, {"rank": "9", "value": 9}, {"rank": "10", "value": 10}, {"rank": "J", "value": 10}, {"rank": "Q", "value": 10}, {"rank": "K", "value": 10}, ] for suit in suits: for rank in ranks: cards.append([suit, rank]) def shuffle(self): random.shuffle(cards) def deal(self, number): cards_dealt = [] for x in range(number): card = cards.pop() cards_dealt.append(card) return cards_dealt ``` --- If you look at the variables defined inside the `__init__` function, only `cards` is used in other functions. Inside a class, in order to access a variable in multiple functions (also called methods), the variable has to start with `self.`. Change all instances of `cards` in every function to `self.cards`. --- ```py import random class Deck: def __init__(self): self.cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = [ {"rank": "A", "value": 11}, {"rank": "2", "value": 2}, {"rank": "3", "value": 3}, {"rank": "4", "value": 4}, {"rank": "5", "value": 5}, {"rank": "6", "value": 6}, {"rank": "7", "value": 7}, {"rank": "8", "value": 8}, {"rank": "9", "value": 9}, {"rank": "10", "value": 10}, {"rank": "J", "value": 10}, {"rank": "Q", "value": 10}, {"rank": "K", "value": 10}, ] for suit in suits: for rank in ranks: self.cards.append([suit, rank]) def shuffle(self): random.shuffle(self.cards) def deal(self, number): cards_dealt = [] for x in range(number): card = self.cards.pop() cards_dealt.append(card) return cards_dealt ``` --- You can now create an instance (also called object) of the deck class. At the very end of your code add the line `deck1 = Deck()` (with no indentation). --- ```py import random class Deck: def __init__(self): self.cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = [ {"rank": "A", "value": 11}, {"rank": "2", "value": 2}, {"rank": "3", "value": 3}, {"rank": "4", "value": 4}, {"rank": "5", "value": 5}, {"rank": "6", "value": 6}, {"rank": "7", "value": 7}, {"rank": "8", "value": 8}, {"rank": "9", "value": 9}, {"rank": "10", "value": 10}, {"rank": "J", "value": 10}, {"rank": "Q", "value": 10}, {"rank": "K", "value": 10}, ] for suit in suits: for rank in ranks: self.cards.append([suit, rank]) def shuffle(self): random.shuffle(self.cards) def deal(self, number): cards_dealt = [] for x in range(number): card = self.cards.pop() cards_dealt.append(card) return cards_dealt deck1 = Deck() ``` --- If you have an instance of a class named `car` with an attribute named `model`, you can access the value of the attribute with `car.model`. In your code, `cards` is an attribute of the `deck1` instance created from the `Deck` class. Print the `cards` attribute. --- ```py import random class Deck: def __init__(self): self.cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = [ {"rank": "A", "value": 11}, {"rank": "2", "value": 2}, {"rank": "3", "value": 3}, {"rank": "4", "value": 4}, {"rank": "5", "value": 5}, {"rank": "6", "value": 6}, {"rank": "7", "value": 7}, {"rank": "8", "value": 8}, {"rank": "9", "value": 9}, {"rank": "10", "value": 10}, {"rank": "J", "value": 10}, {"rank": "Q", "value": 10}, {"rank": "K", "value": 10}, ] for suit in suits: for rank in ranks: self.cards.append([suit, rank]) def shuffle(self): random.shuffle(self.cards) def deal(self, number): cards_dealt = [] for x in range(number): card = self.cards.pop() cards_dealt.append(card) return cards_dealt deck1 = Deck() print(deck1.cards) ``` --- If you run the code now, you should see the `cards` list from `deck` with the cards in order. You already created an instance of the `Deck` class called `deck1`. Underneath that and before the `print` statement, create another instance of the `Deck` class called `deck2`. --- ```py import random class Deck: def __init__(self): self.cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = [ {"rank": "A", "value": 11}, {"rank": "2", "value": 2}, {"rank": "3", "value": 3}, {"rank": "4", "value": 4}, {"rank": "5", "value": 5}, {"rank": "6", "value": 6}, {"rank": "7", "value": 7}, {"rank": "8", "value": 8}, {"rank": "9", "value": 9}, {"rank": "10", "value": 10}, {"rank": "J", "value": 10}, {"rank": "Q", "value": 10}, {"rank": "K", "value": 10}, ] for suit in suits: for rank in ranks: self.cards.append([suit, rank]) def shuffle(self): random.shuffle(self.cards) def deal(self, number): cards_dealt = [] for x in range(number): card = self.cards.pop() cards_dealt.append(card) return cards_dealt deck1 = Deck() deck2 = Deck() print(deck1.cards) ``` If you have an instance of a class named `car` with an method named `drive`, you can call the method with `car.drive()`. In your code, `shuffle` is a method of the `deck2` instance created from the `Deck` class. Call that method right before the `print` statement. --- ```py import random class Deck: def __init__(self): self.cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = [ {"rank": "A", "value": 11}, {"rank": "2", "value": 2}, {"rank": "3", "value": 3}, {"rank": "4", "value": 4}, {"rank": "5", "value": 5}, {"rank": "6", "value": 6}, {"rank": "7", "value": 7}, {"rank": "8", "value": 8}, {"rank": "9", "value": 9}, {"rank": "10", "value": 10}, {"rank": "J", "value": 10}, {"rank": "Q", "value": 10}, {"rank": "K", "value": 10}, ] for suit in suits: for rank in ranks: self.cards.append([suit, rank]) def shuffle(self): random.shuffle(self.cards) def deal(self, number): cards_dealt = [] for x in range(number): card = self.cards.pop() cards_dealt.append(card) return cards_dealt deck1 = Deck() deck2 = Deck() deck2.shuffle() print(deck1.cards) ``` At the end of your code, print the `cards` attribute from the `deck2` instance. If you run the code, you will see that the order of the `cards` list is different each time it is printed. That is because each instance stores the state of it's variables seperately. In the `deck2` instance, the cards were shuffled. In the `deck1` instance, the cards were not shuffled. --- ```py import random class Deck: def __init__(self): self.cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = [ {"rank": "A", "value": 11}, {"rank": "2", "value": 2}, {"rank": "3", "value": 3}, {"rank": "4", "value": 4}, {"rank": "5", "value": 5}, {"rank": "6", "value": 6}, {"rank": "7", "value": 7}, {"rank": "8", "value": 8}, {"rank": "9", "value": 9}, {"rank": "10", "value": 10}, {"rank": "J", "value": 10}, {"rank": "Q", "value": 10}, {"rank": "K", "value": 10}, ] for suit in suits: for rank in ranks: self.cards.append([suit, rank]) def shuffle(self): random.shuffle(self.cards) def deal(self, number): cards_dealt = [] for x in range(number): card = self.cards.pop() cards_dealt.append(card) return cards_dealt deck1 = Deck() deck2 = Deck() deck2.shuffle() print(deck1.cards) print(deck2.cards) ``` SEE IF PEOPLE CAN FIX ERROR OF 0 CARDS The `Deck` works. Now let's add safeguards to prevent errors. Everytime the `deal` function is called, a card is removed from the `cards` list. You can only remove a card if there are cards to remove. So before the program tries to `pop()` a card off of `self.cards`, it should check `if` the length of `self.cards` is greater than (`>`) 0. You can get the number of items in a list with `len()`. Here is an example: `len(self.cards)`. Inside the `deal` function, put all the code inside the appropriate `if` statement. --- ```py import random class Deck: def __init__(self): self.cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = [ {"rank": "A", "value": 11}, {"rank": "2", "value": 2}, {"rank": "3", "value": 3}, {"rank": "4", "value": 4}, {"rank": "5", "value": 5}, {"rank": "6", "value": 6}, {"rank": "7", "value": 7}, {"rank": "8", "value": 8}, {"rank": "9", "value": 9}, {"rank": "10", "value": 10}, {"rank": "J", "value": 10}, {"rank": "Q", "value": 10}, {"rank": "K", "value": 10}, ] for suit in suits: for rank in ranks: self.cards.append([suit, rank]) def shuffle(self): random.shuffle(self.cards) def deal(self, number): cards_dealt = [] for x in range(number): if len(self.cards) > 0: card = self.cards.pop() cards_dealt.append(card) return cards_dealt deck1 = Deck() deck2 = Deck() deck2.shuffle() print(deck1.cards) print(deck2.cards) ``` --- A deck with only one card does not need to be shuffled. Add the appropriate `if` statement to the `shuffle` function. --- ```py import random class Deck: def __init__(self): self.cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = [ {"rank": "A", "value": 11}, {"rank": "2", "value": 2}, {"rank": "3", "value": 3}, {"rank": "4", "value": 4}, {"rank": "5", "value": 5}, {"rank": "6", "value": 6}, {"rank": "7", "value": 7}, {"rank": "8", "value": 8}, {"rank": "9", "value": 9}, {"rank": "10", "value": 10}, {"rank": "J", "value": 10}, {"rank": "Q", "value": 10}, {"rank": "K", "value": 10}, ] for suit in suits: for rank in ranks: self.cards.append([suit, rank]) def shuffle(self): if len(self.cards) > 1: random.shuffle(self.cards) def deal(self, number): cards_dealt = [] for x in range(number): if len(self.cards) > 0: card = self.cards.pop() cards_dealt.append(card) return cards_dealt deck1 = Deck() deck2 = Deck() deck2.shuffle() print(deck1.cards) print(deck2.cards) ``` --- Since a "Card" is a seperate concept than a "Deck", next you'll make a `Card` class. Using the `Deck` class as an example, create a `Card` class above the `Deck` class. Add an `__init__` function and inside that fuction set `self.suit` to equal "hearts". --- ```py import random class Card: def __init__(self): self.suit = "hearts" class Deck: def __init__(self): self.cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = [ {"rank": "A", "value": 11}, {"rank": "2", "value": 2}, {"rank": "3", "value": 3}, {"rank": "4", "value": 4}, {"rank": "5", "value": 5}, {"rank": "6", "value": 6}, {"rank": "7", "value": 7}, {"rank": "8", "value": 8}, {"rank": "9", "value": 9}, {"rank": "10", "value": 10}, {"rank": "J", "value": 10}, {"rank": "Q", "value": 10}, {"rank": "K", "value": 10}, ] for suit in suits: for rank in ranks: self.cards.append([suit, rank]) def shuffle(self): if len(self.cards) > 1: random.shuffle(self.cards) def deal(self, number): cards_dealt = [] for x in range(number): if len(self.cards) > 0: card = self.cards.pop() cards_dealt.append(card) return cards_dealt deck1 = Deck() deck2 = Deck() deck2.shuffle() print(deck1.cards) print(deck2.cards) ``` --- Also inside `__init__`, create a variable called `self.rank` and set it to "A". --- ```py import random class Card: def __init__(self): self.suit = "hearts" self.rank = "A" class Deck: def __init__(self): self.cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = [ {"rank": "A", "value": 11}, {"rank": "2", "value": 2}, {"rank": "3", "value": 3}, {"rank": "4", "value": 4}, {"rank": "5", "value": 5}, {"rank": "6", "value": 6}, {"rank": "7", "value": 7}, {"rank": "8", "value": 8}, {"rank": "9", "value": 9}, {"rank": "10", "value": 10}, {"rank": "J", "value": 10}, {"rank": "Q", "value": 10}, {"rank": "K", "value": 10}, ] for suit in suits: for rank in ranks: self.cards.append([suit, rank]) def shuffle(self): if len(self.cards) > 1: random.shuffle(self.cards) def deal(self, number): cards_dealt = [] for x in range(number): if len(self.cards) > 0: card = self.cards.pop() cards_dealt.append(card) return cards_dealt deck1 = Deck() deck2 = Deck() deck2.shuffle() print(deck1.cards) print(deck2.cards) ``` --- Currently, anytime a `Card` is created, it will be an Ace of Hearts. Refactor the code so the suit and rank are specified when a `Card` object is constructed. The `__self__` method can take additioinal parameters (besides `self`) that are passed into it as the object is constructed. Here is an example of a `Person` class where the `name` and `age` are specified when an object is constructed: ```py class Person: def __init__(self, name, age): self.name = name self.age = age sally = Person("Sally", 32) print("Name: " + sally.name + ", Age: " + sally.age) ``` That code prints out "Sally 32". --- ```py import random class Card: def __init__(self, suit, rank): self.suit = suit self.rank = rank class Deck: def __init__(self): self.cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = [ {"rank": "A", "value": 11}, {"rank": "2", "value": 2}, {"rank": "3", "value": 3}, {"rank": "4", "value": 4}, {"rank": "5", "value": 5}, {"rank": "6", "value": 6}, {"rank": "7", "value": 7}, {"rank": "8", "value": 8}, {"rank": "9", "value": 9}, {"rank": "10", "value": 10}, {"rank": "J", "value": 10}, {"rank": "Q", "value": 10}, {"rank": "K", "value": 10}, ] for suit in suits: for rank in ranks: self.cards.append([suit, rank]) def shuffle(self): if len(self.cards) > 1: random.shuffle(self.cards) def deal(self, number): cards_dealt = [] for x in range(number): if len(self.cards) > 0: card = self.cards.pop() cards_dealt.append(card) return cards_dealt deck1 = Deck() deck2 = Deck() deck2.shuffle() print(deck1.cards) print(deck2.cards) ``` --- When a class has a `__str__` method, it is called when `print()` is invoked on an object from the class. In the `Card` class, add a `__str__` method. Inside the method add `return self.rank['rank'] + " of " + self.suit` to return what should display when a card is printed. --- ```py import random class Card: def __init__(self, suit, rank): self.suit = suit self.rank = rank def __str__(self): return self.rank['rank'] + " of " + self.suit class Deck: def __init__(self): self.cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = [ {"rank": "A", "value": 11}, {"rank": "2", "value": 2}, {"rank": "3", "value": 3}, {"rank": "4", "value": 4}, {"rank": "5", "value": 5}, {"rank": "6", "value": 6}, {"rank": "7", "value": 7}, {"rank": "8", "value": 8}, {"rank": "9", "value": 9}, {"rank": "10", "value": 10}, {"rank": "J", "value": 10}, {"rank": "Q", "value": 10}, {"rank": "K", "value": 10}, ] for suit in suits: for rank in ranks: self.cards.append([suit, rank]) def shuffle(self): if len(self.cards) > 1: random.shuffle(self.cards) def deal(self, number): cards_dealt = [] for x in range(number): if len(self.cards) > 0: card = self.cards.pop() cards_dealt.append(card) return cards_dealt deck1 = Deck() deck2 = Deck() deck2.shuffle() print(deck1.cards) print(deck2.cards) ``` --- Try out the new `__str__` method. Delete the last five lines in the code (everything after the `Deck` class). Add the following lines: ```py card1 = Card("diamonds", {"rank": "A", "value": 11}) card2 = Card("spades", {"rank": "5", "value": 5}) print(card1) print(card2) ``` --- ```py import random class Card: def __init__(self, suit, rank): self.suit = suit self.rank = rank def __str__(self): return self.rank['rank'] + " of " + self.suit class Deck: def __init__(self): self.cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = [ {"rank": "A", "value": 11}, {"rank": "2", "value": 2}, {"rank": "3", "value": 3}, {"rank": "4", "value": 4}, {"rank": "5", "value": 5}, {"rank": "6", "value": 6}, {"rank": "7", "value": 7}, {"rank": "8", "value": 8}, {"rank": "9", "value": 9}, {"rank": "10", "value": 10}, {"rank": "J", "value": 10}, {"rank": "Q", "value": 10}, {"rank": "K", "value": 10}, ] for suit in suits: for rank in ranks: self.cards.append([suit, rank]) def shuffle(self): if len(self.cards) > 1: random.shuffle(self.cards) def deal(self, number): cards_dealt = [] for x in range(number): if len(self.cards) > 0: card = self.cards.pop() cards_dealt.append(card) return cards_dealt card1 = Card("diamonds", {"rank": "A", "value": 11}) card2 = Card("spades", {"rank": "5", "value": 5}) print(card1) print(card2) ``` --- F-strings allow you to include variables inside of strings so you don't have to concatenate the strings. Here is how you would create an f-string with the variables `name` and `age` inside: `f"My name is {name} and I am {age} years old"`. Notice it begins with "f" and the variables are within curly braces. Update the return statement in `__str__` to use an f-string. --- ```py import random class Card: def __init__(self, suit, rank): self.suit = suit self.rank = rank def __str__(self): return f"{self.rank['rank']} of {self.suit}" class Deck: def __init__(self): self.cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = [ {"rank": "A", "value": 11}, {"rank": "2", "value": 2}, {"rank": "3", "value": 3}, {"rank": "4", "value": 4}, {"rank": "5", "value": 5}, {"rank": "6", "value": 6}, {"rank": "7", "value": 7}, {"rank": "8", "value": 8}, {"rank": "9", "value": 9}, {"rank": "10", "value": 10}, {"rank": "J", "value": 10}, {"rank": "Q", "value": 10}, {"rank": "K", "value": 10}, ] for suit in suits: for rank in ranks: self.cards.append([suit, rank]) def shuffle(self): if len(self.cards) > 1: random.shuffle(self.cards) def deal(self, number): cards_dealt = [] for x in range(number): if len(self.cards) > 0: card = self.cards.pop() cards_dealt.append(card) return cards_dealt card1 = Card("diamonds", {"rank": "A", "value": 11}) card2 = Card("spades", {"rank": "5", "value": 5}) print(card1) print(card2) ``` --- Currently, in the `Deck` class, the last line of the `__init__` method appends a list as an item to the `cards` list. Instead of appending the list (`[suit, rank]`), create and append an instance of the `Card` class (`Card(suit, rank)`). Afterwards, when a `Deck` is created, it is filled with `Card`s. --- ```py import random class Card: def __init__(self, suit, rank): self.suit = suit self.rank = rank def __str__(self): return f"{self.rank['rank']} of {self.suit}" class Deck: def __init__(self): self.cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = [ {"rank": "A", "value": 11}, {"rank": "2", "value": 2}, {"rank": "3", "value": 3}, {"rank": "4", "value": 4}, {"rank": "5", "value": 5}, {"rank": "6", "value": 6}, {"rank": "7", "value": 7}, {"rank": "8", "value": 8}, {"rank": "9", "value": 9}, {"rank": "10", "value": 10}, {"rank": "J", "value": 10}, {"rank": "Q", "value": 10}, {"rank": "K", "value": 10}, ] for suit in suits: for rank in ranks: self.cards.append(Card(suit, rank)) def shuffle(self): if len(self.cards) > 1: random.shuffle(self.cards) def deal(self, number): cards_dealt = [] for x in range(number): if len(self.cards) > 0: card = self.cards.pop() cards_dealt.append(card) return cards_dealt card1 = Card("diamonds", {"rank": "A", "value": 11}) card2 = Card("spades", {"rank": "5", "value": 5}) print(card1) print(card2) ``` --- The `Deck` and `Card` classes could be used for any card game. Now make a `Hand` class. This will represent a hand in the game of blackjack. Add a `__init__` method inside the `Hand` class that intializes a variable called `self.cards` that is set to an empty list. Remove the code at the end that are not in a class. --- ```py import random class Card: def __init__(self, suit, rank): self.suit = suit self.rank = rank def __str__(self): return f"{self.rank['rank']} of {self.suit}" class Deck: def __init__(self): self.cards = [] suits = ["spades", "clubs", "hearts", "diamonds"] ranks = [ {"rank": "A", "value": 11}, {"rank": "2", "value": 2}, {"rank": "3", "value": 3}, {"rank": "4", "value": 4}, {"rank": "5", "value": 5}, {"rank": "6", "value": 6}, {"rank": "7", "value": 7}, {"rank": "8", "value": 8}, {"rank": "9", "value": 9}, {"rank": "10", "value": 10}, {"rank": "J", "value": 10}, {"rank": "Q", "value": 10}, {"rank": "K", "value": 10}, ] for suit in suits: for rank in ranks: self.cards.append(Card(suit, rank)) def shuffle(self): if len(self.cards) > 1: random.shuffle(self.cards) def deal(self, number): cards_dealt = [] for x in range(number): if len(self.cards) > 0: card = self.cards.pop() cards_dealt.append(card) return cards_dealt class Hand: def __init__(self): self.cards = [] ``` --- PART TWO IS HERE: https://gist.github.com/beaucarnes/05903eb6f4be455dd47506c8f3470be2