Level 7: Challenge 2 - IncrediCoders/Python1 GitHub Wiki

Syntax Turtle added this page on June 6, 2023


It's time for your second challenge for Level 7!

Hopefully, Challenge 1 wasn't too hard. :)

This challenge is going to be harder. If you think about it, this is the last level of the book, and the second/last challenge of the last level! So, this should be the most difficult of the challenges! They aren't called "challenges" for no reason!

However, we (Syntax and Grafika) are going to help you through each step! You can do it!

For this challenge, you're going to add a second attack option to the game, the Coded Attack! First, you always delivery one hit of damage to the opponent card. This is important, because unlike the TechType Attack, you're guaranteed to deliver this one point of damage!

The Coded Attack also gives your card a special ability, if you get Heads on the coin flip!

What are the Coded Attack special abilities?

What that special ability is, depends on the card. Each card has one of these special abilities (if the coin lands on Heads):

  1. You deliver an extra hit, totaling two damage.
  2. You get another turn!
  3. You get one health back.
  4. You make your opponent get Tails in their next turn!

To find the Level 7 Challenge 2 code template, open the Level 7 folder, the Challenges folder, and then the Challenge2 folder. (In our GitHub repo, you can find the code template in the Challenge2 folder.) You should already have the files all set up and ready to go (see Set up the files). Open the IncrediCards_Challenge2.py file to build the program, by following along with my instructions below!

I broke these instructions down into a few sections:

Explaining the Code

You should have your IncrediCards_Challenge2.py file loaded into your code editor.

On Line 1, from init import * imports code from the init.py file, which sets up the game and includes the features and functions that you'll use throughout this game. The asterisk specifies that we're importing everything from the file.

NEW CODE: On Line 4, we have our first #TODO code comment! See the next section, "Write Your Own Code" below, with instructions on how you're going to add one more parameter to each character card's function. It's the name of the Coded Attack. For now, let's keep explaining the code that's already in the file!

Lines 5-24 create all the cards, including the primary variables for the cards. Then, we also create all the attributes for the cards... the names on the cards, the primary programming languages that each student uses (we call these their "TechTypes"), the TechTypes that they are weak to, the TechTypes that they are strong/resistant to, their PNG file variables (such as annie_conda_img), and their TechType icon variables (such as icon_python). These PNG and icon variables are what show the images on the screen. For example, on Line 4, we have the code, annie_conda = Card('Annie Conda', 'python', 'java', 'bash', annie_conda_img, icon_python). Can you describe what content is in each variable?

On Line 26, the code DECK = [] creates the DECK list. A list is a variable that's an array. (Other programming languages use the term array, but Python uses the term list instead.) You can put a lot of information into the one list, like other variables, strings, numbers, etc. It's just like how you can use multiple drawers in one filing cabinet. Each drawer is like a spot in that list. Annie mentioned this to Paul back in Level 3.

Lines 29-48 append our variables into different spots in our DECK list. For example, on Line 45, DECK.append(viralmuto) appends all the attributes (back from Line 21) into the one spot in the DECK list.

On Line 50, random.shuffle(DECK) shuffles the cards that are in the deck. This means that all the variables (the cards) that are in the DECK list are arranged in a random order. That way, when you start the game, you'll likely have a different set of cards that you play with, every time!

On Line 52, you'll see the code, class PlayScreen(GameState): The game's play screen is one of a few different game states, which are like modes or screens, that the player can move between. Other examples of game states are the welcome screen and the game over screen.

In Lines 54-72, we pass the self variable into our _init_() function, to set up (or initialize) the play screen, with all the graphics on it.

NEW CODE: On Line 60, you'll see the code comment, #TODO: Copy the code to add the Coded Attack button and the action_params attribute below. In the "Write Your Own Code" section below, we'll show you the code to add to Lines 61-62.

NEW CODE: Next, on Line 63, you'll find the code comment, #TODO: Change the instructions argument for the Info Box to use the CHALLENGE_INSTRUCTIONS instead. In the "Write Your Own Code" section below, we'll show you how to change Line 64 to add our new Coded Attack messages in the Info Box.

On Line 74, we define the start() function, with the code, def start(self, players): Lines 75-77 set up the self.players, self.player1, and self.player2 variables, so that we can use them later in the game.

