Notebook 3: Python Basics via Pseudocode & Flowcharts

COMP 1150 — Computer Science Concepts

Author

Brendan Shea, PhD

Published

June 13, 2026

Open In Colab Download .ipynb · View on GitHub

📺 Lecture video: (link coming soon)

Learning Outcomes

By the end of this notebook, you will be able to:

  • Create variables and recognize the four core data types (int, float, str, bool)
  • Build expressions with arithmetic, comparison, and boolean operators
  • Format output with f-strings, escape characters, and string methods
  • Convert between types correctly and read input from a person
  • Write clear pseudocode and read a flowchart
  • Follow the workflow problem → pseudocode → flowchart → Python on a real problem
  • Trace a short program by hand, and use AI to pressure-test a plan you wrote yourself

Maps to course Learning Outcomes 5 (pseudocode & flowcharts) and 6 (writing Python to implement algorithms).

Welcome to the Emporium

Tucked down a foggy lane, behind a window full of dusty curiosities, stands Mirabel’s Emporium of Practical Enchantments. Inside you will find bottled luck, phoenix feathers sold by the quill, jars of moonpetal, and a cat who may or may not be furniture. The shop runs on two things: stock on the shelves and coin in the till — silver crowns and copper bits, where 100 bits make 1 crown.

Mirabel Quill, the proprietor, has a problem. Her apprentice, Fen, keeps the books by hand, by candlelight, late into the night — and Fen, being human, makes mistakes. A miscounted shelf here, a fumbled bit of change there. Mirabel doesn’t want the sums done cleverly. She wants them done exactly, repeatably, the same way every time.

That is what this notebook is about. In Notebooks 1 and 2 you mostly read code. Here you start writing it — and not by guessing. You’ll learn the method this whole course runs on: problem → pseudocode → flowchart → Python. By the end you’ll take a plain-English task from Mirabel and turn it into working code, step by deliberate step — the way the shop’s careful ledger-keeper, Wren Hollow, does it. Wren never touches the ledger until she has written down exactly what she means to do.

A Word You’ll Use All Year: Algorithm

When Mirabel asks for arithmetic done “exactly, repeatably, the same way every time,” she is — without using the word — asking for an algorithm. It is the single most important word in computer science, so let’s make it precise.

An algorithm is a finite list of clear, unambiguous steps that takes some input, does a definite amount of work, and produces an output. You already know dozens of them. A recipe is an algorithm. The long-division procedure you learned as a child is an algorithm. The steps Fen follows to count out change for a customer is an algorithm. A computer is simply a very fast, very literal machine for carrying algorithms out — it never improvises, and it never gets bored.

Computer scientists ask four things of a genuine algorithm:

  • Definite — every step is precise. No “season to taste,” no “do whatever seems best.”
  • Finite — it is a fixed list of steps, not an endless one.
  • Terminating — it eventually stops and hands you an answer.
  • Input and output — it takes something in and gives something back.

Keep these four in your pocket. When something you write loops forever or gives a different answer each run, one of these four has slipped.

Two more ideas are worth holding onto. First, one problem can have many algorithms. There are dozens of ways to sort a shelf of labelled jars — some quick, some slow — and choosing well is much of what computer science is about (you’ll meet this head-on in Notebook 7). Second, an algorithm is an idea, separate from any one programming language. Wren’s method for splitting a cache of crystals among apprentices could be carried out in Python, in some other language, or by Fen with a pencil and a patient evening.

That separation is the whole reason this notebook teaches a workflow instead of just Python syntax. You’ll pin down the algorithm first — in plain words and a picture — and only then translate it into code.

💭 Think About It — Algorithms You Already Follow

You just met the word algorithm: a precise sequence of steps that anyone — or any machine — can follow to get a result.

  • Describe an everyday routine (a recipe, getting ready in the morning, giving someone directions) as an algorithm. Where is it precise, and where does it secretly rely on human judgment?
  • A good algorithm leaves no step to guesswork. Why is “leave nothing to interpretation” so much harder than it sounds when the follower is a machine instead of a person?
  • “Social media algorithms” are in the news constantly. Based on what the word actually means, what do you think people are really worried about when they complain about them?

There are no single right answers here — share a sentence or two on each.

The Roadmap

