PY-1.2-BP4-MQ03

What We Will Learn: Dictionaries

We will learn about dictionaries in Python. Dictionaries are like special lists that store information using keys and values. Think of it like a real dictionary where each word (key) has a meaning (value).

We will learn how to:

  • Make an empty dictionary.
  • Show what's inside a dictionary.
  • Add new things to a dictionary.
  • Find things in a dictionary.
  • Take things out of a dictionary.

Check Your Work

First, let's check if the program works right now. We do this by running tests.

Run this command in your terminal:

pytest module-1.2/blueprint-PY-1.2-BP4/quest-03

What you should see:

  • test_create_empty_dictionary
  • test_print_dictionary
  • test_add_item_to_dictionary
  • test_find_item_in_dictionary
  • test_remove_item_from_dictionary
  • test_get_dc_heroes
  • test_add_and_return_item_to_dictionary

These tests are failing because the code is not finished yet.

Write Your Code

Open main.py and fill in the missing parts for each function. Then, complete the main() function to demonstrate how these dictionary functions work together.

Here are some fun examples of how to work with dictionaries:

1. Make an empty dictionary:

# Imagine you're creating a menu for a new ice cream shop!
ice_cream_menu = {}
print(ice_cream_menu)

2. Add new things to a dictionary:

# Let's add some flavors and their prices to our ice cream menu.
ice_cream_menu = {}
ice_cream_menu["Vanilla"] = 3.50
ice_cream_menu["Chocolate"] = 4.00
print(ice_cream_menu)

# Dictionaries can even hold lists! Like a list of heroes for each comic universe.
comic_universes = {}
comic_universes["Marvel"] = ["Iron Man", "Captain America", "Thor"]
comic_universes["DC"] = ["Batman", "Superman", "Wonder Woman"]
print(comic_universes)

3. Show what's inside a dictionary:

# Let's see all the items on our ice cream menu.
ice_cream_menu = {"Strawberry": 3.75, "Mint Chip": 4.25}
print(ice_cream_menu)

4. Find things in a dictionary:

# What's the price of Chocolate ice cream?
ice_cream_menu = {"Vanilla": 3.50, "Chocolate": 4.00}
chocolate_price = ice_cream_menu["Chocolate"]
print(f"Chocolate ice cream costs ${chocolate_price}")

# Is "Spider-Man" in the Marvel universe?
comic_universes = {"Marvel": ["Iron Man", "Captain America", "Thor"]}
if "Spider-Man" in comic_universes["Marvel"]:
    print("Spider-Man is a Marvel hero!")
else:
    print("Spider-Man is not listed here.")

5. Take things out of a dictionary:

# Oh no, we ran out of Vanilla! Let's remove it from the menu.
ice_cream_menu = {"Vanilla": 3.50, "Chocolate": 4.00, "Strawberry": 3.75}
del ice_cream_menu["Vanilla"]
print(ice_cream_menu)

6. Get heroes from a specific universe:

# We have a dictionary of comic universes. How do we get just the DC heroes?
all_universes = {
    "Marvel": ["Iron Man", "Captain America"],
    "DC": ["Batman", "Superman"]
}
dc_heroes_list = all_universes["DC"]
print(dc_heroes_list)

7. Add an item and get the updated dictionary:

# Let's add a new flavor to our menu and see the whole updated menu.
my_current_menu = {"Chocolate": 4.00}
my_current_menu["Cookie Dough"] = 4.50
print(my_current_menu)

Check Your Work Again

Now that you've written your code, let's check it again.

Run this command in your terminal:

pytest module-1.2/blueprint-PY-1.2-BP4/quest-03

What you should see:

  • test_create_empty_dictionary
  • test_print_dictionary
  • test_add_item_to_dictionary
  • test_find_item_in_dictionary
  • test_remove_item_from_dictionary
  • test_get_dc_heroes
  • test_add_and_return_item_to_dictionary

Think About Your Code

You have now learned how to work with dictionaries!

Think about these questions:

  1. What is a dictionary used for?
  2. How is a dictionary different from a list?
  3. How do you add a new item to a dictionary?
  4. How do you get an item from a dictionary?
  5. How do you remove an item from a dictionary?

Documentation

Blueprint PY-1.2-BP4 Documentation

This document provides a reference for key concepts and functions used in the micro-quests for Blueprint PY-1.2-BP4.


Pygame Basics

Initialization and Window

Before using Pygame functions, the library must be initialized. A display window (screen) is then created.

import pygame

# Initialize Pygame
pygame.init()

# Screen dimensions
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600

# Create the screen surface
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))

# Set the window title
pygame.display.set_caption("My Pygame Window")

Updating the Display

After drawing, you must update the display to make your changes visible. It's common to fill the background first to clear the previous frame.

# Inside the main game loop, after drawing commands:
screen.fill((255, 255, 255)) # Fill with white
# ... drawing commands ...
pygame.display.flip() # Make the drawn content visible

