Shape Shifter

Objective: Shape Shifter

Let's begin by reviewing our objective.

Micro-Quest Objective: Create a Python script using the Turtle library that defines a function named draw_polygon(num_sides, side_length, pen_color). This function should take three parameters: num_sides (the number of sides for the polygon), side_length (the length of each side), and pen_color (the color of the pen). The function should draw the specified polygon. The script should then call this function to draw a blue triangle (3 sides) with a side length of 100 pixels, and a separate orange pentagon (5 sides) with a side length of 70 pixels.

Check Spec: See the Failing Tests

Next, we'll run pytest to see the failing tests. This confirms the engineering specification we need to meet.

Run the tests now.

Test Results:

  • test_draw_polygon_function_logic
  • test_main_drawing_logic_sequence
  • test_draw_polygon_with_invalid_sides

As expected, all tests related to the new function and its usage are failing because the implementation is missing.

Implement: `main.py` (draw_polygon function)

Now, let's build the solution by following the TODO comments in the skeleton code.

We'll start with the draw_polygon function in main.py.

Step by step checklist:

  1. Implement the check to see if the number of sides is less than 3. If it is, exit the function immediately.
  2. If the number of sides is valid (3 or more), create a new turtle object.
  3. Set the pen color of the new turtle using the provided color argument.
  4. Calculate the exterior angle needed for turning based on the number of sides.
  5. Create a loop that runs for the number of sides.
  6. Inside the loop, move the turtle forward by the side length.
  7. Inside the loop, turn the turtle left by the calculated angle.

The following documentation sections are going to be helpful:

  • Functions with Parameters
  • Conditional Execution (if)
  • Comparison Operators
  • Early Exit with return (Guard Clauses)
  • Turtle Graphics Basics (Relevant Commands)
  • Example: Drawing Polygons with Turtle Functions

Implement: `main.py` (main_drawing_logic function)

Now let's implement the main_drawing_logic function in main.py to use our new draw_polygon function.

Step by step checklist:

  1. Call the draw_polygon function to draw a blue triangle with a side length of 100.
  2. Call the draw_polygon function again to draw an orange pentagon with a side length of 70.

The following documentation sections are going to be helpful:

  • Basic Definition and Call
  • Functions with Parameters
  • Example: Drawing Polygons with Turtle Functions

Validate: Run the Tests Again

With the code in place, let's run the tests again to validate our work.

Run the tests now.

Test Results:

  • test_draw_polygon_function_logic
  • test_main_drawing_logic_sequence
  • test_draw_polygon_with_invalid_sides All tests passed!

Great job! The tests confirm that your draw_polygon function works correctly for valid and invalid inputs, and that your main_drawing_logic function calls it correctly to draw the specified shapes.

Debrief: Prepare for Code Review

You've successfully implemented the draw_polygon function and used it to draw the required shapes!

Now, let's prepare for the final step: the code review with your mentor.

Review your code, focusing on:

  • Readability and clarity.
  • How the draw_polygon function generalizes the drawing process.
  • How the guard clause handles invalid input.
  • How main_drawing_logic orchestrates the drawing by calling draw_polygon.

Be ready to explain your implementation choices and how they meet the micro-quest's objective and the test specifications.

Documentation

Python Fundamentals: Building Blocks Documentation

This document provides a quick reference for core Python concepts related to functions, conditional logic, and output formatting.

1. Functions

Functions are blocks of reusable code that perform a specific task. They help organize code, make it easier to read, and avoid repetition.

Basic Definition and Call

You define a function using the def keyword, followed by the function's name, parentheses (), and a colon :. The code inside the function must be indented. To run the code inside a function, you "call" it by using its name followed by parentheses.

# Defining a simple function
def say_greeting():
    print("Hello!")
    print("Nice to meet you.")

# Calling the function (running its code)
say_greeting()
say_greeting()

Output:

Hello!
Nice to meet you.
Hello!
Nice to meet you.

Image or GIF showing the concept of calling a function multiple times to repeat a block of code.

Functions with Parameters

Parameters are variables listed inside the parentheses in the function definition. They act as placeholders for values (arguments) that you provide when you call the function. This allows functions to be flexible and perform similar tasks with different data.

def greet_person(name, occasion):
    print(f"Hello, {name}! Happy {occasion}!")

# Calling with arguments
greet_person("Alex", "Birthday")
greet_person("Jordan", "Graduation")

Output:

Hello, Alex! Happy Birthday!
Hello, Jordan! Happy Graduation!

Diagram illustrating parameters as inputs to a function.

Passing Objects as Parameters (e.g., Turtle)

You can pass any type of data as an argument, including objects like a Turtle graphics object. This allows functions to operate on specific objects that are created outside the function.

import turtle

# Create a turtle
my_artist = turtle.Turtle()

# Pass the turtle object to the function
draw_segment(my_artist, 100)
draw_segment(my_artist, 50)