On Line 79, we set the active player to be the attacker. This is based on the coin toss that the players see, before they pick their cards.

On Line 80, we set the defender, which is the player who is going to be attacked for that turn.

On Line 82, we set the card that gets displayed as the active card for Player 1. This is based on which card you picked to start with, on the "choose hand" screen. Or whenever you click a new card in your On Deck box, this is the function that displays that card as your new active card.

On Line 83, we set the card that gets displayed as the active card for Player 2.

On Lines 85-86, we display the players' healthbars. This is what visually shows how much life the players have left.

On Lines 88-89, we display the current cards in the players' On Deck boxes. Keep in mind that we added two more cards in the On Deck boxes for Challenge 1. So, each player starts off with four cards in their On Deck boxes (to switch to), instead of two.

On Line 91, self.dialog_box = DialogBox((200,300), (X_CENTER-100, 50)) displays the dialog box in the middle of the screen, between the two players' cards. This is the box where the players will see the instructions and information about the game they're playing.

On Lines 93-98, you define the get_event() function. It checks if the currently active player clicks the TechType Attack button or any of the On Deck cards.

On Lines 100-105, you define the button_action() function. This function flips the coin when the active player clicks the TechType Attack button.

On Lines 107-217, you define the update() function. This is the main function of the game. It updates the graphics on the screen, transitions between the players' turns, and it displays the messages that describe the results of each turn. This function is a lot longer for Challenge 2, because this is where we put the logic for the new CodedAttack button!

We're now going to break down the update() function to see all the different things that this function does!

Lines 108-115 update the players' healthbars, On Deck boxes, and displayed cards, if needed. For example, if Player 1 picked a new On Deck card, then when the update() function runs, it will show the new displayed card on the screen, and it will update what cards are listed in Player 1's On Deck box.

On Lines 117-120, we check if the coin is flipping during this turn. If so, then we animate the coin flipping.

On Lines 122-124, we then check if the turn is ready to move on to the action part (after the coin flip). If so, we set which card is attacking (the offense_card) and which card is defending (defense_card).

On Lines 126-128, we add the messages into the message variable, to update the players on what happened with the attack. Later, we display these messages in the Dialog box in the middle of the screen.

Lines 131-156 contain our logic for running the TechType Attack. On Line 131, the code if not self.coded_attack: makes sure you clicked the TechType Attack button and not the Coded Attack button. You previously wrote some of the code when you first made this game (following along with the book's instructions). For more details, see the Level 7: Help Glossary of Terms, #35-46, to follow through this process more. The Advice on Writing the Code section also gives more details.

Because we already covered the TechType Attack logic, the else: statement on Line 159 begins our logic for the new Coded Attack option.

NEW CODE: Next, you're going to write the code on Line 161. See the next section, "Write Your Own Code." Let's keep explaining the rest of the code.

On Line 164, you'll see the code, if self.side_up == 'Heads': This if statement checks if the coin lands on heads (for the Coded Attack). As the code comment on Line 165 explains, if the coin lands on heads, then there are four different paths that the code logic can take. Those are the four if statements on Lines 168, 175, 178, and 189. Let's take a look at each one!

On Line 168, you'll see the statement, if offense_card.coded_type == 'extra_hit': This statements checks if the particular character card uses the Coded Attack special ability known as 'extra hit'. This ability makes it so that the attacking card deals an extra one damage, for a total of two damage.

The TechType Attack can deal three damage, but it only deals two damage if your opponent is resistant to your TechType, and you only have a 50% chance of success. With this Coded Attack, you always deal one damage to your opponent, and you have a 50% chance of dealing two damage instead. So you can see why this attack can be valuable in certain situations.

NEW CODE: Next, you're going to write the code on Line 170, which makes the defense card take an extra point of damage. See the next section, "Write Your Own Code."

Line 171 displays the message to announce that the attacking card has dealt two damage points to the defending card.

NEW CODE: Next, you're going to write the code on Line 173, which switches to the active player. This function switches the players on the new turn, so the player who was on defense, is now on offense. See the next section, "Write Your Own Code."

On Lines 175-176, this if statement gives the active player an extra turn!

On Line 178, you'll see our third type of special ability, with the code, if offense_card.coded_type == 'gain_health':

Each character card is already assigned to one of the four Coded Attack special abilities (each card includes text that explains its Coded Attack special ability). For this 'gain_health' ability, your character gains one health back (if you flipped heads).

NEW CODE: Line 180 was started for you! You're going to add the second part of that line of code, to call the gain_health() method, to add 1 health back to your character. If your current card already has full health, you'll get a health point back on another card (if applicable). See the next section, "Write Your Own Code."

On Lines 181-182, the if statement checks if all the cards have full health. That means no cards can be healed. The message on Line 182 announces that to the players.

On Line 183, the else: statement runs to display a message (Line 184) that tells the players which character gained back 1 health point.

NEW CODE: Next, you're going to write the code on Line 186, which switches the active player, for the next turn. See the next section, "Write Your Own Code."

It's time for the last Coded Attack special ability! On Line 189, the if statement checks if the attacking player's Coded Attack special ability is 'opponent_tails'. This special ability forces your opponent to get tails on their next turn's coin flip (no matter what attack they choose). (If they're smart, they'd pick the Coded Attack, because at least then they'd still do one damage to their opponent.)