Drawing Shapes (pygame.draw)

The pygame.draw module provides functions for drawing simple shapes onto a Surface (like your screen). The first argument is always the surface to draw on.

Examples of Pygame drawing primitives (rect, circle, line, polygon)

  • Rectangle: pygame.draw.rect(surface, color, (x, y, width, height)) or pygame.draw.rect(surface, color, rect_object)
    • color is an RGB tuple (e.g., (255, 0, 0) for red).
    • (x, y, width, height) is a tuple defining the top-left corner, width, and height.
  • Circle: pygame.draw.circle(surface, color, (center_x, center_y), radius)
    • (center_x, center_y) is a tuple for the circle's center point.
    • radius is the circle's radius in pixels.
  • Lines: pygame.draw.lines(surface, color, closed, list_of_points, thickness)
    • closed is True or False. If True, it connects the last point to the first.
    • list_of_points is a list of coordinate tuples, e.g., [(10, 20), (50, 60), (80, 30)].
    • thickness is the line width in pixels.
  • Polygon: pygame.draw.polygon(surface, color, list_of_points)
    • list_of_points is a list of coordinate tuples defining the vertices of the polygon. The points are automatically connected, and the shape is filled.
# Example drawing calls:
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)

# Draw a red rectangle
pygame.draw.rect(screen, RED, (100, 100, 50, 80))

# Draw a green circle
pygame.draw.circle(screen, GREEN, (400, 300), 25)

# Draw blue lines
points = [(50, 50), (150, 50), (100, 150)]
pygame.draw.lines(screen, BLUE, False, points, 2)

The pygame.Rect Object

The pygame.Rect object is a fundamental Pygame class for storing and manipulating rectangular areas. It holds integer coordinates for the top-left corner, width, and height. It also provides convenient attributes for other corners, the center, and dimensions, which are calculated automatically.

Pygame Rect attributes

A Rect object can be created using pygame.Rect(left, top, width, height).

# Example Rect creation and attributes:
my_rect = pygame.Rect(100, 150, 200, 80)

print(f"x: {my_rect.x}")
print(f"y: {my_rect.y}")
print(f"width: {my_rect.width}")
print(f"height: {my_rect.height}")
print(f"center: {my_rect.center}")
print(f"topleft: {my_rect.topleft}")
print(f"bottomright: {my_rect.bottomright}")

# You can also draw a Rect object directly
# pygame.draw.rect(screen, BLUE, my_rect)

Core Programming Patterns

The Game Loop (Input, Update, Render)

Most real-time applications, including games, run on a continuous loop that processes three main phases:

  1. Handle Input: Check for user actions (key presses, mouse clicks, window closing).
  2. Update State: Change game variables (like position, score, health) based on input or game logic.
  3. Render: Draw the current state of the game to the screen.

Input -> Update -> Render cycle

# Basic structure inside the main game loop:
running = True
while running:
    # 1. Handle Input
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        # Handle other events (key presses, mouse clicks)

    # 2. Update State
    # Check key states for continuous movement
    # Update player position, check collisions, update scores, etc.

    # 3. Render
    screen.fill(BACKGROUND_COLOR) # Clear previous frame
    # Draw game objects (player, enemies, score, etc.)
    pygame.display.flip() # Show the newly drawn frame

Managing State with Variables and Lists

Game state refers to all the variables that describe the current condition of the game (e.g., player position, score, whether an object is active, a list of items).

Lists for Storing State

Python lists are useful for keeping track of a sequence of game states, such as the history of positions for a drawing trail.

# Initialize an empty list
trail_points = []

# Add a position to the list
current_position = (100, 100)
trail_points.append(current_position)

# Add another position
new_position = (110, 105)
trail_points.append(new_position)

print(trail_points) # Output: [(100, 100), (110, 105)]

# You can then use this list with drawing functions like pygame.draw.lines().
# if len(trail_points) > 1:
#     pygame.draw.lines(screen, BLUE, False, trail_points, 2)

# To clear a list:
# trail_points.clear()
# or
# trail_points = []

Boolean Flags

A boolean variable (True or False) can act as a "flag" to control program behavior. Toggling a boolean means flipping its value (True becomes False, False becomes True).

Boolean Flag Example

# Global flag
is_active = True

def toggle_active():
    global is_active # Use global to modify the variable outside the function
    is_active = not is_active # Toggles the value
    print(f"Is active: {is_active}")

# Example usage:
# toggle_active() # is_active becomes False
# toggle_active() # is_active becomes True

You can use an if statement to make code run only when a flag is True.

# Inside a function or loop:
if is_active:
    # Code here only runs if is_active is True
    print("Action performed because active.")
else:
    # Code here runs if is_active is False
    print("Action skipped because inactive.")

Cycling through Lists

You can use an index variable and the modulo operator (%) to cycle through items in a list, looping back to the beginning when you reach the end.