2. Conditional Execution (if)

Conditional statements allow your program to make decisions and execute different code blocks based on whether a condition is true or false.

Basic if Statement

The syntax involves the if keyword, a condition, and a colon. The code to execute if the condition is true is indented.

def check_score(score):
    if score > 90:
        print("Excellent!")
    # No 'else' part here, so nothing happens if score is 90 or less

check_score(95)  # Output: Excellent!
check_score(88)  # No output

Flowchart of a basic if statement.

Comparison Operators

These are used to form conditions in if statements:

OperatorMeaningExample
==Equal toa == b
!=Not equal toa != b
<Less thana < b
>Greater thana > b
<=Less than or equal toa <= b
>=Greater than or equal toa >= b

Early Exit with return (Guard Clauses)

A return statement immediately exits the current function. This is useful for "guard clauses" that check input at the beginning of a function and stop execution if the input is invalid.

def process_positive_number(number):
    if number <= 0:
        print("Error: Input must be positive.")
        return  # Exit the function early

    # This code only runs if number is positive
    print(f"Processing {number}...")
    # ... rest of the function logic ...

process_positive_number(-5)
process_positive_number(10)

Output:

Error: Input must be positive.
Processing 10...

3. Output Formatting (print())

The print() function is used to display output to the console. It has several features to control how output is formatted.

Printing Multiple Items

You can pass multiple items to print(), separated by commas. By default, print() will insert a space between each item.

item_name = "Widgets"
count = 12
print("Inventory:", count, item_name)

Output:

Inventory: 12 Widgets

F-Strings (Formatted String Literals)

F-strings provide a concise way to embed expressions and variables inside string literals. Start the string with an f or F before the opening quote. You place variables or expressions inside curly braces {} within the string.

product = "Laptop"
price = 999.99
discount = 0.15
final_price = price * (1 - discount)

print(f"Product: {product}")
print(f"Original Price: ${price}")
# Format final_price to two decimal places
print(f"Discounted Price: ${final_price:.2f}")

Output:

Product: Laptop
Original Price: $999.99
Discounted Price: $849.99

Diagram showing how an f-string substitutes variable values into placeholders.

Controlling Separators and Endings with sep and end

The print() function accepts optional sep and end parameters.

  • sep: Specifies the string to insert between items, replacing the default space.
  • end: Specifies the string to append at the end of the output, replacing the default newline character (\n).
# Using sep
print("File", "Edit", "View", sep=" | ")

# Using end to stay on the same line
print("Loading...", end="")
print(" Complete!")

Output:

File | Edit | View
Loading... Complete!

Simple animation showing how sep changes the space between items and end changes what comes after the printed line.

4. Turtle Graphics Basics (Relevant Commands)

The turtle module provides a way to create graphics using a "turtle" that draws on a screen.

import turtle

# Setup (often done outside drawing functions for testability)
# screen = turtle.Screen()
# my_turtle = turtle.Turtle()

# Basic Movement
# my_turtle.forward(100) # Move forward 100 units
# my_turtle.backward(50) # Move backward 50 units
# my_turtle.left(90)     # Turn left 90 degrees
# my_turtle.right(45)    # Turn right 45 degrees
# my_turtle.goto(x, y)   # Move to specific coordinates

# Pen Control
# my_turtle.penup()    # Lift the pen (stop drawing when moving)
# my_turtle.pendown()  # Put the pen down (start drawing when moving)
# my_turtle.pencolor("red") # Set the pen color by name or hex code
# my_turtle.pensize(3) # Set the thickness of the line

# Keeping the window open (usually in the __main__ block)
# turtle.done() # or screen.mainloop()

[ASSET: Example: Drawing Polygons with Turtle Functions] Functions are powerful for creating reusable drawing logic with Turtle.

import turtle

def draw_polygon(t_obj, num_sides, side_length, pen_color):
    # Guard clause for valid polygon
    if num_sides < 3:
        print("A polygon needs at least 3 sides.")
        return

    t_obj.pencolor(pen_color)
    angle = 360.0 / num_sides  # Calculate exterior angle

    for _ in range(num_sides):
        t_obj.forward(side_length)
        t_obj.left(angle)

# Setup
# screen = turtle.Screen()
# my_turtle = turtle.Turtle()
# my_turtle.speed(1) # Slower for visibility

# Draw a blue triangle
# draw_polygon(my_turtle, 3, 100, "blue")

# Move turtle to a new position for the next shape
# my_turtle.penup()
# my_turtle.goto(150, 50)
# my_turtle.pendown()

# Draw an orange pentagon
# draw_polygon(my_turtle, 5, 70, "orange")

# screen.mainloop() # Keep the window open

An animation showing the draw_polygon function being called twice, first drawing a blue triangle, then the turtle moving, and then drawing an orange pentagon.