NEW CODE: Next, you're going to write the code on Line 191, which makes the opponent get tails in their next turn's coin flip. See the next section, "Write Your Own Code."

On Line 192, the code displays a message that lets the players know that the opponent will get tails on their next coin flip.

NEW CODE: Next, you're going to write the code on Line 194, which switches the active player, for the next turn. You should be great at writing that line of code by now! See the next section, "Write Your Own Code."

Line 196 is another else: statement. This one runs if the attacking player gets tails for their Coded Attack. The defending player still takes 1 damage point.

On Line 198, the code displays the message on the screen, explaining that the defending player took 1 damage point. It's time to switch players again!

NEW CODE: Next, you're going to write the code on Line 200, which switches the active player, for the next turn. See the next section, "Write Your Own Code."

On Lines 203-204, the code adds the last turn's message to the dialog box, based on the outcome of the turn.

On Lines 206-207, we refresh the hands of the players, for the new turn. For example, if one card lost, then the next card becomes the attacking card.

NEW CODE: Next, you're going to write the code on Line 210, which turns off the Coded Attack, to reset it for the next turn. See the next section, "Write Your Own Code."

Line 211 resets the action for the next turn. The turn is now over, and it sets up the next turn. This is a signal for the coin animation to reset, so that it's ready for the next turn. Line 212 increments 1 to the counter, so that the game counts the total number of turns and knows which turn we're on.

Lines 214-217 check if a player ran out of cards and if there's a winner. If so, then it sets the winner and ends the game.

Lines 219-224 define the flip_coin() function. It randomly determines which side is up, and then it returns that information (in the side variable).

Lines 226-235 complete the steps of switching the attacking player to the defending player and vice versa.

Lines 237-245 define the check_game_end() function. This function checks the status of both players. If one player survives, then we end the game (see Line 245).

Lines 247-265 define the draw() function. It updates all of the graphics on the screen, for each new round.

On Lines 267-274, states = {} declares a collection of states, or different screens that are needed for the game. This is also called a state machine, which provides the overall structure for the game logic. That includes any different modes or screens. It's a logical structure for your game code, where you don't need to put all your code into a loop to run the game.

Line 268 enters the TitleScreen() into the state machine, which is the screen you see when you start the game. Line 269 adds in GetNameScreen(), which is the screen where you enter in the names of the two players. Line 270 adds in the CoinFlipScreen(), which is where you flip a coin to see who goes first.

Line 271 adds in ChooseHandScreen(DECK), which is where you pick the card that you want to start with. Line 272 adds in PlayScreen(), which is the main game screen. And, finally, Line 273 adds in VictoryScreen(), which is the screen you go to when the game is over.

Line 276 is game = GameRunner(SCREEN, states, "Title"). It's the line that starts the game runner. Everything up to this line was all the setup, but this line starts running the code.

Write Your Own Code

On Line 4, we have our first #TODO code comment! You're going to add one more parameter to each character card's function. It's the name of the Coded Attack.

