#!/usr/bin/env python3
"""
Week 18: Money β Coins & Bills
Phase 3: Measurement, Time & Money
Standards: 2.MD.C.8 (solve problems with dollar bills, quarters, dimes, nickels, pennies)
New Standard:
- Reduced drill (40% fewer problems)
- Estimation before calculating (about how much?)
- Multiple strategies encouraged (start with biggest coin, count by 5s/10s/25s)
- Better word problems (reasoning over keywords)
- Real challenges (open-ended thinking β make an amount different ways)
- Number talks (compare coin collections without counting every cent)
- Friday self-check with reflection
- Fact fluency warmup daily (skip counting by 5s, 10s, 25s)
- Word problems every day
"""
import os
import glob
from weasyprint import HTML
from math_helpers import (
CSS, TEACHER_CSS,
page, page_multi, hdr, sec, b, bw, bl,
tg_page_multi, tg_sec, tg_note, tg_section_title,
coin_svg,
)
from activity_builders import (
build_coin_identification,
build_money_adding,
)
BASE = os.path.expanduser("~/Home_School/2nd_Grade/Math")
WEEK = os.path.join(BASE, "Week_18")
def coins_row(coin_list):
"""Render a row of coin SVGs from [(type, count), ...]."""
html = ''
for ctype, count in coin_list:
for _ in range(count):
html += coin_svg(ctype, size=22)
return html
# βββββββββββββββββββββββββββββββββββββββββββββββββββ
# MONDAY β Meet the Coins
# βββββββββββββββββββββββββββββββββββββββββββββββββββ
def monday():
# 1: Fluency warmup β skip count by 5s and 10s (coin counting foundation)
s1 = '<div class="abox" style="background:#e8f5e9;">'\
'<p><b>2-min Fluency Warm-up</b> β Skip count. Fill in the blanks.</p>'\
'<div class="mgrid c3">'
for seq in ["5, 10, 15, ___", "10, 20, 30, ___", "25, 50, ___", "10, 15, 20, ___"]:
s1 += f'<div class="abox"><p>{seq}</p></div>'
s1 += '</div></div>'
# 2: Meet the coins β guided intro
s2 = '<p class="note">Every coin has a name and a value. P = penny, N = nickel, D = dime, Q = quarter.</p>'
s2 += build_coin_identification({
"coins": [
{"type": "penny", "count": 1, "blank_value": False},
{"type": "nickel", "count": 1, "blank_value": False},
{"type": "dime", "count": 1, "blank_value": False},
{"type": "quarter", "count": 1, "blank_value": False},
],
"note": "Read together: the penny is 1Β’, nickel 5Β’, dime 10Β’, quarter 25Β’. Fun fact: the dime is the smallest coin but NOT the smallest value!"
})
# 3: Coin values practice (reduced from 8 to 4)
s3 = build_coin_identification({
"coins": [
{"type": "quarter", "count": 1, "blank_value": True},
{"type": "dime", "count": 1, "blank_value": True},
{"type": "penny", "count": 1, "blank_value": True},
{"type": "nickel", "count": 1, "blank_value": True},
],
"note": "Write the value of each coin."
})
# 4: Number Talk β reason about coins WITHOUT counting
s4 = '<div class="abox" style="background:#e3f2fd;">'\
'<p><b>Number Talk</b> β Explain WITHOUT calculating.</p>'\
'<div class="mgrid c2">'
s4 += '<div class="abox"><p>Who has more money: Ana with 3 dimes, or Ben with 3 pennies? How do you know without counting?</p><p style="font-size:11px;">My thinking: ' + bw() + '</p></div>'
s4 += '<div class="abox"><p>A dime is smaller than a nickel. Does that mean it is worth less? Explain.</p><p style="font-size:11px;">My thinking: ' + bw() + '</p></div>'
s4 += '</div></div>'
# 5: Word problem
s5 = '<div class="wp">'\
'<p class="note">Read carefully. Think about what is happening.</p>'\
'<div class="abox"><p style="font-size:0.95em;">Zoe found a coin under the couch. It is worth more than a dime but less than a dollar, '\
'and it has a 25 on the back. What coin did Zoe find? How much is it worth?</p>'\
'<p>Coin: ' + bw("8em") + ' Value: ' + b("3em") + 'Β’</p></div></div>'
return page(18, "Monday", "Meet the Coins",
f'''{sec(1, "Warm-up: Skip Counting", s1)}
{sec(2, "Coin Names and Values", s2)}
{sec(3, "Write the Values", s3)}
{sec(4, "Number Talk: Size vs. Value", s4)}
{sec(5, "Word Problem", s5)}''')
# βββββββββββββββββββββββββββββββββββββββββββββββββββ
# TUESDAY β Counting Same-Coin Groups + Estimation
# βββββββββββββββββββββββββββββββββββββββββββββββββββ
def tuesday():
# 1: Fluency warmup β count by 25s
s1 = '<div class="abox" style="background:#e8f5e9;">'\
'<p><b>2-min Fluency Warm-up</b> β Count by 25s (like quarters!).</p>'\
'<div class="mgrid c3">'
for seq in ["25, 50, ___", "25, 50, 75, ___", "50, 75, ___", "___, 50, 75"]:
s1 += f'<div class="abox"><p>{seq}</p></div>'
s1 += '</div></div>'
# 2: Count groups of the same coin (reduced from 8 to 4)
s2 = '<p class="note">Skip count to find the total: nickels by 5s, dimes by 10s, quarters by 25s.</p>'
s2 += '<div class="mgrid c2">'
groups = [("nickel", 4, "5s"), ("dime", 5, "10s"), ("quarter", 3, "25s"), ("penny", 6, "1s")]
for ctype, count, skip in groups:
s2 += f'<div class="abox" style="text-align:center;">{coins_row([(ctype, count)])}'\
f'<p style="font-size:11px;">Count by {skip}</p>'\
f'<p>Total: {b("3em")}Β’</p></div>'
s2 += '</div>'
# 3: Estimate First! β about how much?
s3 = '<div class="abox" style="background:#fff3e0;">'\
'<p><b>Estimate First!</b> Look at the coins. Is the total MORE or LESS than 50Β’? Circle one, then count exactly.</p>'\
'<div class="mgrid c2">'
est_groups = [
[("quarter", 2), ("dime", 1)],
[("dime", 2), ("penny", 3)],
[("quarter", 1), ("nickel", 2)],
[("dime", 4), ("nickel", 3)],
]
for grp in est_groups:
s3 += f'<div class="abox" style="text-align:center;">{coins_row(grp)}'\
f'<p>more than 50Β’ / less than 50Β’</p>'\
f'<p>Exact: {b("3em")}Β’</p></div>'
s3 += '</div></div>'
# 4: Which coin am I? riddles
s4 = '<div class="abox">'\
'<p class="note">Coin riddles! Read the clues and name the coin.</p>'\
'<div class="mgrid c2">'
riddles = [
"Two of me make a dime. What am I?",
"Four of me make a dollar. What am I?",
"I am worth the least, but you need 100 of me for a dollar. What am I?",
"Ten of me make a dollar. What am I?",
]
for r in riddles:
s4 += f'<div class="abox"><p style="font-size:0.95em;">{r}</p><p>' + bw("8em") + '</p></div>'
s4 += '</div></div>'
# 5: Word problem
s5 = '<div class="wp">'\
'<p class="note">Read carefully. Think about what is happening. Draw the coins if it helps!</p>'\
'<div class="abox"><p style="font-size:0.95em;">Milo has 6 nickels in his piggy bank. He skip counts by 5s to find his total. '\
'What total does he get? Write the numbers he says.</p>'\
'<p style="font-size:11px;">Numbers he says: ' + bw() + '</p>'\
'<p>Total: ' + b("3em") + 'Β’</p></div></div>'
return page(18, "Tuesday", "Counting Coin Groups",
f'''{sec(1, "Warm-up: Count by 25s", s1)}
{sec(2, "Skip Count the Coins", s2)}
{sec(3, "Estimate First!", s3)}
{sec(4, "Coin Riddles", s4)}
{sec(5, "Word Problem", s5)}''')
# βββββββββββββββββββββββββββββββββββββββββββββββββββ
# WEDNESDAY β Counting Mixed Coins + Two Ways
# βββββββββββββββββββββββββββββββββββββββββββββββββββ
def wednesday():
# 1: Fluency warmup β mixed skip counting
s1 = '<div class="abox" style="background:#e8f5e9;">'\
'<p><b>2-min Fluency Warm-up</b> β Keep the count going.</p>'\
'<div class="mgrid c3">'
for seq in ["25, 35, 45, ___", "50, 60, 65, ___", "25, 50, 60, ___", "10, 20, 25, ___"]:
s1 += f'<div class="abox"><p>{seq}</p></div>'
s1 += '</div></div>'
# 2: Count mixed coins β start with the biggest! (reduced from 8 to 4)
s2 = '<p class="note"><b>Strategy:</b> Start with the biggest value coin, then count on with the smaller ones.</p>'
s2 += build_money_adding({
"problems": [
{"coins": [{"type": "quarter", "count": 1}, {"type": "dime", "count": 2}, {"type": "penny", "count": 3}], "blank": True},
{"coins": [{"type": "quarter", "count": 2}, {"type": "nickel", "count": 1}], "blank": True},
{"coins": [{"type": "dime", "count": 3}, {"type": "nickel", "count": 2}, {"type": "penny", "count": 4}], "blank": True},
{"coins": [{"type": "quarter", "count": 1}, {"type": "dime", "count": 1}, {"type": "nickel", "count": 1}, {"type": "penny", "count": 1}], "blank": True},
],
"note": "Count the coins and write the total. Biggest coins first!"
})
# 3: Two Ways β make the same amount two different ways
s3 = '<div class="abox">'\
'<p class="note"><b>Two Ways</b> β Show two different ways to make each amount with coins. Draw or write the coins.</p>'\
'<div class="mgrid c2">'
for amount in ["30Β’", "50Β’"]:
s3 += f'<div class="abox"><p><b>Make {amount}</b></p>'\
'<p style="font-size:11px;">Strategy 1: ' + bw() + '</p>'\
'<p style="font-size:11px;">Strategy 2: ' + bw() + '</p></div>'
s3 += '</div></div>'
# 4: Word problems
s4 = '<div class="wp">'\
'<p class="note">Read carefully. Think about what is happening. Draw the coins if it helps!</p>'\
'<div class="mgrid c2">'
problems = [
"Ruby empties her pocket: 1 quarter, 1 dime, and 2 pennies. She wants to buy a sticker that costs 40Β’. Does she have enough?",
"Jack has 3 dimes. Emma has 5 nickels. Jack says he has more money because dimes are worth more. Is he right?",
]
for text in problems:
s4 += f'<div class="abox"><p style="font-size:0.95em;">{text}</p>'\
'<p style="font-size:11px;">Draw or write your thinking: ' + bw() + '</p>'\
'<p>Answer: ' + bw() + '</p></div>'
s4 += '</div></div>'
# 5: Challenge β Create Your Own
s5 = '<div class="abox" style="background:#f3e5f5;">'\
'<p><b>Create Your Own</b></p>'\
'<p>Pick your own amount less than 99Β’. Write it, then show a handful of coins that makes it.</p>'\
'<p>My amount: ' + b("3em") + 'Β’</p>'\
'<p style="min-height:60px; border:1px dashed #999; border-radius:4px; padding:6px; font-size:11px; color:#999;">Draw or list your coins here</p>'\
'<p style="font-size:11px; color:#666;">Strategy I used: ' + bw() + '</p>'\
'</div>'
return page(18, "Wednesday", "Counting Mixed Coins",
f'''{sec(1, "Warm-up: Mixed Skip Counting", s1)}
{sec(2, "Count Mixed Coins (Biggest First)", s2)}
{sec(3, "Two Ways to Make an Amount", s3)}
{sec(4, "Word Problems", s4)}
{sec(5, "Challenge: Create Your Own", s5)}''')
# βββββββββββββββββββββββββββββββββββββββββββββββββββ
# THURSDAY β Dollar Bills & Real-World Money
# βββββββββββββββββββββββββββββββββββββββββββββββββββ
def thursday():
# 1: Fluency warmup
s1 = '<div class="abox" style="background:#e8f5e9;">'\
'<p><b>2-min Fluency Warm-up</b> β How many make a dollar?</p>'\
'<div class="mgrid c3">'
for q in ["___ quarters = $1", "___ dimes = $1", "___ nickels = $1", "___ pennies = $1"]:
s1 += f'<div class="abox"><p>{q}</p></div>'
s1 += '</div></div>'
# 2: Dollars and the $ sign
s2 = '<p class="note">100Β’ = $1.00 (one dollar). We write dollars with a <b>$</b> and a dot: $1.25 means 1 dollar and 25 cents. '\
'Bills come in $1, $5, $10, and $20.</p>'\
'<div class="mgrid c2">'
for q, hint in [("$1 bill + 1 quarter = $", "1 dollar and 25 cents"),
("$5 bill + 1 dime = $", "5 dollars and 10 cents"),
("$1 bill + 3 dimes = $", "1 dollar and 30 cents"),
("$10 bill + 1 nickel = $", "10 dollars and 5 cents")]:
s2 += f'<div class="abox"><p>{q}{b("2em")}.{b("2em")}</p><p style="font-size:11px; color:#666;">({hint})</p></div>'
s2 += '</div>'
# 3: Better word problems β reasoning (reduced from 4 to 3)
s3 = '<div class="wp">'\
'<p class="note">Read carefully. Think about what is happening in the situation.</p>'\
'<div class="mgrid c2">'
problems = [
"At the fair, a pretzel costs 75Β’. Ava has 2 quarters and 2 dimes. Does she have enough for the pretzel? Show your thinking.",
"Grandpa gives Theo one $1 bill. Theo's sister has 4 quarters. Who has more money, or do they have the same?",
"A juice box costs 55Β’. Name TWO different sets of coins that pay for it exactly.",
]
for text in problems:
s3 += f'<div class="abox"><p style="font-size:0.95em;">{text}</p>'\
'<p style="font-size:11px;">Draw or write your thinking: ' + bw() + '</p>'\
'<p>Answer: ' + bw() + '</p></div>'
s3 += '</div></div>'
# 4: Number Talk β Explain WITHOUT calculating
s4 = '<div class="abox" style="background:#e3f2fd;">'\
'<p><b>Number Talk</b> β Explain WITHOUT calculating.</p>'\
'<div class="mgrid c2">'
s4 += '<div class="abox"><p>A: 5 dimes B: 5 nickels</p><p>Which is worth more? How do you know without counting?</p><p style="font-size:11px;">My thinking: ' + bw() + '</p></div>'
s4 += '<div class="abox"><p>A: 3 quarters B: 8 dimes</p><p>Which is closer to one dollar? Reason it out.</p><p style="font-size:11px;">My thinking: ' + bw() + '</p></div>'
s4 += '</div></div>'
# 5: Create your own word problem
s5 = '<div class="abox" style="background:#f3e5f5;">'\
'<p><b>Create Your Own Word Problem</b></p>'\
'<p>Write a money word problem about a small store (toys, snacks, stickersβ¦). Use at least two kinds of coins. Then solve it.</p>'\
'<p style="min-height:60px; border-bottom:1px solid #333;"></p>'\
'<p style="min-height:30px; border-bottom:1px solid #333;"></p>'\
'<p>Answer: ' + bl() + '</p>'\
'</div>'
return page(18, "Thursday", "Dollars, Bills & Real-World Money",
f'''{sec(1, "Warm-up: Make a Dollar", s1)}
{sec(2, "Dollars and the $ Sign", s2)}
{sec(3, "Word Problems: Think About What Is Happening", s3)}
{sec(4, "Number Talk: Compare Without Counting", s4)}
{sec(5, "Challenge: Create Your Own", s5)}''')
# βββββββββββββββββββββββββββββββββββββββββββββββββββ
# FRIDAY β Review & Self-Check
# βββββββββββββββββββββββββββββββββββββββββββββββββββ
def friday():
# 1: Fluency warmup
s1 = '<div class="abox" style="background:#e8f5e9;">'\
'<p><b>2-min Fluency Warm-up</b> β Coin values. Go fast!</p>'\
'<div class="mgrid c3">'
for q in ["quarter = ___Β’", "dime = ___Β’", "nickel = ___Β’", "penny = ___Β’"]:
s1 += f'<div class="abox"><p>{q}</p></div>'
s1 += '</div></div>'
# 2: Estimate First! β more or less than a dollar?
s2 = '<div class="abox" style="background:#fff3e0;">'\
'<p><b>Estimate First!</b> Is each set MORE or LESS than $1.00? Circle, then count exactly.</p>'\
'<div class="mgrid c2">'
est_groups = [
[("quarter", 3), ("dime", 2)],
[("quarter", 4), ("nickel", 1)],
[("dime", 6), ("penny", 5)],
[("quarter", 2), ("dime", 3), ("nickel", 1)],
]
for grp in est_groups:
s2 += f'<div class="abox" style="text-align:center;">{coins_row(grp)}'\
f'<p>more than $1 / less than $1</p>'\
f'<p>Exact: {b("3em")}Β’</p></div>'
s2 += '</div></div>'
# 3: Mixed coin counting review (reduced from 6 to 4)
s3 = build_money_adding({
"problems": [
{"coins": [{"type": "quarter", "count": 1}, {"type": "nickel", "count": 3}], "blank": True},
{"coins": [{"type": "dime", "count": 4}, {"type": "penny", "count": 2}], "blank": True},
{"coins": [{"type": "quarter", "count": 2}, {"type": "dime", "count": 1}, {"type": "penny", "count": 1}], "blank": True},
{"coins": [{"type": "nickel", "count": 4}, {"type": "dime", "count": 2}], "blank": True},
],
"note": "Review: count each set. Use any strategy you like."
})
# 4: Word problem review
s4 = '<div class="wp">'\
'<p class="note">Read carefully. Show your thinking.</p>'\
'<div class="mgrid c2">'
problems = [
"Sam's snack costs 65Β’. He pays with 2 quarters, 1 dime, and 1 nickel. Did he pay exactly the right amount?",
"Lily wants to trade her 10 nickels for dimes. How many dimes should she get so it's a fair trade?",
]
for text in problems:
s4 += f'<div class="abox"><p style="font-size:0.95em;">{text}</p>'\
'<p style="font-size:11px;">My thinking: ' + bw() + '</p>'\
'<p>Answer: ' + bw() + '</p></div>'
s4 += '</div></div>'
# 5: Self-check with emoji reflection
s5 = '<div class="selfcheck">'\
'<p><b>Self-Check: How do you feel about coins and bills?</b></p>'\
'<div style="display:flex; gap:20px; flex-wrap:wrap;">'\
'<div style="background:#fff3e0; padding:10px; border-radius:5px; flex:1; min-width:150px;">'\
'<p><b>Coin Names & Values</b></p>'\
'<p>π I got it! | π Getting there | π Need help</p>'\
'</div>'\
'<div style="background:#e3f2fd; padding:10px; border-radius:5px; flex:1; min-width:150px;">'\
'<p><b>Counting Mixed Coins</b></p>'\
'<p>π I got it! | π Getting there | π Need help</p>'\
'</div>'\
'<div style="background:#f3e5f5; padding:10px; border-radius:5px; flex:1; min-width:150px;">'\
'<p><b>Making Amounts Different Ways</b></p>'\
'<p>π I got it! | π Getting there | π Need help</p>'\
'</div>'\
'</div>'\
'<p style="margin-top:10px;"><b>One thing I learned this week:</b> ' + bl() + '</p>'\
'<p><b>One thing I want to practice more:</b> ' + bl() + '</p>'\
'<p><b>My favorite coin-counting strategy:</b> ' + bl() + '</p>'\
'</div>'
return page(18, "Friday", "Week 18 Review & Self-Check",
f'''{sec(1, "Warm-up: Coin Values", s1)}
{sec(2, "Estimate First!", s2)}
{sec(3, "Count the Coins Review", s3)}
{sec(4, "Word Problems", s4)}
{sec(5, "Self-Check & Reflection", s5)}''')
# βββββββββββββββββββββββββββββββββββββββββββββββββββ
# TEACHER GUIDE
# βββββββββββββββββββββββββββββββββββββββββββββββββββ
def teacher_guide():
return tg_page_multi(
"Week 18", "Money: Coins & Bills β Teacher Guide",
tg_section_title("Monday: Meet the Coins") +
tg_sec(1, "Warm-up skip count", ["20; 40; 75; 25"]) +
tg_sec(2, "Coin Values (guided)", ["1Β’, 5Β’, 10Β’, 25Β’"]) +
tg_sec(3, "Write the Values", ["25Β’, 10Β’, 1Β’, 5Β’"]) +
tg_sec(4, "Number Talk", ["Ana β dimes are each worth 10Γ a penny", "No β size does not equal value; dime (10Β’) > nickel (5Β’)"]) +
tg_sec(5, "Word Problem", ["Quarter β 25Β’"]) +
tg_note("Page break"),
tg_section_title("Tuesday: Counting Coin Groups") +
tg_sec(1, "Warm-up 25s", ["75; 100; 100; 25"]) +
tg_sec(2, "Skip Count Coins", ["4 nickels=20Β’, 5 dimes=50Β’, 3 quarters=75Β’, 6 pennies=6Β’"]) +
tg_sec(3, "Estimate First", ["60Β’ (more), 23Β’ (less), 35Β’ (less), 55Β’ (more)"]) +
tg_sec(4, "Coin Riddles", ["nickel, quarter, penny, dime"]) +
tg_sec(5, "Word Problem", ["5,10,15,20,25,30 β total 30Β’"]) +
tg_note("Page break"),
tg_section_title("Wednesday: Counting Mixed Coins") +
tg_sec(1, "Warm-up", ["55; 70; 70; 30 (accept sensible continuations)"]) +
tg_sec(2, "Mixed Coins", ["48Β’ ($0.48), 55Β’ ($0.55), 44Β’ ($0.44), 41Β’ ($0.41)"]) +
tg_sec(3, "Two Ways", ["30Β’: 3 dimes / quarter+nickel / 6 nickelsβ¦", "50Β’: 2 quarters / 5 dimes / quarter+2 dimes+nickelβ¦"]) +
tg_sec(4, "Word Problems", ["Ruby has 37Β’ β NOT enough for 40Β’", "Jack: 30Β’ vs Emma: 25Β’ β Jack right, but for the total, not just coin type"]) +
tg_sec(5, "Create Own", ["Accept any correct amount + matching coins"]) +
tg_note("Page break"),
tg_section_title("Thursday: Dollars, Bills & Real-World Money") +
tg_sec(1, "Warm-up make a dollar", ["4 quarters, 10 dimes, 20 nickels, 100 pennies"]) +
tg_sec(2, "Dollars & $ Sign", ["$1.25, $5.10, $1.30, $10.05"]) +
tg_sec(3, "Word Problems", ["Ava has 70Β’ β not enough for 75Β’", "Same β 4 quarters = $1", "e.g., 2 quarters+1 nickel; 5 dimes+1 nickel; 11 nickels"]) +
tg_sec(4, "Number Talk", ["Dimes β each dime is worth more than each nickel", "8 dimes (80Β’) is closer to $1 than 3 quarters (75Β’)"]) +
tg_sec(5, "Create Own", ["Accept student-created money problems"]) +
tg_note("Page break"),
tg_section_title("Friday: Review & Self-Check") +
tg_sec(1, "Warm-up values", ["25, 10, 5, 1"]) +
tg_sec(2, "Estimate First", ["95Β’ (less), 105Β’ (more), 65Β’ (less), 85Β’ (less)"]) +
tg_sec(3, "Coin Review", ["40Β’, 42Β’, 61Β’, 40Β’"]) +
tg_sec(4, "Word Problems", ["Yes β 25+25+10+5 = 65Β’ exactly", "5 dimes (10 nickels = 50Β’ = 5 dimes)"]) +
tg_sec(5, "Self-Check", ["Accept student self-assessment and reflection"])
)
# βββββββββββββββββββββββββββββββββββββββββββββββββββ
# GENERATE
# βββββββββββββββββββββββββββββββββββββββββββββββββββ
if __name__ == "__main__":
os.makedirs(WEEK, exist_ok=True)
for f in glob.glob(os.path.join(WEEK, "*.pdf")):
os.remove(f)
for f in glob.glob(os.path.join(WEEK, "*.html")):
os.remove(f)
days = [
(monday, "Monday", "Meet the Coins"),
(tuesday, "Tuesday", "Counting Coin Groups"),
(wednesday, "Wednesday", "Counting Mixed Coins"),
(thursday, "Thursday", "Dollars, Bills & Real-World Money"),
(friday, "Friday", "Week 18 Review & Self-Check"),
]
for lesson_func, day, title in days:
html = lesson_func()
fname = f"Week_18_{day}"
path = os.path.join(WEEK, f"{fname}.html")
with open(path, "w") as f:
f.write(html)
pdf_path = os.path.join(WEEK, f"{fname}.pdf")
HTML(filename=path).write_pdf(pdf_path)
print(f"Generated: {pdf_path}")
html = teacher_guide()
path = os.path.join(WEEK, "Week_18_Teacher_Guide.html")
with open(path, "w") as f:
f.write(html)
pdf_path = os.path.join(WEEK, "Week_18_Teacher_Guide.pdf")
HTML(filename=path).write_pdf(pdf_path)
print(f"Generated: {pdf_path}")
print("\nWeek 18 (Money: Coins & Bills, new standard) complete!")