items = ['apple', 'banana', 'cherry']
current_index = 0

def get_next_item():
    global current_index
    # Calculate the next index, wrapping around using modulo
    current_index = (current_index + 1) % len(items)
    # Return the item at the new index
    return items[current_index]

# Example usage:
# print(get_next_item()) # Prints 'banana', index becomes 1
# print(get_next_item()) # Prints 'cherry', index becomes 2
# print(get_next_item()) # Prints 'apple', index becomes 0 (wraps around)

Pygame Input Handling

Event-Based Input (pygame.event.get())

The pygame.event.get() function retrieves events from Pygame's event queue. This is typically done once per frame inside the main game loop. You then iterate through the list of events to check their type.

# Inside the main game loop:
for event in pygame.event.get():
    # Check event.type here
    pass

Checking for QUIT

The pygame.QUIT event is generated when the user clicks the close button on the window. Checking for this event is essential for allowing the user to exit the application gracefully.

# Inside the event loop:
if event.type == pygame.QUIT:
    running = False # Set a flag to exit the main game loop

Handling KEYDOWN

The pygame.KEYDOWN event is generated once when a key is pressed down. The event.key attribute contains the constant representing the specific key that was pressed (e.g., pygame.K_LEFT, pygame.K_SPACE, pygame.K_c).

# Inside the event loop:
if event.type == pygame.KEYDOWN:
    if event.key == pygame.K_LEFT:
        # Code to handle left arrow key press
        pass
    elif event.key == pygame.K_SPACE:
        # Code to handle spacebar press
        pass
    # Add more elif checks for other keys

State-Based Input (pygame.key.get_pressed())

The pygame.key.get_pressed() function returns a sequence (like a list or tuple) containing the state of every keyboard key. Each item in the sequence is True if the corresponding key is currently held down, and False otherwise. This is useful for continuous actions like movement, as you can check the key's state every frame.

# Inside the main game loop, but OUTSIDE the event loop:
keys = pygame.key.get_pressed()

if keys[pygame.K_LEFT]:
    # Code to move left continuously while the key is held
    pass
if keys[pygame.K_RIGHT]:
    # Code to move right continuously while the key is held
    pass
# Use separate 'if' statements for each direction to allow diagonal movement

Turtle Graphics Basics

Initialization and Screen

You need a Screen object to represent the drawing window and a Turtle object (often called a "stylus" or "pen") to do the drawing.

Turtle Core Structure

import turtle

# Get the screen object
screen = turtle.Screen()
screen.title("My Turtle Window")

# Create a turtle object
stylus = turtle.Turtle()

Turtle Control Commands

The turtle object has methods to control its movement, drawing state, and appearance.

Turtle Control commands list

  • Movement:
    • stylus.forward(distance): Move forward by distance pixels.
    • stylus.backward(distance): Move backward.
    • stylus.left(degrees): Turn left by degrees.
    • stylus.right(degrees): Turn right by degrees.\
    • stylus.goto(x, y): Move directly to the specified coordinates.
  • Drawing:
    • stylus.penup(): Lift the pen up (stop drawing when moving).
    • stylus.pendown(): Put the pen down (start drawing when moving).
    • stylus.pencolor("color_name"): Set the color of the line drawn. Can use color names (like "red", "blue") or hex codes.
    • stylus.shape("shape_name"): Change the appearance of the turtle cursor (e.g., "arrow", "turtle", "circle", "square", "triangle", "classic").
  • Resetting:
    • stylus.clear(): Erase the turtle's drawings from the screen, but the turtle's position and state remain unchanged.
    • stylus.reset(): Erase drawings and reset the turtle to its initial state (center, facing right, pen down).
# Example Turtle commands:
stylus.pencolor("green")
stylus.forward(100)
stylus.left(90)
stylus.penup()
stylus.forward(50)
stylus.pendown()
stylus.pencolor("purple")
stylus.circle(30)
stylus.clear() # Erase everything drawn so far

Event Handling (Binding Functions)

Turtle Graphics uses a simple event binding system. You define functions (handlers) and tell the screen which event should trigger which function.

Turtle Core Structure diagram

# Define a function to be called on an event
def handle_click(x, y):
    print(f"Clicked at ({x}, {y})")

# Tell the screen to start listening for events
screen.listen()

# Bind the left mouse click to the handler function
screen.onclick(handle_click)

# Bind a key press to a handler function
# The second argument is the key name (e.g., "space", "Up", "Down", "Left", "Right", "c")
def handle_space_press():
    print("Space was pressed!")

screen.onkey(handle_space_press, "space")

# Bind mouse drag to a handler function
# The handler receives the x, y coordinates where the mouse is dragged
def handle_drag(x, y):
    print(f"Dragging at ({x}, {y})")
    # stylus.goto(x, y) # Example: move the turtle to the drag position

turtle.ondrag(handle_drag)