Lines 5-24 create all the cards, including the primary variables for the cards. Next, you'll add in the missing attributes... the names of the CodedAttacks.

On Line 5, Annie Conda's CodedAttack was already added in for you. It's called 'Super Squeeze'.

On Lines 6-24, you're going to add in the 8th attribute for each character card:

  1. Inside (to the left of) the end parenthesis, add a comma.
  2. After the comma, add a space.
  3. Type in the name of the character's CodedAttack. Be sure to use title casing (where the first letter of each word is capitalized) and put the title in single quotes.
  4. Make sure each line ends with the end parenthesis.

Here are the character card CodedAttack names to add in:

  1. On Line 6, for Bayo Wolf, add in 'Bitter Bite' as the eighth attribute.
  2. On Line 7, for Captain Javo, add in 'Punch Line' as the eighth attribute.
  3. On Line 8, for Cryptic Creeper, add in 'Viper Strike' as the eighth attribute.
  4. On Line 9, for Emily Airheart, add in 'Helmet Headbutt' as the eighth attribute.
  5. On Line 10, for Grafika Turtle, add in 'Shell Smash' as the eighth attribute.
  6. On Line 11, for Intelli-Scents, add in 'Cranium Caning' as the eighth attribute.
  7. On Line 12, for Java Lynn, add in 'Flying Kick' as the eighth attribute.
  8. On Line 13, for Jitter Bug, add in 'Dance Fight' as the eighth attribute.
  9. On Line 14, for Justin Timbersnake, add in 'Pop' as the eighth attribute.
  10. On Line 15, for Mrs. Scratcher, add in 'Purrfect Pounce' as the eighth attribute.
  11. On Line 16, for Paul Python, add in 'Mech Mash' as the eighth attribute.
  12. On Line 17, for Queen Cobra, add in 'Class Lecture' as the eighth attribute.
  13. On Line 18, for RAM and ROM, add in 'Twin Spin' as the eighth attribute.
  14. On Line 19, for SideWinder, add in 'Goth Glare' as the eighth attribute.
  15. On Line 20, for Syntax Turtle, add in 'Board Slam' as the eighth attribute.
  16. On Line 21, for ViralMuto, add in 'Cape Whip' as the eighth attribute.
  17. On Line 22, for Virobotica, add in 'Scepter Smash' as the eighth attribute.
  18. On Line 23, for the Virobots, add in 'Dog Pile' as the eighth attribute.
  19. On Line 24, for Woodchuck norrs, add in 'Roundhouse Kick' as the eighth attribute.

The next section where you need to add in missing code is at Lines 61-62.