Part What you’ll pick up
Variables & types How a program stores a value, and what kind of value it is
Operators & expressions Arithmetic, comparison, and combining true/false conditions
Input & output How a program talks to a person — and the #1 beginner bug
Printing well Escape characters, f-string formatting, string methods
The workflow Problem → pseudocode → flowchart → Python, start to finish
Building with AI Plan by hand, let the AI critique your plan, then build

One scope note. Every program in this notebook runs straight down, top to bottom — no choices, no repetition. Decisions (if) and repetition (loops) are Notebook 4. We’ll point at that door near the end, but we won’t walk through it yet.

How to Use This Notebook

This is a tinkering notebook, not a reading one. Most code cells open with a block like this:

# ⬇️ CHANGE THESE, THEN RE-RUN
crowns = 50

Change the numbers, press Shift + Enter, and watch what happens. Poking at a working example is how the ideas actually stick — far more than reading about them. Each new section also ends with a small ✏️ Your Turn cell where you write a little code of your own. Don’t skip those; they’re the point.

Variables: Named Boxes

Before a program can do anything with a value, it needs somewhere to keep it. That somewhere is a variable — a labelled box that holds one value at a time. You put a value into the box with the assignment operator, the single =.

Here is the shape of every assignment you’ll ever write:

box_name = value

The trick is how to read that =. Read it as “gets,” not “equals.” So crowns = 50 means “the box named crowns gets the value 50.” It’s an instruction to store something, not a claim that two things are equal. Mirabel likes this arrangement: a named box can be checked, reused, and corrected in exactly one place — unlike Fen’s totals, scattered in the margins of three different pages.

# ⬇️ CHANGE THESE, THEN RE-RUN
crowns = 50      # coins in the till
spent  = 12      # a customer's purchase
# ----------------------------------

crowns = crowns - spent      # the right side runs first, then it's stored back

print(crowns)

There is one line above that trips up almost every beginner: crowns = crowns - spent. How can a box equal itself minus something? It can’t — and that’s the clue that = is not “equals.” The right side always runs first. Python computes 50 - 12 = 38, and then drops that result into crowns, replacing whatever was there before. A variable always holds whatever was assigned most recently; the old value is simply gone.

Try it: set spent = 70 and re-run. The till goes negative, and Python doesn’t bat an eye — to it, numbers are just numbers. (Mirabel would bat an eye.)

Reading the picture: the yellow box is the expression Python works out first; the arrow is the act of storing; the green box is crowns after the update. Assignment always flows right → left.

✏️ Your Turn — Update the Till

A customer buys a phoenix feather. Start with the till and the price already in boxes, then update the till to reflect the sale, and print the new total.

# ⬇️ CHANGE THESE, THEN RE-RUN
till  = 200      # crowns currently in the till
price = 35       # price of one phoenix feather
# ----------------------------------

# TODO: subtract the price from the till, store it back into `till`,
#       then print the new total.

Data Types: What Kind of Value?

Every value a program holds has a type — a category that decides what you’re allowed to do with it. You can add two numbers, but “adding” two names means something different, and dividing a word by three means nothing at all. The type is what tells Python which rules apply.

Auditor Crane, who visits from the Guild of Weights and Measures with a magnifying glass and no sense of humour, insists that you always know which type you are holding. The four you need right now:

Type Full name Example Used for
int integer 42, -7 whole numbers — counts, crowns, bits
float floating-point 3.14, 2.0 numbers with a decimal point
str string "Mirabel" text, always in quotes
bool boolean True, False yes/no answers

When you want to know what you’re holding, ask Python directly with the type() function:

type(some_value)
print(type(42))           # a whole number
print(type(3.14))         # has a decimal point
print(type("Mirabel"))    # in quotes -> text
print(type(7 > 3))        # a comparison -> True / False
print(type("42"))         # quotes! looks like a number, but it's text

# ⬇️ CHANGE THIS and re-run to test your own guess:
mystery = 9.0
print("mystery is:", type(mystery))

Notice the last two lines especially. 42 is an int, but "42" — with quotes — is a str. They look almost identical on the page and behave completely differently, and confusing them is the most common beginner bug there is. The rule to carry all year: quotes win. If it’s in quotes, it’s text, no matter how numeric it looks. And one small surprise worth memorizing now: 2 is an int, but 2.0 is a float. The lone decimal point is the whole difference.

✏️ Your Turn — Name That Type

Store one value of each of the four types in the boxes below — your own choices — then print the type of each. Before you run it, predict each answer out loud; then check yourself against Python.

