#!/usr/bin/env python3
"""
Week 9: Addition with Regrouping
Phase 2: Addition & Subtraction to 100
"""
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_grid_answers, tg_note, tg_section_title,
)
from activity_builders import (
build_column_addition,
build_regrouping_visual,
)
BASE = os.path.expanduser("~/Home_School/2nd_Grade/Math")
WEEK = os.path.join(BASE, "Week_9")
def ensure_week_dir():
os.makedirs(WEEK, exist_ok=True)
for f in glob.glob(os.path.join(WEEK, "*.pdf")):
os.remove(f)
# ═══════════════════════════════════════════════════
# MONDAY — Introduction to Regrouping (Visual)
# ═══════════════════════════════════════════════════
def monday():
# 1: Visual regrouping with base-10 blocks
s1 = '<p class="note">When ones add to 10 or more, we <b>regroup</b>: 10 ones = 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 problems (horizontal)
s2 = '<p class="note">Add the ones. If you get 10 or more, regroup. Then add the tens.</p>'
s2 += '<div class="mgrid c3">'
problems = [(28, 35), (47, 26), (39, 44), (58, 27), (67, 18), (49, 35)]
for a, c in problems:
s2 += f'<div class="abox"><p>{a} + {c} = {b("5em")}</p></div>'
s2 += '</div>'
# 3: Step-by-step regrouping
s3 = '<p class="note">Show your work: add ones, regroup if needed, add tens.</p>'
s3 += '<div class="mgrid c2">'
for a, c in [(28, 35), (47, 26), (39, 44)]:
ao, at = a % 10, a // 10
co, ct = c % 10, c // 10
s3 += f'<div class="abox"><p><b>{a} + {c}</b></p>'
s3 += f'<p>Ones: {ao} + {co} = ' + b("4em") + ' (regroup: <span class="bw">__</span> ten, <span class="bw">__</span> ones)</p>'
s3 += f'<p>Tens: {at} + {ct} = ' + b("4em") + '0</p>'
s3 += '<p><b>Total: </b>' + b("5em") + '</p></div>'
s3 += '</div>'
# 4: Number line with regrouping
s4 = '<p class="note">Use the number line. Jump by tens, then by ones.</p>'
s4 += '<div class="mgrid c2">'
for a, t in [(28, 35), (47, 26)]:
s4 += f'<div class="abox"><p style="font-size:1.1em;"><b>{a} + {t} = {b("5em")}</b></p>'
start_tick = (a // 10) * 10
end_tick = start_tick + 80
s4 += '<div style="position:relative; height:50px; margin-top:20px;">'
s4 += '<div style="position:absolute; left:0; right:0; top:25px; height:3px; background:#333;"></div>'
for tick in range(start_tick, end_tick + 10, 10):
left_pct = ((tick - start_tick) / 80) * 100
s4 += f'<div style="position:absolute; left:{left_pct}%; top:20px; height:10px; width:2px; background:#333;"></div>'
s4 += f'<div style="position:absolute; left:{left_pct}%; top:32px; transform:translateX(-50%); font-size:0.85em;">{tick}</div>'
s4 += '</div>'
s4 += f'<p style="font-size:0.85em; color:#666; margin-top:10px;">Start at {a}, jump +30, then +5</p>'
s4 += '</div>'
s4 += '</div>'
# 5: Challenge — predict if regrouping is needed
s5 = '<p class="note">Look at the ones. Will you need to regroup? Write yes or no.</p>'
s5 += '<div class="mgrid c3">'
for a, c in [(23, 45), (28, 35), (41, 56), (39, 44), (52, 27), (49, 35)]:
s5 += f'<div class="abox"><p>{a} + {c}: Regroup? <span class="bw">______</span></p></div>'
s5 += '</div>'
return page(9, "Monday", "Introduction to Regrouping",
f'''{sec(1, "Visual Regrouping", s1)}
{sec(2, "Simple Regrouping", s2)}
{sec(3, "Step-by-Step Regrouping", s3)}
{sec(4, "Number Line", s4)}'''
)
# ═══════════════════════════════════════════════════
# TUESDAY — Column Addition with Regrouping
# ═══════════════════════════════════════════════════
def tuesday():
# 1: Column addition with regrouping (carry the 1)
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), (67, 18), (49, 35)],
"digits": 2,
"note": "Don't forget to add the carried 1 to the tens column!"
})
# 2: More column practice
s2 = build_column_addition({
"problems": [(78, 19), (56, 38), (69, 27), (87, 16), (45, 68), (39, 75)],
"digits": 2,
"note": "Keep carrying that 1!"
})
# 3: Step-by-step with regrouping explanation
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: Find the error (regrouping mistakes)
s4 = '<p class="note">One of these has a regrouping error. Find it!</p>'
s4 += '<div class="mgrid c3">'
# Wrong: 28+35 should be 63, not 53 (forgot to carry)
s4 += '<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></div>'
# Correct: 47+26=73
s4 += '<div class="abox"><p style="text-align:center;"> 47</p><p style="text-align:center;">+ 26</p><hr><p style="text-align:center;"> 73</p><p>✓ or ✗?</p></div>'
# Wrong: 39+44 should be 83, not 73
s4 += '<div class="abox"><p style="text-align:center;"> 39</p><p style="text-align:center;">+ 44</p><hr><p style="text-align:center;"> 73</p><p>✓ or ✗?</p></div>'
s4 += '</div>'
# 5: Challenge — larger sums
s5 = '<p class="note">These sums are bigger. Still carry the 1!</p>'
s5 += '<div class="mgrid c3">'
for a, c in [(59, 48), (68, 39), (79, 28), (87, 46), (95, 38), (76, 59)]:
s5 += f'<div class="abox"><p>{a} + {c} = {b("5em")}</p></div>'
s5 += '</div>'
return page(9, "Tuesday", "Column Addition with Regrouping",
f'''{sec(1, "Carry the 1", s1)}
{sec(2, "More Practice", s2)}
{sec(3, "Step-by-Step", s3)}
{sec(4, "Find the Error", s4)}
{sec(5, "Challenge", s5)}'''
)
# ═══════════════════════════════════════════════════
# WEDNESDAY — Mixed Regrouping Practice
# ═══════════════════════════════════════════════════
def wednesday():
# 1: Mixed — some regroup, some don't
s1 = '<p class="note">Decide: does this need regrouping? 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), (52, 27), (64, 23)]:
s1 += f'<div class="abox"><p>{a} + {c} = {b("5em")}</p></div>'
s1 += '</div>'
# 2: Column addition (all regroup)
s2 = build_column_addition({
"problems": [(58, 39), (67, 48), (79, 26), (85, 38), (49, 56), (68, 47)],
"digits": 2,
"note": "All of these need regrouping. Watch for the carried 1!"
})
# 3: Three addends (with regrouping)
s3 = '<p class="note">Add ones column first. Regroup if needed. Then tens.</p>'
s3 += '<div class="mgrid c3">'
for a, c, e in [(28, 35, 14), (47, 26, 19), (39, 24, 35)]:
s3 += f'<div class="abox" style="text-align:center;">'
s3 += f'<p style="font-size:1.3em; letter-spacing:3px;"> {a}</p>'
s3 += f'<p style="font-size:1.3em; letter-spacing:3px;">+ {c}</p>'
s3 += f'<p style="font-size:1.3em; letter-spacing:3px;">+ {e}</p>'
s3 += '<hr style="border:2px solid #333;">'
s3 += f'<p style="font-size:1.3em; letter-spacing:3px;"> {b("4em")}</p>'
s3 += '</div>'
s3 += '</div>'
# 4: Horizontal to column conversion
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), (74, 29), (58, 37)]:
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 — find the error (regrouping focus)
s5 = '<p class="note">Find the errors. Some forgot to carry, some carried in wrong place.</p>'
s5 += '<div class="mgrid c3">'
# Wrong: 58+39 should be 97, not 87
s5 += '<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></div>'
# Correct: 67+48=115
s5 += '<div class="abox"><p style="text-align:center;"> 67</p><p style="text-align:center;">+ 48</p><hr><p style="text-align:center;"> 115</p><p>✓ or ✗?</p></div>'
# Wrong: 79+26 should be 105, not 95
s5 += '<div class="abox"><p style="text-align:center;"> 79</p><p style="text-align:center;">+ 26</p><hr><p style="text-align:center;"> 95</p><p>✓ or ✗?</p></div>'
s5 += '</div>'
return page(9, "Wednesday", "Mixed Regrouping Practice",
f'''{sec(1, "Mixed Practice", s1)}
{sec(2, "Column Addition", s2)}
{sec(3, "Three Addends", s3)}
{sec(4, "Convert to Column", s4)}
{sec(5, "Find the Error", s5)}'''
)
# ═══════════════════════════════════════════════════
# THURSDAY — Word Problems with Regrouping
# ═══════════════════════════════════════════════════
def thursday():
# 1: Simple word problems (all require regrouping)
s1 = '<p class="note">Read, circle numbers, choose operation, solve. Watch for regrouping!</p>'
s1 += '<div class="mgrid c2">'
problems = [
("Emma collected 28 shells on Monday and 35 on Tuesday. How many shells total?", 28, 35, "shells"),
("The library has 47 fiction books and 36 non-fiction books. How many books total?", 47, 36, "books"),
("Jake scored 58 points in game 1 and 48 points in game 2. How many points total?", 58, 48, "points"),
("A farmer has 69 chickens and 28 ducks. How many birds?", 69, 28, "birds"),
]
for text, a, c, unit in problems:
s1 += f'<div class="abox"><p style="font-size:0.95em;">{text}</p>'
s1 += '<p>' + b("6em") + f' {unit}</p></div>'
s1 += '</div>'
# 2: Draw a picture problems
s2 = '<p class="note">Draw a picture or use base-10 blocks to help you solve.</p>'
s2 += '<div class="mgrid c2">'
problems = [
("Tom has 39 red marbles and 48 blue marbles. How many marbles?", 39, 48),
("A bakery sold 58 cupcakes in the morning and 37 in the afternoon. Total?", 58, 37),
]
for text, a, c in problems:
s2 += f'<div class="abox"><p style="font-size:0.95em;">{text}</p>'
s2 += '<p style="min-height:80px; border:1px dashed #999; margin:10px 0;"></p>'
s2 += '<p>' + b("6em") + '</p></div>'
s2 += '</div>'
# 3: Compare two problems
s3 = '<p class="note">Solve both. Which is bigger? Circle it.</p>'
s3 += '<div class="mgrid c2">'
s3 += '<div class="abox"><p>A: 38 + 49 = ' + b("5em") + '</p>'
s3 += '<p>B: 52 + 38 = ' + b("5em") + '</p>'
s3 += '<p>Which is bigger? <span class="bw">A</span> or <span class="bw">B</span></p></div>'
s3 += '<div class="abox"><p>A: 67 + 29 = ' + b("5em") + '</p>'
s3 += '<p>B: 48 + 47 = ' + b("5em") + '</p>'
s3 += '<p>Which is bigger? <span class="bw">A</span> or <span class="bw">B</span></p></div>'
s3 += '</div>'
# 4: Two-step problems
s4 = '<p class="note">Solve step by step. Watch for regrouping in each step!</p>'
s4 += '<div class="mgrid c2">'
problems = [
("Sarah has 28 stickers. Tom gives her 35. Then Mom gives her 27 more. How many now?", [(28, 35), ("result", 27)]),
("A store had 47 apples. They got 38 more. Then sold 15. How many left?", [(47, 38), ("result", -15)]),
]
for text, steps in problems:
s4 += f'<div class="abox"><p style="font-size:0.95em;">{text}</p>'
s4 += '<p>Step 1: ' + b("6em") + '</p>'
s4 += '<p>Step 2: ' + b("6em") + '</p></div>'
s4 += '</div>'
# 5: Create your own
s5 = '<p class="note">Write your own addition word problem that needs regrouping. Then solve it.</p>'
s5 += '<div class="abox"><p style="min-height:60px; border-bottom:1px solid #333;"></p>'
s5 += '<p>Answer: ' + bl() + '</p></div>'
return page(9, "Thursday", "Word Problems with Regrouping",
f'''{sec(1, "Word Problems", s1)}
{sec(2, "Draw a Picture", s2)}
{sec(3, "Compare Sums", s3)}
{sec(4, "Two-Step Problems", s4)}
{sec(5, "Create Your Own", s5)}'''
)
# ═══════════════════════════════════════════════════
# FRIDAY — Review & Self-Check (Regrouping)
# ═══════════════════════════════════════════════════
def friday():
# 1: Mental math warm-up (easy regrouping)
s1 = '<p class="note">Solve in your head. These are easier regrouping problems.</p>'
s1 += '<div class="mgrid c4">'
for a, c in [(29, 11), (38, 12), (47, 13), (56, 14), (69, 11), (78, 12), (87, 13), (96, 14)]:
s1 += f'<div class="abox"><p>{a} + {c} = {b("4em")}</p></div>'
s1 += '</div>'
# 2: Column addition review (all regroup)
s2 = build_column_addition({
"problems": [(38, 47), (62, 39), (43, 58), (71, 29), (54, 39), (26, 67)],
"digits": 2,
"note": "Review: Column addition with regrouping."
})
# 3: Mixed horizontal
s3 = '<p class="note">Use any strategy you prefer.</p>'
s3 += '<div class="mgrid c3">'
for a, c in [(47, 58), (36, 69), (74, 29), (58, 37), (29, 48), (63, 29)]:
s3 += f'<div class="abox"><p>{a} + {c} = {b("5em")}</p></div>'
s3 += '</div>'
# 4: Word problem review
s4 = '<p class="note">Read carefully. Show your work.</p>'
s4 += '<div class="mgrid c2">'
problems = [
("A class has 28 boys and 29 girls. How many students?", 28, 29, "students"),
("Mom bought 38 apples and 47 oranges. How many fruits?", 38, 47, "fruits"),
("Jake read 48 pages on Monday and 39 pages on Tuesday. Total pages?", 48, 39, "pages"),
]
for text, a, c, unit in problems:
s4 += f'<div class="abox"><p style="font-size:0.95em;">{text}</p>'
s4 += '<p>' + b("6em") + f' {unit}</p></div>'
s4 += '</div>'
# 5: Self-check quiz
s5 = '<p class="note">Time yourself! How many can you do in 5 minutes?</p>'
s5 += '<div class="mgrid c4">'
facts = [(28, 35), (47, 26), (39, 44), (58, 27), (67, 18), (49, 35), (59, 48), (68, 39)]
for a, c in facts:
s5 += f'<div class="abox"><p>{a} + {c} = {b("4em")}</p></div>'
s5 += '</div>'
s5 += '<p>I got _____ out of 8 correct.</p>'
s5 += '<p>One thing I want to practice more: ' + bl() + '</p>'
return page(9, "Friday", "Week 9 Review & Self-Check",
f'''{sec(1, "Mental Math Warm-up", s1)}
{sec(2, "Column Addition Review", s2)}
{sec(3, "Mixed Practice", s3)}
{sec(4, "Word Problems", s4)}
{sec(5, "Self-Check Quiz", s5)}'''
)
# ═══════════════════════════════════════════════════
# TEACHER GUIDE
# ═══════════════════════════════════════════════════
def monday_tg():
return tg_page_multi(9, "Monday", "Introduction to Regrouping",
f'''{tg_section_title("Key Concept: When Ones Add to 10+, We Regroup")}
{tg_note("28 + 35: 8 + 5 = 13. We regroup 10 ones as 1 ten. Write 3 in ones place, carry 1 to tens.")}
{tg_note("Teach: Use base-10 blocks. Show 13 unit cubes becoming 1 rod + 3 cubes.")}
{tg_section_title("Activity Answers")}
{tg_note("1. Visual: 28+35=63, 47+26=73")}
{tg_note("2. Simple: 63, 73, 83, 85, 85, 84")}
{tg_note("3. Step-by-step: 63, 73, 83")}
{tg_note("5. Predict: 23+45=no, 28+35=yes, 41+56=no, 39+44=yes, 52+27=yes, 49+35=yes")}
{tg_section_title("Common Misconceptions")}
{tg_note("Students may forget to add the carried 1. Have them circle it in red.")}
{tg_note("Some add the 1 to the ones column instead of tens. Use color-coding.")}
'''
)
def tuesday_tg():
return tg_page_multi(9, "Tuesday", "Column Addition with Regrouping",
f'''{tg_section_title("Key Concept: Carry the 1")}
{tg_note("Teach the language: 'I carry the 1' or 'I regroup 1 ten.'")}
{tg_note("Show: Write the carried 1 small above the tens column as a reminder.")}
{tg_section_title("Activity Answers")}
{tg_note("1. Carry the 1: 63, 73, 83, 85, 85, 84")}
{tg_note("2. More practice: 97, 94, 96, 103, 113, 114")}
{tg_note("3. Step-by-step: 63, 73")}
{tg_note("4. Find error: 28+35=63 (not 53), 39+44=83 (not 73)")}
{tg_note("5. Challenge: 107, 107, 107, 133, 133, 135")}
{tg_section_title("Strategy Tips")}
{tg_note("Emphasize: Always start with ones column. Write the carried 1 before forgetting!")}
{tg_note("For students who struggle, use graph paper to keep columns aligned.")}
'''
)
def wednesday_tg():
return tg_page_multi(9, "Wednesday", "Mixed Regrouping Practice",
f'''{tg_section_title("Key Concept: Decide Before You Solve")}
{tg_note("Teach students to look at ones digits first: Do they add to 10 or more?")}
{tg_note("This prediction skill helps them catch errors.")}
{tg_section_title("Activity Answers")}
{tg_note("1. Mixed: 68, 63, 97, 83, 79, 87")}
{tg_note("2. Column: 97, 115, 105, 123, 105, 115")}
{tg_note("3. Three addends: 77, 92, 98")}
{tg_note("4. Convert: 105, 105, 103, 95")}
{tg_note("5. Find error: 58+39=97 (not 87), 79+26=105 (not 95)")}
{tg_section_title("Common Errors")}
{tg_note("Forgetting to carry when ones sum to 10+. Have student mark ones digits in color.")}
{tg_note("Adding carried 1 to wrong column. Practice saying: '1 ten goes in tens place.'")}
'''
)
def thursday_tg():
return tg_page_multi(9, "Thursday", "Word Problems with Regrouping",
f'''{tg_section_title("Key Concept: Regrouping in Real Context")}
{tg_note("Word problems help students see regrouping as useful, not just abstract.")}
{tg_note("Teach: After solving, ask 'Does this answer make sense?'")}
{tg_section_title("Activity Answers")}
{tg_note("1. Word problems: 63 shells, 83 books, 106 points, 97 birds")}
{tg_note("2. Draw: 87 marbles, 95 cupcakes")}
{tg_note("3. Compare: A=87, B=90 (B bigger); A=96, B=95 (A bigger)")}
{tg_note("4. Two-step: 90 stickers (28+35=63, 63+27=90); 70 apples (47+38=85, 85-15=70)")}
{tg_section_title("Scaffolding")}
{tg_note("For struggling readers, read problems aloud together.")}
{tg_note("Have student circle both numbers and the question word (total, how many, etc.).")}
'''
)
def friday_tg():
return tg_page_multi(9, "Friday", "Week 9 Review",
f'''{tg_section_title("Review Goals")}
{tg_note("By end of Week 9, student should confidently add 2-digit numbers with regrouping using column method.")}
{tg_section_title("Activity Answers")}
{tg_note("1. Mental math: 40, 50, 60, 70, 80, 90, 100, 110")}
{tg_note("2. Column review: 85, 101, 101, 100, 93, 93")}
{tg_note("3. Mixed: 105, 105, 103, 95, 77, 92")}
{tg_note("4. Word problems: 57 students, 85 fruits, 87 pages")}
{tg_note("5. Self-check: 63, 73, 83, 85, 85, 84, 107, 107")}
{tg_section_title("Assessment Notes")}
{tg_note("If student struggles with regrouping, return to base-10 blocks for concrete practice.")}
{tg_note("Celebrate progress! Regrouping is a major milestone in addition.")}
{tg_note("Week 10 will introduce subtraction with regrouping — the inverse operation.")}
'''
)
# ═══════════════════════════════════════════════════
# MAIN
# ═══════════════════════════════════════════════════
if __name__ == "__main__":
ensure_week_dir()
# Student worksheets
HTML(string=monday()).write_pdf(os.path.join(WEEK, "Week_9_Monday.pdf"))
HTML(string=tuesday()).write_pdf(os.path.join(WEEK, "Week_9_Tuesday.pdf"))
HTML(string=wednesday()).write_pdf(os.path.join(WEEK, "Week_9_Wednesday.pdf"))
HTML(string=thursday()).write_pdf(os.path.join(WEEK, "Week_9_Thursday.pdf"))
HTML(string=friday()).write_pdf(os.path.join(WEEK, "Week_9_Friday.pdf"))
# Teacher guide - combine all days
tg_html = tg_page_multi(9, "Week 9 Teacher Guide",
monday_tg().split('<body>')[1].rsplit('</body>', 1)[0],
tuesday_tg().split('<body>')[1].rsplit('</body>', 1)[0],
wednesday_tg().split('<body>')[1].rsplit('</body>', 1)[0],
thursday_tg().split('<body>')[1].rsplit('</body>', 1)[0],
friday_tg().split('<body>')[1].rsplit('</body>', 1)[0]
)
HTML(string=tg_html).write_pdf(os.path.join(WEEK, "Week_9_Teacher_Guide.pdf"))
print(f"Week 9 generated: 6 PDFs in {WEEK}")