Line 61 is similar to what you wrote on Line 58:

  • Make sure you're indented at the same level as Lines 59 and 60.
  • Type in the variable self.coded_attack_button onto Line 61.
  • Next, type in a space, an equal sign, and another space.
  • Then type in the Button() function.
  • This time, it won't be the "TechType Attack" text. Instead, type in "Coded Attack", as the text that appears on the button. (Be sure to use the comma.)
  • Next, still inside the function parentheses, type X_CENTER-85, 575, 170, 40, to determine the position/placement of the button.
  • Type coin_yellow, coin_dark_yellow, to make the color of the button and the button outline to be different shades of yellow. ("Coin yellow" is a color that means it's yellow, like how you'd expect a gold coin to appear.)
  • The last code you're going to add (still in the function's parentheses), is the same as Line 58. Type in parent = self to make the button independent (so it's not attached to a parent element or object on the screen). Make sure you end the line with the closing parenthesis.

On Line 62, this will be similar to Line 59, which is self.tech_attack_button.action_params = "tech". However, this time you are writing the code for a "Coded Attack". In this case, instead of ending the line with "tech", write "coded" at the end of Line 62.

This line changes the function of the button to the Coded Attack function (and features) for each card. In other words, this line sets up the button_action function on Line 100, to go into the Coded Attack (instead of the TechType Attack).

Now we're moving onto the next line of code that you'll need to update, Line 64.

On Line 64, you're given this line of code: self.instructions_box = InfoBox(INSTRUCTIONS, dialog_inst, BLACK, (200, 300), (X_CENTER, 200), 200). Next, you need to change it so that the argument for the Info Box uses the CHALLENGE_INSTRUCTIONS instead. This calls the new instructions into the info box, which explain the Coded Attack feature. Here's what you need to change:

  • Replace INSTRUCTIONS with CHALLENGE_INSTRUCTIONS instead.

Now, let's hop on down to Line 161! You're going to add a line of code that makes the defense card take 1 damage. (The Coded Attack always gives the opponent one point of damage.)

On Line 161, add the following code:

  • Type in defense_card to identify the variable. This points to the card that you're going to attack.
  • Next, type in a period . with no spaces. This signals you're going to be calling a function on the defense_card variable.
  • Then type the function take_damage() to cause the defense card to take damage.
  • Type the number 1 in the parentheses. The card will take one damage.

Next, you're going to add in Line 170. Find the code comment on Line 169, #TODO: Add the code to make the defense card take 1 damage.

Line 170 is the exact same text as Line 161. Type it in!

Just like before, the defense card takes 1 damage. We run Line 170 when the attacking card has the Coded Attack special ability to provide an extra hit!

Next is Line 173. You're going to add code that switches to the active player (for the next turn). Type in the code:

  • Type self as the variable that you're running the function on. The variable self represents the game screen. We're just telling the game screen to switch players.
  • Next, type in a period . with no spaces. This signals you're going to be calling a function on the variable.
  • Finally, type in the switch_active_player() function. You don't need to add any parameters in the parentheses.

Now move on to Line 186! You're going to do the same thing that you did on Line 173, where you switch to the active character. It's exact same code, so type it in!

Now, move down to Line 191. This time, you're adding code that sets the game's attribute to force tails to be True. Type in the code:

  • Type in the self.force_tails variable. This variable will make sure the next time the coin is flipped, it lands on tails.
  • Add a space, an equal sign, and then another space.
  • End the line with the boolean statement True to activate this state.

Next, you're going to write the code on Line 194, which switches the active player again (for the new turn).

  • Write the same code that you did on Line 186.

In the first part, the self variable represents the game screen. After the period, you added the function that switches to the active character, for the new turn. You can use this function, switch_active_player(), with no parameters needed (nothing inside the parentheses). Don't forget to add a . between the variable and the function. This one sets up the Coded Card attack that forces the opponent to get tails on the next coin flip.

On Line 200, you're going to add the code to switch the active player again.

  • Type in the same code that you added on Lines 173, 186, and 194.

This time, your code isn't indented as far. Make sure it's indented at the same level as Lines 197-199. This time it's after a Coded Attack gets tails. The defending player still takes one damage.

On Line 210, you are going to add the code to set the game's coded attack attribute to False.

  1. Start by typing the self variable.
  2. Add a . symbol (a period). (No space.)
  3. Type in the next variable (that's associated with the self variable) coded_attack after the period.
  4. Add a space, a = symbol (an equals sign), and another space.
  5. Type in False to turn off the Coded Attack mode.

Make sure you're indented at the same level as Lines 209 and 211. Refer back to Line 70 if you need more help putting it together (it's the same line of code).

The Final Code

I included a solution file for Level 7, Challenge 2. This file has all the code filled in, so if you run into any issues with your code (for example, if it doesn't compile/run, or if something isn't working correctly in your program), then you can take a look at the final code file to see what you did differently:

IMPORTANT: Please don't cheat yourself! Finish the game first!

Next Steps

More Level 7 Resources

In addition to these Level 7 challenges, we also have the Help page for the book, Online Articles, a Learning Quiz, an Unplugged Activity, and a Rewards article:

  • Level 7: Help - This page helps you complete the instructions in the book, in case you get stuck.

  • Level 7: Online Articles - I made you a list of different web pages I found, which will help you learn more about the lessons we covered in Level 7.

  • Level 7: Learning Quiz - I wrote some questions in case you want to quiz yourself about what you learned. Or you can teach others and quiz them!

  • Level 7: Unplugged Activity - In this game, we recreate the basic aspects of the IncrediCards game, but in real life!

  • Level 7: Rewards - If you completed the IncrediCards project that we talked about in our text messages, then I set up this page to act as a reward. You can see some illustrations of how the art of the card game was made!

⚠️ **GitHub.com Fallback** ⚠️