# ⬇️ FILL IN a value of each type, then run.
whole_number   =      # an int
decimal_number =      # a float
some_text      =      # a str (remember the quotes!)
yes_or_no      =      # a bool: True or False
# ----------------------------------

# TODO: print the type() of each of the four boxes above.

Operators & Expressions

An expression is any piece of code that computes a value. crowns - spent is an expression; so is 7 > 3. The values an expression works on are its operands, and the symbols that act on them — +, -, and friends — are its operators. A whole line of code like total = crowns - spent is a statement: a complete instruction. (Tuck those four words away — expression, operand, operator, statement — they come back all year.)

The everyday arithmetic operators are the ones you’d expect: + - * /. But three more deserve special attention, because they show up constantly and surprise people:

Operator Meaning Example Result
/ true division — always gives a float 7 / 2 3.5
// floor division — the whole part only 7 // 2 3
% modulo — the remainder left over 7 % 2 1
** exponent — raise to a power 2 ** 3 8

The pair // and % are a team. Together they answer one very practical question: “how many whole groups fit, and how much is left over?” That question is everywhere — and in our shop, it’s exactly how you turn a heap of copper bits into crowns-and-bits.

# ⬇️ CHANGE THIS, THEN RE-RUN
bits = 347        # a pile of loose copper bits (100 bits = 1 crown)
# ----------------------------------

