#!/usr/bin/env python3
"""
Week 9: Addition with Regrouping — REWRITTEN
Phase 2: Addition & Subtraction to 100
New Standard:
- Reduced drill (40% fewer problems)
- Added estimation activities
- Multiple strategies encouraged
- Better word problems (reasoning over keywords)
- Real challenges (open-ended thinking)
- Number talks (compare without calculating)
- Friday self-check with reflection
"""
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, tg_page_multi, tg_sec, tg_note, tg_section_title,
)
from activity_builders import (
build_column_addition,
build_regrouping_visual,
build_two_step_problems,
)
BASE = os.path.expanduser("~/Home_School/2nd_Grade/Math")
WEEK = os.path.join(BASE, "Week_9")
# ═══════════════════════════════════════════════════
# MONDAY — Introduction to Regrouping (Visual)
# ═══════════════════════════════════════════════════
def monday():
# 1: Base-10 blocks concept — "10 ones = 1 ten"
s1 = '<p class="note">When the ones add up to 10 or more, we <b>regroup</b>: trade 10 ones for 1 ten.</p>'
s1 += build_regrouping_visual({
"problems": [(28, 35, "add"), (47, 26, "add")],
"note": "Look at the ones. When they make 10 or more, circle them and trade for a ten."
})
# 2: Simple regrouping (reduced from 6 to 4)
s2 = '<p class="note">Add the ones. If you get 10 or more, regroup. Then add the tens.</p>'
s2 += '<div class="mgrid c3">'
for n in [(28, 35), (47, 26), (39, 44), (58, 27)]:
s2 += f'<div class="abox"><p>{n[0]} + {n[1]} = {b("5em")}</p></div>'
s2 += '</div>'
# 3: NEW — Predict: Will regrouping be needed?
s3 = '<p class="note">Look at the ones digits. Will you need to regroup? Write <b>yes</b> or <b>no</b> before solving.</p>'
s3 += '<div class="mgrid c3">'
for a, c in [(23, 45), (28, 35), (41, 56), (39, 44)]:
s3 += f'<div class="abox"><p>{a} + {c}: Regroup? <span class="bw">______</span></p></div>'
s3 += '</div>'
# 4: NEW — Number Talk: Compare WITHOUT calculating
s4 = '<div class="abox" style="background:#e3f2fd;">'
s4 += '<p><b>Number Talk</b> — Explain WITHOUT calculating.</p>'
s4 += '<div class="mgrid c2">'
s4 += '<div class="abox"><p>Which sum is bigger?</p><p>28 + 35 or 28 + 45</p><p style="font-size:11px;">My thinking: ' + bw() + '</p></div>'
s4 += '<div class="abox"><p>Which sum is bigger?</p><p>47 + 26 or 37 + 26</p><p style="font-size:11px;">My thinking: ' + bw() + '</p></div>'
s4 += '</div></div>'
# 5: Challenge — Show two different ways (reduced from 3 step-by-step to 2)
s5 = '<div class="abox" style="background:#f3e5f5;">'
s5 += '<p><b>Challenge</b> — Show two different ways to solve. Try base-10 blocks in your head AND column addition.</p>'
s5 += '<div class="mgrid c2">'
for a, c in [(38, 46), (57, 35)]:
s5 += f'<div class="abox"><p><b>{a} + {c} = </b>{b("5em")}</p>'
s5 += '<p style="font-size:11px; color:#666;">Strategy 1: ' + bw() + '</p>'
s5 += '<p style="font-size:11px; color:#666;">Strategy 2: ' + bw() + '</p></div>'
s5 += '</div></div>'
return page(9, "Monday", "Introduction to Regrouping (Visual)",
f'''{sec(1, "Visual Regrouping: 10 Ones = 1 Ten", s1)}
{sec(2, "Simple Regrouping", s2)}
{sec(3, "Predict: Will You Regroup?", s3)}
{sec(4, "Number Talk: Which Sum is Bigger?", s4)}
{sec(5, "Challenge: Show Two Different Ways", s5)}''')
# ═══════════════════════════════════════════════════
# TUESDAY — Column Addition with Regrouping
# ═══════════════════════════════════════════════════
def tuesday():
# 1: Column addition with regrouping — carry the 1 (reduced from 6 to 4)
s1 = '<p class="note">Add ones column. If 10 or more, write ones digit and <b>carry the 1</b> to tens.</p>'
s1 += build_column_addition({
"problems": [(28, 35), (47, 26), (39, 44), (58, 27)],
"digits": 2,
"note": "Don't forget to add the carried 1 to the tens column!"
})
# 2: NEW — Estimation before calculating
s2 = '<div class="abox" style="background:#fff3e0;">'
s2 += '<p><b>Estimate First!</b> Round to tens, estimate, then calculate the actual answer.</p>'
s2 += '<div class="mgrid c2">'
for a, c in [(28, 35), (47, 56), (69, 28), (78, 45)]:
at = (a + 5) // 10 * 10 # round to tens
ct = (c + 5) // 10 * 10
s2 += f'<div class="abox"><p><b>{a} + {c}</b></p>'
s2 += f'<p>Round to tens: {at} + {ct} = {(at + ct)}</p>'
s2 += f'<p>Estimate: ' + b('4em') + '</p>'
s2 += f'<p>Actual: ' + b('4em') + '</p></div>'
s2 += '</div></div>'
# 3: Step-by-step with regrouping explanation (reduced from 2 to 1)
s3 = '<p class="note">Write each step. Show where the carried 1 goes.</p>'
s3 += '<div class="mgrid c2">'
for a, c in [(28, 35), (47, 26)]:
ao, at = a % 10, a // 10
co, ct = c % 10, c // 10
ones_sum = ao + co
s3 += f'<div class="abox"><p><b>{a} + {c}</b></p>'
s3 += f'<p>Ones: {ao} + {co} = {ones_sum}</p>'
s3 += f'<p>Regroup: {ones_sum} = 1 ten + {(ones_sum % 10)} ones</p>'
s3 += '<p>Write <span class="bw">___</span> in ones place, carry 1 to tens</p>'
s3 += f'<p>Tens: {at} + {ct} + 1 (carried) = ' + b("4em") + '</p>'
s3 += '<p><b>Total: </b>' + b("5em") + '</p></div>'
s3 += '</div>'
# 4: Multiple strategies encouraged
s4 = '<div class="abox">'
s4 += '<p class="note">Use ANY strategy you prefer. Try a different one for each problem.</p>'
s4 += '<div class="mgrid c2">'
for a, c in [(78, 19), (56, 38), (69, 27), (87, 16)]:
s4 += f'<div class="abox"><p><b>{a} + {c} = </b>{b("5em")}</p>'
s4 += '<p style="font-size:11px; color:#666;">Strategy I used: ' + bw() + '</p></div>'
s4 += '</div></div>'
# 5: NEW — Number Talk: Explain WITHOUT calculating
s5 = '<div class="abox" style="background:#e3f2fd;">'
s5 += '<p><b>Number Talk</b> — Explain WITHOUT calculating.</p>'
s5 += '<div class="mgrid c1">'
s5 += '<div class="abox"><p>If 39 + 24 = 63, what is 39 + 25?</p>'
s5 += '<p style="font-size:11px;">My thinking: ' + bw() + '</p></div>'
s5 += '<div class="abox"><p>If 47 + 26 = 73, what is 57 + 26?</p>'
s5 += '<p style="font-size:11px;">My thinking: ' + bw() + '</p></div>'
s5 += '</div></div>'
return page(9, "Tuesday", "Column Addition with Regrouping",
f'''{sec(1, "Carry the 1", s1)}
{sec(2, "Estimate First!", s2)}
{sec(3, "Step-by-Step Regrouping", s3)}
{sec(4, "Try Different Strategies", s4)}
{sec(5, "Number Talk: Connected Sums", s5)}''')
# ═══════════════════════════════════════════════════
# WEDNESDAY — Mixed Regrouping Practice
# ═══════════════════════════════════════════════════
def wednesday():
# 1: Mixed — some regroup, some don't (reduced from 6 to 4)
s1 = '<p class="note">Decide: does this need regrouping? Write <b>yes</b> or <b>no</b>, then solve.</p>'
s1 += '<div class="mgrid c3">'
# Mix of regrouping and non-regrouping
for a, c in [(23, 45), (28, 35), (41, 56), (39, 44)]:
s1 += f'<div class="abox"><p>{a} + {c}: Regroup? <span class="bw">____</span></p>'
s1 += f'<p>{a} + {c} = {b("5em")}</p></div>'
s1 += '</div>'
# 2: Three addends with regrouping (reduced from 3 to 2)
s2 = '<p class="note">Add ones column first. Regroup if needed. Then tens.</p>'
s2 += '<div class="mgrid c2">'
for a, c, e in [(28, 35, 14), (47, 26, 19)]:
s2 += f'<div class="abox" style="text-align:center;">'
s2 += f'<p style="font-size:1.3em; letter-spacing:3px;"> {a}</p>'
s2 += f'<p style="font-size:1.3em; letter-spacing:3px;">+ {c}</p>'
s2 += f'<p style="font-size:1.3em; letter-spacing:3px;">+ {e}</p>'
s2 += '<hr style="border:2px solid #333;">'
s2 += f'<p style="font-size:1.3em; letter-spacing:3px;"> {b("4em")}</p>'
s2 += '</div>'
s2 += '</div>'
# 3: Find the error — regrouping mistakes (reduced from 3 to 2)
s3 = '<div class="abox">'
s3 += '<p class="note">One of these has a regrouping error. Find it, explain the error, and fix it.</p>'
s3 += '<div class="mgrid c2">'
# Wrong: 28+35 should be 63, not 53 (forgot to carry)
s3 += '<div class="abox"><p style="text-align:center;"> 28</p><p style="text-align:center;">+ 35</p><hr><p style="text-align:center;"> 53</p><p>✓ or ✗?</p><p style="font-size:11px;">Explain the error: ' + bw() + '</p><p style="font-size:11px;">Correct answer: ' + b("4em") + '</p></div>'
# Wrong: 58+39 should be 97, not 87
s3 += '<div class="abox"><p style="text-align:center;"> 58</p><p style="text-align:center;">+ 39</p><hr><p style="text-align:center;"> 87</p><p>✓ or ✗?</p><p style="font-size:11px;">Explain the error: ' + bw() + '</p><p style="font-size:11px;">Correct answer: ' + b("4em") + '</p></div>'
s3 += '</div></div>'
# 4: Horizontal to column conversion (reduced from 4 to 2)
s4 = '<p class="note">Write it as a column problem, then solve.</p>'
s4 += '<div class="mgrid c2">'
for a, c in [(47, 58), (36, 69)]:
s4 += f'<div class="abox"><p><b>{a} + {c} = </b></p>'
s4 += f'<p style="text-align:center; font-size:1.3em; letter-spacing:3px;"> {a}</p>'
s4 += f'<p style="text-align:center; font-size:1.3em; letter-spacing:3px;">+ {c}</p>'
s4 += '<hr style="border:2px solid #333;">'
s4 += f'<p style="text-align:center; font-size:1.3em; letter-spacing:3px;"> {b("4em")}</p></div>'
s4 += '</div>'
# 5: Challenge — Create your own
s5 = '<div class="abox" style="background:#f3e5f5;">'
s5 += '<p><b>Create Your Own</b></p>'
s5 += '<p>Make a column addition problem that <b>needs regrouping</b>. Write it and solve it.</p>'
s5 += '<p style="text-align:center; font-size:1.3em; letter-spacing:3px;"> ' + b("3em") + '</p>'
s5 += '<p style="text-align:center; font-size:1.3em; letter-spacing:3px;">+ ' + b("3em") + '</p>'
s5 += '<hr style="border:2px solid #333;">'
s5 += '<p style="text-align:center; font-size:1.3em; letter-spacing:3px;"> ' + b("4em") + '</p>'
s5 += '<p style="font-size:11px; color:#666;">Strategy I used: ' + bw() + '</p>'
s5 += '</div>'
return page(9, "Wednesday", "Mixed Regrouping Practice",
f'''{sec(1, "Mixed: Does It Need Regrouping?", s1)}
{sec(2, "Three Addends", s2)}
{sec(3, "Find the Error", s3)}
{sec(4, "Convert to Column", s4)}
{sec(5, "Challenge: Create Your Own", s5)}''')
# ═══════════════════════════════════════════════════
# THURSDAY — Word Problems with Regrouping
# ═══════════════════════════════════════════════════
def thursday():
# 1: Better word problems — reasoning, not keywords (reduced from 4 to 3)
s1 = '<div class="wp">'
s1 += '<p class="note">Read carefully. Think about what is happening in the situation.</p>'
s1 += '<div class="mgrid c2">'
problems = [
("Emma collected 28 seashells on the beach on Saturday. On Sunday, she found 35 more while walking her dog. She put all her seashells in her collection box. How many seashells are in the box now?", 28, 35, "seashells"),
("The school library had 47 picture books last week. This week, the librarian ordered 36 new ones to add to the shelf. How many picture books are there now?", 47, 36, "picture books"),
("During soccer practice, Jake scored 58 goals in the morning game. In the afternoon game, he scored 48 more goals. How many goals did Jake score that day?", 58, 48, "goals"),
]
for text, a, c, unit in problems:
s1 += f'<div class="abox"><p style="font-size:0.95em;">{text}</p>'
s1 += '<p style="font-size:11px;">Draw or write your thinking: ' + bw() + '</p>'
s1 += '<p>' + b("6em") + f' {unit}</p></div>'
s1 += '</div></div>'
# 2: Two-step word problems (reduced from 2 to 1)
s2 = '<div class="abox">'
s2 += '<p class="note">Solve step by step. Write each answer as you go.</p>'
s2 += build_two_step_problems({
"problems": [
{
"text": "Sarah has 28 stickers. Her friend Tom gives her 35 stickers. Then her mom gives her 27 more stickers for her birthday. How many stickers does Sarah have now?",
"step1_label": "Step 1: After Tom's stickers",
"step2_label": "Step 2: After Mom's stickers",
"final_label": "Total stickers"
}
],
"note": "Solve each step carefully."
})
s2 += '</div>'
# 3: NEW — Number Talk: Compare sums WITHOUT calculating
s3 = '<div class="abox" style="background:#e3f2fd;">'
s3 += '<p><b>Number Talk</b> — Explain WITHOUT calculating.</p>'
s3 += '<div class="mgrid c2">'
s3 += '<div class="abox"><p>A: 38 + 49</p><p>B: 48 + 39</p><p>Which sum is bigger, or are they the same?</p><p style="font-size:11px;">My thinking: ' + bw() + '</p></div>'
s3 += '<div class="abox"><p>A: 26 + 57</p><p>B: 27 + 56</p><p>Which sum is bigger, or are they the same?</p><p style="font-size:11px;">My thinking: ' + bw() + '</p></div>'
s3 += '</div></div>'
# 4: Create your own word problem (open-ended challenge)
s4 = '<div class="abox" style="background:#f3e5f5;">'
s4 += '<p><b>Create Your Own Word Problem</b></p>'
s4 += '<p>Write an addition word problem about something you like (sports, animals, games, food, etc.). Make sure it needs regrouping. Then solve it.</p>'
s4 += '<p style="min-height:60px; border-bottom:1px solid #333;"></p>'
s4 += '<p style="min-height:30px; border-bottom:1px solid #333;"></p>'
s4 += '<p style="font-size:11px;">My thinking: ' + bw() + '</p>'
s4 += '<p>Answer: ' + bl() + '</p>'
s4 += '</div>'
return page(9, "Thursday", "Word Problems with Regrouping",
f'''{sec(1, "Word Problems: Think About What Is Happening", s1)}
{sec(2, "Two-Step Problem", s2)}
{sec(3, "Number Talk: Compare Sums", s3)}
{sec(4, "Challenge: Create Your Own", s4)}''')
# ═══════════════════════════════════════════════════
# FRIDAY — Review & Self-Check
# ═══════════════════════════════════════════════════
def friday():
# 1: Mental math warm-up (reduced from 8 to 4)
s1 = '<p class="note">Solve in your head. Go fast!</p>'
s1 += '<div class="mgrid c3">'
for a, c in [(29, 11), (38, 12), (47, 13), (56, 14)]:
s1 += f'<div class="abox"><p>{a} + {c} = {b("4em")}</p></div>'
s1 += '</div>'
# 2: Estimation warm-up (NEW — replaced timed quiz)
s2 = '<div class="abox" style="background:#fff3e0;">'
s2 += '<p><b>Estimate First!</b> Round to tens, estimate, then solve.</p>'
s2 += '<div class="mgrid c2">'
for a, c in [(38, 47), (62, 39), (54, 39), (26, 67)]:
at = (a + 5) // 10 * 10
ct = (c + 5) // 10 * 10
s2 += f'<div class="abox"><p><b>{a} + {c}</b></p>'
s2 += f'<p>Estimate ({at} + {ct}): ' + b('4em') + '</p>'
s2 += f'<p>Actual: ' + b('4em') + '</p></div>'
s2 += '</div></div>'
# 3: Mixed column addition review (reduced from 6 to 4)
s3 = '<p class="note">Use any strategy you prefer.</p>'
s3 += build_column_addition({
"problems": [(38, 47), (62, 39), (54, 39), (26, 67)],
"digits": 2,
"note": "Review: Column addition with regrouping."
})
# 4: Word problem review (reduced from 3 to 2)
s4 = '<div class="wp">'
s4 += '<p class="note">Read carefully. Show your work.</p>'
s4 += '<div class="mgrid c2">'
problems = [
("A class has 28 boys and 29 girls. The teacher wants to know how many students are in the whole class. How many students are there?", 28, 29, "students"),
("Mom bought 38 red apples and 47 green apples at the market. She wants to know the total number of apples. How many apples did she buy?", 38, 47, "apples"),
]
for text, a, c, unit in problems:
s4 += f'<div class="abox"><p style="font-size:0.95em;">{text}</p>'
s4 += '<p style="font-size:11px;">Draw or write your thinking: ' + bw() + '</p>'
s4 += '<p>' + b("6em") + f' {unit}</p></div>'
s4 += '</div></div>'
# 5: NEW — Self-check with emoji reflection (replaces timed quiz)
s5 = '<div class="selfcheck">'
s5 += '<p><b>Self-Check: How do you feel about adding with regrouping?</b></p>'
s5 += '<div style="display:flex; gap:20px; flex-wrap:wrap;">'
s5 += '<div style="background:#fff3e0; padding:10px; border-radius:5px; flex:1; min-width:150px;">'
s5 += '<p><b>Visual Regrouping</b></p>'
s5 += '<p>😊 I got it! | 😐 Getting there | 😟 Need help</p>'
s5 += '</div>'
s5 += '<div style="background:#e3f2fd; padding:10px; border-radius:5px; flex:1; min-width:150px;">'
s5 += '<p><b>Column Addition with Carry</b></p>'
s5 += '<p>😊 I got it! | 😐 Getting there | 😟 Need help</p>'
s5 += '</div>'
s5 += '<div style="background:#f3e5f5; padding:10px; border-radius:5px; flex:1; min-width:150px;">'
s5 += '<p><b>Word Problems with Regrouping</b></p>'
s5 += '<p>😊 I got it! | 😐 Getting there | 😟 Need help</p>'
s5 += '</div>'
s5 += '</div>'
s5 += '<p style="margin-top:10px;"><b>One thing I learned this week:</b> ' + bl() + '</p>'
s5 += '<p><b>One thing I want to practice more:</b> ' + bl() + '</p>'
s5 += '<p><b>My favorite strategy for adding with regrouping:</b> ' + bl() + '</p>'
s5 += '</div>'
return page(9, "Friday", "Week 9 Review & Self-Check",
f'''{sec(1, "Mental Math Warm-up", s1)}
{sec(2, "Estimate First!", s2)}
{sec(3, "Column Addition Review", s3)}
{sec(4, "Word Problems", s4)}
{sec(5, "Self-Check & Reflection", s5)}''')
# ═══════════════════════════════════════════════════
# TEACHER GUIDE — Combined for all days
# ═══════════════════════════════════════════════════
def teacher_guide():
"""Generate combined teacher guide for all 5 days."""
return tg_page_multi(
"Week 9", "Addition with Regrouping — Teacher Guide",
# Monday
tg_section_title("Monday: Introduction to Regrouping (Visual)") +
tg_sec(1, "Visual Regrouping", ["28+35=63, 47+26=73"]) +
tg_sec(2, "Simple Regrouping", ["63, 73, 83, 85"]) +
tg_sec(3, "Predict Regrouping", ["23+45=no, 28+35=yes, 41+56=no, 39+44=yes"]) +
tg_sec(4, "Number Talk", ["28+45 is bigger (adding more to same number)", "47+26 is bigger (starting with more)"]) +
tg_sec(5, "Challenge", ["38+46=84, 57+35=92"]) +
tg_note("Page break"),
# Tuesday
tg_section_title("Tuesday: Column Addition with Regrouping") +
tg_sec(1, "Carry the 1", ["63, 73, 83, 85"]) +
tg_sec(2, "Estimation", ["Est 30+40=70, actual 63 / Est 50+60=110, actual 103 / Est 70+30=100, actual 97 / Est 80+50=130, actual 123"]) +
tg_sec(3, "Step-by-Step", ["63, 73"]) +
tg_sec(4, "Strategies", ["97, 94, 96, 103"]) +
tg_sec(5, "Number Talk", ["39+25=64 (one more)", "57+26=83 (ten more)"]) +
tg_note("Page break"),
# Wednesday
tg_section_title("Wednesday: Mixed Regrouping Practice") +
tg_sec(1, "Mixed", ["68(no), 63(yes), 97(no), 83(yes)"]) +
tg_sec(2, "Three Addends", ["77, 92"]) +
tg_sec(3, "Find Error", ["28+35=63 not 53 (forgot to carry 1)", "58+39=97 not 87 (forgot to carry 1)"]) +
tg_sec(4, "Convert to Column", ["105, 105"]) +
tg_sec(5, "Create Own", ["Various — any column addition needing regrouping"]) +
tg_note("Page break"),
# Thursday
tg_section_title("Thursday: Word Problems with Regrouping") +
tg_sec(1, "Word Problems", ["63 seashells, 83 picture books, 106 goals"]) +
tg_sec(2, "Two-Step", ["Step 1: 28+35=63, Step 2: 63+27=90 stickers"]) +
tg_sec(3, "Number Talk", ["Same sum (38+49 = 48+39 = 87)", "Same sum (26+57 = 27+56 = 83)"]) +
tg_sec(4, "Create Own", ["Accept student-created problems with regrouping"]) +
tg_note("Page break"),
# Friday
tg_section_title("Friday: Review & Self-Check") +
tg_sec(1, "Mental Math", ["40, 50, 60, 70"]) +
tg_sec(2, "Estimation", ["Est 40+50=90, actual 85 / Est 60+40=100, actual 101 / Est 50+40=90, actual 93 / Est 30+70=100, actual 93"]) +
tg_sec(3, "Column Review", ["85, 101, 93, 93"]) +
tg_sec(4, "Word Problems", ["57 students, 85 apples"]) +
tg_sec(5, "Self-Check", ["Accept student self-assessment and reflection"])
)
# ═══════════════════════════════════════════════════
# GENERATE
# ═══════════════════════════════════════════════════
if __name__ == "__main__":
# Clean old files
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", "Introduction to Regrouping (Visual)"),
(tuesday, "Tuesday", "Column Addition with Regrouping"),
(wednesday, "Wednesday", "Mixed Regrouping Practice"),
(thursday, "Thursday", "Word Problems with Regrouping"),
(friday, "Friday", "Week 9 Review & Self-Check"),
]
# Generate student worksheets
for lesson_func, day, title in days:
html = lesson_func()
fname = f"Week_9_{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}")
# Generate combined teacher guide
html = teacher_guide()
path = os.path.join(WEEK, "Week_9_Teacher_Guide.html")
with open(path, "w") as f:
f.write(html)
pdf_path = os.path.join(WEEK, "Week_9_Teacher_Guide.pdf")
HTML(filename=path).write_pdf(pdf_path)
print(f"Generated: {pdf_path}")
print("\nWeek 9 (rewritten to new standard) complete!")