print(bits / 100)     # true division -> 3.47  (a float)
print(bits // 100)    # floor division -> 3    (whole crowns)
print(bits % 100)     # modulo -> 47           (leftover bits)
print(bits ** 2)      # exponent -> 120409

Look at the middle two lines together: 347 // 100 is 3 and 347 % 100 is 47. So 347 loose bits is 3 crowns and 47 bits. That’s the entire idea behind // and %, and it returns as the worked example later in this notebook — so make sure it clicks now. (Note too that / gave 3.47, a float, even though we wanted whole crowns. / always hands back a float, even when the division comes out even: 10 / 5 is 5.0, not 5.)

A Few Built-in Math Tools

Operators aren’t the only way to compute. Python ships with small functions that do common jobs — you call one by writing its name and putting its inputs in parentheses, like abs(-5). A clerk’s-toolkit worth knowing:

Function What it does Example Result
abs(x) distance from zero (drops the minus sign) abs(-38) 38
round(x, n) round to n decimal places round(19.547, 2) 19.55
min(...) the smallest value min(8, 40, 12) 8
max(...) the largest value max(8, 40, 12) 40
divmod(a, b) the // and % answers together, as a pair divmod(347, 100) (3, 47)

That last one, divmod, is just the crowns-and-bits split in a single call — handy once you trust what // and % do.

✏️ Your Turn — Crowns and Bits

A customer pays for a jar of moonpetal with a fistful of loose bits. Given the number of bits, work out how many whole crowns that is and how many bits are left over, and print both.

# ⬇️ CHANGE THIS, THEN RE-RUN
paid_bits = 525
# ----------------------------------

# TODO: use // and % to split paid_bits into whole crowns and leftover bits,
#       then print a line like:  525 bits = 5 crowns and 25 bits

Comparisons & Booleans: Asking Yes/No Questions

So far our expressions have produced numbers. But programs also need to ask questionsis the till empty? can the customer afford this? — and the answer to a yes/no question is a bool: either True or False.

You ask numeric questions with the comparison operators:

Operator Means Example Result
== equal to 7 == 7 True
!= not equal to 7 != 5 True
< less than 3 < 2 False
> greater than 10 > 4 True
<= less than or equal to 5 <= 5 True
>= greater than or equal to 9 >= 12 False

One of these causes more grief than all the others combined: == is a question, = is a command. crowns == 50 asks “is the till 50?” and answers True or False. crowns = 50 orders “put 50 in the till.” Mixing them up is a rite of passage; knowing the difference now will save you a real headache later.

Often one question isn’t enough — can the customer afford it and is it in stock? You combine yes/no answers with the boolean operators and, or, and not. These are exactly the AND / OR / NOT logic gates from Notebook 2, now spelled as English words:

A B A and B A or B not A
F F F F T
F T F T T
T F F T F
T T T T F
  • and — True only when both sides are True.
  • or — True when either side is True.
  • not — flips it: not True is False.
# ⬇️ CHANGE THESE, THEN RE-RUN
purse  = 72        # crowns the customer is carrying
price  = 50        # price of the item
in_stock = True
# ----------------------------------

print(purse >= price)                       # can they afford it?
print(purse >= price and in_stock)          # affordable AND on the shelf?
print(purse < price or in_stock)            # either one is enough here
print(not in_stock)                         # is it sold out?

Tracing it by hand. “Tracing” means running code in your head, line by line, predicting each result before Python tells you — and it is the single most useful habit for the rest of this course. Python untangles a compound condition from the inside out, simplest part first. Walk through purse >= price and in_stock with purse = 72, price = 50, in_stock = True:

  1. 72 >= 50True
  2. in_stock is True
  3. True and TrueTrue

When several operators meet in one line, they resolve in a set order — arithmetic → comparisons → notandor — but you never have to memorize that under pressure. When in doubt, add parentheses and Python (and your reader) will evaluate the innermost ones first.

✏️ Your Turn — The Shopkeeper’s Test

Mirabel will sell an item only if the customer can afford it and it’s in stock. Set up the boxes below, then write and print one boolean expression that is True exactly when the sale should go through. Test it by changing the values so it comes out both True and False.

# ⬇️ CHANGE THESE, THEN RE-RUN
purse    = 40
price    = 35
in_stock = True
# ----------------------------------

# TODO: print a single True/False value: can this sale go through?

Input & Output: Talking to a Person

Two built-in functions let a program hold a conversation. You’ve seen both; now we make them precise:

  • print(...) shows a value to the person at the keyboard.
  • input(prompt) shows a prompt, waits for them to type a line, and hands it back.

The shape of an input is:

answer = input("a prompt to show: ")

There is one surprise hiding in that line, and it is responsible for the most common bug in this entire course — so let’s meet it head-on.

# This cell PAUSES and waits for you to type. That's expected, not a freeze.
typed = input("Type any number: ")
print(typed, "has type", type(typed))

Type 42 and look at what Python reports: the type is str, not int. input() always hands back a string, every time, even when the person typed digits. In Colab the cell pauses until you press Enter — if you ever “Run all” and the notebook seems stuck, it’s probably waiting politely at an input(). (This is exactly why our learning examples set values directly instead: editing a box is faster and never pauses.)

The #1 Beginner Bug

Because input() returns a string, doing arithmetic on it goes wrong in a way that looks almost right — which is the most dangerous kind of wrong:

# ⬇️ CHANGE THESE, THEN RE-RUN
a = "5"     # pretend these two arrived from input()
b = "3"
# ----------------------------------

print(a + b)               # "53"  — NOT 8!
print(int(a) + int(b))     # 8     — fixed

"5" + "3" is "53", because for strings + means glue together, not add. No error appears — Python silently does the wrong thing. The fix is type casting: int("5") deliberately converts the text into the number 5. The casts you’ll reach for most are int(...), float(...), and str(...).

The rule: any number that came from input() must be wrapped in int(...) or float(...) before you do math with it:

count = int(input("How many feathers? "))

✏️ Your Turn — Ask and Answer

Ask the customer how many phoenix feathers they want and the price per feather, then print the total cost. Remember to cast each input before multiplying.

# TODO: read two numbers with input(), cast them with int(),
#       multiply, and print the total cost.
#
# feathers = int(input("How many feathers? "))
# ...

Printing Well

Mirabel doesn’t want a bare number flung at the screen — she wants a readable receipt, lined up and labelled. Three tools turn raw output into something that looks like a document: escape characters, f-string formatting, and string methods.

Escape Characters

Inside a string, a backslash begins an escape character — a little code for something you can’t easily type:

Escape Means
\n start a new line
\t a tab (jump to the next column)
\" a literal double-quote
\\ a literal backslash
print("Line one\nLine two")
print("Item:\tMoonpetal")
print("Mirabel said \"mind the cat\"")
print("Path: C:\\ledgers")

Each backslash code stands in for a character that’s awkward to type literally: \n ended the first line and started a second, \t jumped to a tab stop so columns can line up, \" slipped a quote inside a quoted string without ending it early, and \\ printed a single backslash (you write two to get one).

f-string Formatting

An f-string is a string with the letter f in front of it. Inside, anything in curly braces { } gets replaced by the value of that variable. Add a colon and a format specifier, and you also control how it prints — the very same machinery as Notebook 2’s {n:08b}, just different codes:

f"text {variable} more text"
f"{variable:specifier}"
Spec Effect Example →
:.2f exactly 2 decimal places (money!) 19.519.50
:>10 right-align within 10 columns [ Fen]
:<10 left-align within 10 columns [Fen ]
:^10 centre within 10 columns [ Fen ]
:, thousands separators 12345671,234,567
# ⬇️ CHANGE THESE, THEN RE-RUN
price = 19.5
name  = "mirabel"
count = 1234567
# ----------------------------------

print(f"Total: {price:.2f} crowns")     # money -> 19.50
print(f"[{name:>12}]")                   # right-aligned
print(f"[{name:<12}]")                   # left-aligned
print(f"[{name:^12}]")                   # centred
print(f"Bits counted: {count:,}")        # 1,234,567

The colon-code only ever changes how a value prints — never the value itself. {price:.2f} forces two decimals so 19.5 reads as 19.50, which is what you want for money. The alignment codes :>12, :<12, :^12 pad a value out to 12 characters so that stacked rows line up into neat columns; the [ ] brackets above are just there to make the padding visible.

String Methods

Strings come with built-in methods — small tools you call on a string by attaching a dot:

text.method()
Tool What it does Example Result
.upper() all uppercase "mirabel".upper() "MIRABEL"
.lower() all lowercase "FEN".lower() "fen"
.title() Capitalize Each Word "phoenix feather".title() "Phoenix Feather"
.strip() trim spaces from both ends " Fen ".strip() "Fen"
.replace(old, new) swap matching text "moonpetal".replace("petal","dust") "moondust"
len(s) count the characters len("Fen") 3
"x" * n repeat a string n times "-" * 10 "----------"

Two things to know. Strings are immutable — a method never changes the original; it hands back a new string. And methods can be chained left to right, so raw.strip().title() trims first, then title-cases the trimmed result.

# ⬇️ CHANGE THIS, THEN RE-RUN
raw = "  mirabel quill  "
# ----------------------------------

print(raw.strip())                   # "mirabel quill"
print(raw.strip().title())           # "Mirabel Quill"  (trim, then title-case)
print(raw.replace("quill", "QUILL")) # swap part of the text
print("length:", len(raw.strip()))
print("=" * 30)                      # a divider line, 30 characters wide

Notice raw itself never changed — each method returned a brand-new string and left the original alone. That "=" * 30 trick is how you draw divider lines and borders without typing thirty equals signs by hand. Combine repetition with \n and f-string alignment, and you can build a tidy banner — which is exactly the next step.

Putting It Together: a Shop Label

These tools shine when you use them at once. The cell below prints a bordered price label using all three — a repeated-character rule, a centred upper-cased banner, and a right-aligned price column to two decimals.

# ⬇️ CHANGE THESE, THEN RE-RUN
shop = "mirabel's emporium"
item = "phoenix feather"
price = 35.0
# ----------------------------------

rule = "-" * 32

print(rule)
print(f"{shop.upper():^32}")
print(rule)
print(f"{item.title():<22}{price:>9.2f}")
print(rule)

Read that cell against its output: a rule line, a centred upper-cased shop name, then a left-aligned item with a right-aligned price. Nothing fancy — just the four tools combined on purpose. Change shop to your own name and re-run; the banner re-centres itself, because the width (32) is fixed and :^32 does the arithmetic for you.

✏️ Your Turn — Your Own Price Label

Make a label for an item of your own invention (a self-stirring teaspoon? a jar of bottled Tuesday?). Print a bordered label with the shop name centred and the price right-aligned to two decimals — start from the cell above and make it yours.

# ⬇️ CHANGE THESE, THEN RE-RUN
shop  = "your shop name"
item  = "your wondrous item"
price = 12.5
# ----------------------------------

# TODO: print a bordered label. Use "-" * n for the rule, :^ to centre
#       the shop name, .title() on the item, and :>9.2f for the price.

The Workflow: Problem → Pseudocode → Flowchart → Python

You now have enough Python to be dangerous. This section gives you the method that keeps you safe — the one the whole course uses. Wren Hollow never writes a line of ledger-code before she has written down what she intends to do. Four steps:

  1. Problem — state what’s needed in plain English, including the inputs and outputs.
  2. Pseudocode — the steps, written in structured plain language. Language-neutral.
  3. Flowchart — those same steps drawn as a picture, so the shape is obvious at a glance.
  4. Python — translate the pseudocode line by line, then verify the result by hand.

Jumping straight to step 4 is the most common reason beginners get stuck. The first three steps are where the thinking happens; the Python is just the transcription.

One Algorithm, Three Ways of Writing It Down

Here’s the idea that ties the workflow together: steps 2, 3, and 4 are not three different things. They are the same algorithm, written three different ways — pseudocode in structured words, a flowchart as a picture, Python as code a machine can run. Change the representation and the underlying algorithm doesn’t change, the same way £100 is the same amount whether you write it in numerals, spell it in words, or stack it in coins.

That is your first real taste of abstraction — separating what a process does from how it happens to be written down. Pseudocode lets you think purely about the what; Python worries about the how. Getting the what right first is why the planning steps matter more than the typing.

Pseudocode: the House Style

There’s no official pseudocode language, so a consistent style keeps it readable. Ours:

  • A header naming the ALGORITHM, its INPUT, and its OUTPUT.
  • Numbered steps, one action each.
  • Keywords in capitals: READ, SET, PRINT (and later IF, REPEAT).
  • Plain arithmetic, in words or symbols — whatever reads clearest.

It is deliberately not Python: no colons, no quotes, no syntax to trip over. The test is simple — if you can read it aloud and a non-programmer follows along, it’s good pseudocode.

Flowchart Notation

A flowchart draws that same algorithm. Four shapes cover everything; you need three of them today (the fourth, the decision diamond, waits for Notebook 4).

The shapes: an ellipse marks Start and End, a parallelogram marks Input or Output, a rectangle marks a Process (a calculation), and the rose-coloured diamond marks a Decision — greyed out here because choices arrive in Notebook 4.

A Worked Example, All Four Steps

Step 1 — The Problem. A customer arrives with a cache of mana-crystals to be shared out among the shop’s apprentices:

A cache holds a whole number of mana-crystals. Divide them evenly among the apprentices so each gets an equal whole number of crystals. Any crystals that don’t divide evenly are handed back to the customer. Report each apprentice’s share and the number handed back.

Pinned down precisely:

  • Inputs: crystals (a whole number), apprentices (a count)
  • Outputs: share (crystals per apprentice), leftover (crystals handed back)
  • The relationship: “how many whole groups, and how much left over?” — our old friends // and %.

Step 2 — Pseudocode. The steps, in the house style, with no Python anywhere in sight:

ALGORITHM: share_crystals
INPUT:   crystals     — total crystals in the cache
         apprentices  — how many apprentices share them
OUTPUT:  share        — crystals each apprentice receives
         leftover     — crystals handed back to the customer

1. READ crystals
2. READ apprentices
3. SET share    = crystals // apprentices
4. SET leftover = crystals % apprentices
5. PRINT share
6. PRINT leftover

Six numbered steps anyone could follow — including a tired future you, debugging this at midnight.

Step 2½ — The Flowchart. The same six steps, drawn so the straight-line shape is obvious: Start, two inputs, two calculations, one output, End.

Step 3 — Python. Now — and only now — translate the pseudocode line for line. We use an editable value block first, so the output is reproducible and we can check it by hand:

# ⬇️ CHANGE THESE, THEN RE-RUN
crystals    = 1000      # step 1: READ crystals
apprentices = 7         # step 2: READ apprentices
# ----------------------------------

share    = crystals // apprentices      # step 3
leftover = crystals % apprentices       # step 4

print(f"Each apprentice receives {share} crystals.")      # step 5
print(f"{leftover} crystals are handed back.")            # step 6

Step 4 — Verify by hand. Never trust output you haven’t checked. With crystals = 1000, apprentices = 7:

  • 1000 // 7 → 7 goes into 1000 142 times (142 × 7 = 994)
  • 1000 % 7 → leftover is 1000 − 994 = 6
  • Cross-check: 142 × 7 + 6 = 994 + 6 = 1000 ✓ — the shares plus the leftover must add back up to the whole cache. They do.

That (quotient × divisor) + remainder = original check works for any // and % pair. Get in the habit of running it.

Here is the same algorithm wired to a real person, with int(input(...)) standing in for steps 1–2 — the type-casting rule applied. The thinking was finished before a line of Python got written. That’s the whole method.

crystals    = int(input("Crystals in the cache: "))
apprentices = int(input("Number of apprentices: "))

share    = crystals // apprentices
leftover = crystals % apprentices

print(f"Each apprentice receives {share} crystals.")
print(f"{leftover} crystals are handed back.")

✏️ Exercise — Run the Whole Pipeline

Take this one through all four steps yourself — the planning steps are not optional:

A customer pays with a heap of loose copper bits. Convert it into whole crowns and leftover bits, where 100 bits = 1 crown. Report the crowns and the bits.

  1. Problem: write down the inputs and outputs.
  2. Pseudocode: in a markdown cell, in the house style.
  3. Flowchart: describe it in words, or copy the flowchart cell above and adapt it.
  4. Python: in a code cell with an editable value block — then verify by hand with one example and show the cross-check.

Hint: it’s the same // and % shape as the crystal split.

# ✏️ Your Python for the bits-to-crowns exercise.
# Write your pseudocode in a markdown cell FIRST, then translate it here.

# ⬇️ CHANGE THIS, THEN RE-RUN
paid_bits = 925
# ----------------------------------

# TODO: split paid_bits into whole crowns and leftover bits, and print both.

Building With AI: Plan First, Then Code

Notebook 1 left us with a warning: an AI generates plausible-looking text, which is not the same as correct text. The right response isn’t to avoid AI — it’s to do the thinking yourself first and then use the AI to pressure-test that thinking. When you have your own plan to compare against, you can actually tell whether the AI’s code is right.

A verification checklist for any code, yours or an AI’s:

  1. Does it run? Errors are the easy case — Python tells you about them.
  2. Test a known input. Feed it something you worked out by hand. Does the answer match?
  3. Read every line. Is each input() cast with int()? Is it // or /? Is it == or =?
  4. Does it match your plan? Without pseudocode to compare against, “it didn’t crash” is all you really know — and that’s not the same as “it’s correct.”

💭 Think About It — Who Does the Thinking?

You just saw the habit of planning in pseudocode before asking an AI to write the code.

  • If an AI can write the code for you, why bother learning to plan it yourself first? What might you lose by skipping straight to “AI, just build this”?
  • When an AI hands you code that runs but you don’t understand it, what should you do — and whose responsibility is it if that code turns out to be wrong?
  • Compare leaning on AI to write code with using GPS to navigate. What does each make easier, and what skill might quietly fade if you rely on it for everything?

There are no single right answers here — share a sentence or two on each.

Practice: PyQuiz

Time to write some code of your own against a tool that checks it for you. PyQuiz gives you short problems, lets you write a solution, and runs it against several test inputs so you can see exactly where it works and where it doesn’t.

A quick word about functions

PyQuiz frames every problem the same way: you write a function that takes some inputs and returns an answer. You’ll learn def properly in Notebook 4, but the pattern is short enough to read now:

def double_number(number):       # name, and the input it takes
    return number * 2            # the answer to hand back
  • The def line names the function and lists its parameters (the inputs).
  • The indented return line says what value to give back — note there’s no print(); PyQuiz reads the returned value directly.

PyQuiz writes the def line for you. You just fill in the body.

How to use it

For each problem: read the description and sample runs, edit the code in the box, and click Run Tests to see how you did. Stuck? Click Hint. Use Next to move on, or the dropdown to jump around — your code is checked per test case, so you can see partial progress clearly.

Run the cell below to start. (The first time, it downloads pyquiz.py from the course repo — a brief pause, then the tool appears.)

# PyQuiz bootstrap — works in Colab or any local Jupyter.
import os, urllib.request
REPO = "https://raw.githubusercontent.com/brendanpshea/computing_concepts_python/main"
if not os.path.exists("pyquiz.py"):
    urllib.request.urlretrieve(f"{REPO}/tools/python_code_quiz/pyquiz.py", "pyquiz.py")

from pyquiz import PracticeTool
practice_tool = PracticeTool(
    json_url=f"{REPO}/tools/python_code_quiz/banks/nb03_python_basics.json"
)

✏️ Capstone — Build a Trading Game (AI-Assisted)

In this exercise you’ll build a trading game. The core idea is always the same — start with some money, buy low and sell high, and try to end up richer — but the theme is yours: a magic shop, a space trader hauling cargo, a sneaker reseller flipping drops, a lemonade stand, a card- or crypto-market where prices swing. You’ll build it the way a pro does: plan first, let an AI help you write it, then verify.

One note: a real game repeats over many turns, and repetition needs loops, which arrive in Notebook 4. That’s fine here — the AI will reach for a few tools you haven’t formally met. Your job is to plan the game and check that it works, not to know every line by heart.

Step 1 — Design it first (before touching the AI). A generic prompt makes a generic game. Jot these in a markdown cell:

  • Setting & goods: your theme, plus 3–5 things to trade and a price for each.
  • The purse: how much money does the player start with?
  • The goal: end richer than you started — or hit a target before you run out.
  • The catch: what makes it fun? Prices that drift each turn? A limited number of turns? A risky item?

Step 2 — Turn your design into a prompt. Fill in the blanks and send it to Gemini (or Claude / ChatGPT):

Write a small text trading game as a Python program for Google Colab. The player starts with [N] money and can buy or sell these goods each turn: [your goods and prices]. Prices [stay fixed / drift each turn]. The game lasts [number] turns or until [your end condition]. Each turn, show the player’s money and inventory; at the end, say whether they finished richer. Keep it short and beginner-readable.

Step 3 — Get the bones working, then test. Paste it into the cell below and run it now. It won’t be perfect. Get the simplest version working first — buy one item, sell it, watch the money change — and check that by hand before adding anything.

Step 4 — Add the bells and whistles. Once the core works, add one or two extras, testing after each: prices that change each turn, a sell price different from the buy price (where profit lives), a win/lose message, or a risky item that might be worthless.

Step 5 — Reflect. In a markdown cell, write 2–3 sentences: what did the AI get wrong or what did you improve, and how did you fix it?

Remember the course rule: AI is a fast first draft. You verify.

# ✏️ Paste your AI-built trading game here, then run it and fix what's broken.

Key Terms

  • Algorithm — A finite list of clear, definite steps that takes input, does a fixed amount of work, terminates, and produces output.
  • Representation — One way of writing an algorithm down; pseudocode, a flowchart, and Python are three representations of the same algorithm.
  • Abstraction — Separating what a process does from how it is written down or carried out.
  • Variable — A named box that holds one value.
  • Assignment (=) — Stores the right-hand value into a variable; read it as “gets,” and remember the right side runs first.
  • Data type — The kind of a value: int, float, str, bool.
  • int / float — A whole number vs. a number with a decimal point.
  • str / bool — Text in quotes; a truth value (True / False).
  • Expression / statement — Code that computes a value vs. a complete instruction.
  • Operator / operand — The verb (+, //, and) and the values it acts on.
  • Floor division (//) / modulo (%) — The whole part of a division / the remainder left over.
  • Comparison operators== != < > <= >=; each produces a bool.
  • Boolean operatorsand, or, not; combine truth values.
  • Operator precedence — The order operators resolve: arithmetic → comparison → notandor.
  • Type casting — Deliberately converting a value’s type, e.g. int("5").
  • Escape character — A backslash code inside a string: \n, \t, \", \\.
  • f-string / format specifierf"..." text with {var}; codes like :.2f, :>10, :, control how a value prints.
  • String method — A function called on a string with a dot: .upper(), .strip(), .replace().
  • Pseudocode — Structured, language-neutral plain English describing an algorithm.
  • Flowchart — A diagram of an algorithm: ellipse = start/end, parallelogram = input/output, box = process, diamond = decision.
  • Trace — To run code in your head, line by line, predicting each result.
  • Comment (#) — A note for humans; Python ignores it.

Summary

  • An algorithm is a finite, definite, terminating recipe of steps from input to output — the central idea of the course — and one problem can have many algorithms.
  • Pseudocode, flowcharts, and Python are three representations of one algorithm; get the algorithm right first, then translate.
  • A variable is a named box; = stores into it, and the right side runs first.
  • Every value has a type; quotes always mean str, and input() always returns str.
  • / always gives a float; // and % answer “how many whole groups, how much left over.”
  • Boolean expressions resolve from the innermost, simplest part outward.
  • Printing well = escape characters + f-string specifiers (:.2f, alignment) + string methods + repetition.
  • The course workflow is problem → pseudocode → flowchart → Python → verify. Plan by hand; let the AI critique the plan, not hand you the answer.

Write it down before you write it up. Wren Hollow would insist.

What’s Next

Every program in this notebook ran straight down, top to bottom. Notebook 4 brings the shape we left greyed-out in the flowchart legend: the decision diamond. Programs will start making choices and repeating work — if, else, and loops. Fen restocks the shelves by repeating the same handful of steps for every jar; soon you’ll write the loop that does it without losing count.

COMP 1150 — Computer Science Concepts · Brendan Shea, PhD Content licensed under CC BY 4.0.