#!/usr/bin/env python3
"""
Week 31: Final Review โ REWRITTEN
Phase: Final Review (the last SERIOUS review week โ Week 32 is the celebration)
Standards: All 2nd grade domains reviewed โ 2.OA (add/subtract, odd/even, arrays),
2.NBT (place value, 3-digit +/โ), 2.MD (length, time, money), 2.G (shapes, partitions)
New Standard:
- Reduced drill (40% fewer problems)
- Estimation before calculating
- Multiple strategies encouraged
- Better word problems (reasoning over keywords)
- Real challenges (open-ended thinking)
- Number talks (compare without calculating)
- Friday self-check with reflection
- Fact fluency warmup daily
- 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,
col_add_inline, col_sub_inline,
clock_svg, coin_svg, shape_svg, array_svg,
ruler_cm, measure_line,
)
from activity_builders import (
build_challenge_box,
)
BASE = os.path.expanduser("~/Home_School/2nd_Grade/Math")
WEEK = os.path.join(BASE, "Week_31")
BLUE = "#1e88e5"
RED = "#e53935"
GREEN = "#43a047"
def warmup(exprs):
s = '<div class="abox" style="background:#e8f5e9;">'\
'<p><b>2-min Fluency Warm-up</b> โ Solve in your head.</p>'\
'<div class="mgrid c3">'
for expr in exprs:
s += f'<div class="abox"><p>{expr} = {b("4em")}</p></div>'
s += '</div></div>'
return s
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# MONDAY โ Place Value & Number Sense Review
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
def monday():
s1 = warmup(["9 + 7", "15 โ 6", "8 + 8", "13 โ 4"])
# 2: Place value review (reduced from 8 to 4)
s2 = '<div class="abox">'\
'<p class="note">Remember: 347 = 3 hundreds, 4 tens, 7 ones.</p>'\
'<div class="mgrid c2">'
s2 += '<div class="abox"><p>In 582, the 8 means ' + b("5em") + '</p></div>'
s2 += '<div class="abox"><p>Expanded form: 316 = ' + b("5em") + ' + ' + b("5em") + ' + ' + b("3em") + '</p></div>'
s2 += '<div class="abox"><p>Write the number: 700 + 40 + 9 = ' + b("4em") + '</p></div>'
s2 += '<div class="abox"><p>Compare: 438 ' + b("3em") + ' 483 (<, >, =)</p></div>'
s2 += '</div></div>'
# 3: Number Talk โ compare without calculating
s3 = '<div class="abox" style="background:#e3f2fd;">'\
'<p><b>Number Talk</b> โ Explain WITHOUT calculating.</p>'\
'<div class="mgrid c2">'
s3 += '<div class="abox"><p>Which is bigger: <b>399 + 10</b> or <b>410</b>? How do you know without adding?</p>'\
'<p style="font-size:11px;">My thinking: ' + bw() + '</p></div>'
s3 += '<div class="abox"><p>Marisol says 205 is bigger than 250 because "5 is bigger than 0." Is she right? Why or why not?</p>'\
'<p style="font-size:11px;">My thinking: ' + bw() + '</p></div>'
s3 += '</div></div>'
# 4: Skip counting review (reduced from 6 to 3)
s4 = '<div class="abox">'\
'<p class="note">Fill in the missing numbers.</p>'\
'<div class="mgrid c1">'
s4 += '<div class="abox"><p>Count by 10s: 217, 227, ' + b("3em") + ', 247, ' + b("3em") + '</p></div>'
s4 += '<div class="abox"><p>Count by 100s: 145, 245, ' + b("3em") + ', ' + b("3em") + ', 545</p></div>'
s4 += '<div class="abox"><p>Count by 5s: 480, 485, ' + b("3em") + ', 495, ' + b("3em") + '</p></div>'
s4 += '</div></div>'
# 5: Word problem
s5 = '<div class="wp">'\
'<p class="note">Read carefully. Think about what is happening. Draw if it helps!</p>'\
'<div class="abox"><p style="font-size:0.95em;">The school library has 264 picture books. '\
'The number of chapter books is 100 more than the picture books. How many chapter books are there? '\
'How many books is that in all?</p>'\
'<p style="font-size:11px;">Draw or write your thinking: ' + bw() + '</p>'\
'<p>Chapter books: ' + b("4em") + ' Total: ' + b("4em") + '</p></div></div>'
return page(31, "Monday", "Place Value & Number Sense Review",
f'''{sec(1, "Warm-up: Mental Math", s1)}
{sec(2, "Place Value Review", s2)}
{sec(3, "Number Talk: Compare Without Calculating", s3)}
{sec(4, "Skip Counting Review", s4)}
{sec(5, "Word Problem", s5)}''')
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# TUESDAY โ Addition & Subtraction Review
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
def tuesday():
s1 = warmup(["6 + 8", "14 โ 9", "7 + 9", "16 โ 7"])
# 2: Estimate First! before computing
s2 = '<div class="abox" style="background:#fff3e0;">'\
'<p><b>Estimate First!</b> Round to the nearest ten and estimate BEFORE you solve.</p>'\
'<div class="mgrid c2">'
for a_, b_, op in [(48, 34, "+"), (72, 29, "โ")]:
s2 += f'<div class="abox"><p>{a_} {op} {b_}</p>'\
f'<p>Estimate: {b("3em")} {op} {b("3em")} = {b("3em")}</p>'\
f'<p>Exact answer: {b("4em")}</p>'\
'<p style="font-size:11px;">Was your estimate close? ' + b("4em") + '</p></div>'
s2 += '</div></div>'
# 3: Mixed +/โ with regrouping (reduced from 10 to 4)
s3 = '<div class="abox">'\
'<p class="note">Solve. Watch out โ some need regrouping and some do not!</p>'\
'<div class="mgrid c2">'
s3 += f'<div class="abox">{col_add_inline(57, 26)}</div>'
s3 += f'<div class="abox">{col_sub_inline(83, 45)}</div>'
s3 += f'<div class="abox">{col_add_inline(38, 41)}</div>'
s3 += f'<div class="abox">{col_sub_inline(60, 27)}</div>'
s3 += '</div></div>'
# 4: Show two different ways
s4 = '<div class="abox">'\
'<p><b>Show two different ways</b> to solve <b>46 + 39</b>.</p>'\
'<p style="font-size:11px; color:#666;">Ideas: column addition, make a friendly number (39 + 1 = 40), break apart tens and ones, number line.</p>'\
'<div class="mgrid c2">'\
'<div class="abox"><p style="font-size:11px;">Way 1: ' + bw() + '</p><div style="min-height:50px;"></div></div>'\
'<div class="abox"><p style="font-size:11px;">Way 2: ' + bw() + '</p><div style="min-height:50px;"></div></div>'\
'</div><p>Answer: ' + b("4em") + '</p></div>'
# 5: Word problems (reduced from 4 to 2)
s5 = '<div class="wp">'\
'<p class="note">Read carefully. Think about what is happening in the situation.</p>'\
'<div class="mgrid c2">'
s5 += '<div class="abox"><p style="font-size:0.95em;">A bakery made 92 muffins. They sold 58 in the morning. '\
'Then they baked 25 more. How many muffins do they have now?</p>'\
'<p style="font-size:11px;">My thinking: ' + bw() + '</p><p>' + b("4em") + ' muffins</p></div>'
s5 += '<div class="abox"><p style="font-size:0.95em;">Kim has 35 stickers. Her goal is 70. Jo says she needs 45 more. '\
'Is Jo right? Prove it.</p>'\
'<p style="font-size:11px;">My thinking: ' + bw() + '</p><p>Jo is: right / wrong โ she needs ' + b("3em") + '</p></div>'
s5 += '</div></div>'
return page(31, "Tuesday", "Addition & Subtraction Review",
f'''{sec(1, "Warm-up: Mental Math", s1)}
{sec(2, "Estimate First!", s2)}
{sec(3, "Mixed Addition & Subtraction", s3)}
{sec(4, "Show Two Different Ways", s4)}
{sec(5, "Word Problems", s5)}''')
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# WEDNESDAY โ Measurement, Time & Money Review
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
def wednesday():
s1 = warmup(["25 + 25", "10 + 5 + 1", "50 โ 25", "10 + 10 + 5"])
# 2: Time review (reduced from 6 to 3)
s2 = '<p class="note">Write the time shown on each clock.</p>'\
'<div class="mgrid c3">'
for h, m in [(3, 15), (7, 40), (11, 5)]:
s2 += f'<div class="abox" style="text-align:center;">{clock_svg(h, m, 70)}'\
f'<p>{b("3em")} : {b("5em")}</p></div>'
s2 += '</div>'
# 3: Money review (reduced from 6 to 3)
s3 = '<p class="note">Count the coins. Write the total.</p>'\
'<div class="mgrid c1">'
coin_sets = [
(["quarter", "quarter", "dime", "penny"], 61),
(["quarter", "dime", "dime", "nickel", "penny"], 51),
(["quarter", "quarter", "quarter", "nickel"], 80),
]
for coins, _total in coin_sets:
row = ''.join(coin_svg(c, 26) for c in coins)
s3 += f'<div class="abox"><div style="display:flex; gap:6px; align-items:center;">{row}'\
f'<span style="margin-left:10px;">= {b("3em")}ยข</span></div></div>'
s3 += '</div>'
# 4: Estimate First! โ measurement
s4 = '<div class="abox" style="background:#fff3e0;">'\
'<p><b>Estimate First!</b> Estimate each line in cm, then measure with your ruler.</p>'\
'<div class="mgrid c2">'
for label, px in [("A.", 144), ("B.", 216)]:
s4 += f'<div class="abox"><div style="display:flex; align-items:center; gap:6px;">'\
f'<div class="measure-line" style="width:{px}px;"></div><span>{label}</span></div>'\
f'<p>Estimate: {b("3em")} cm Measured: {b("3em")} cm</p></div>'
s4 += '</div></div>'
# 5: Number Talk โ money reasoning
s5 = '<div class="abox" style="background:#e3f2fd;">'\
'<p><b>Number Talk</b> โ Explain WITHOUT counting every coin.</p>'\
'<p>Ben has 4 quarters. Ava has 9 dimes. Who has more money? '\
'How can you decide quickly, without counting cent by cent?</p>'\
'<p style="font-size:11px;">My thinking: ' + bw() + '</p>'\
'</div>'
return page(31, "Wednesday", "Measurement, Time & Money Review",
f'''{sec(1, "Warm-up: Coin Math", s1)}
{sec(2, "Telling Time", s2)}
{sec(3, "Counting Money", s3)}
{sec(4, "Estimate First: Measurement", s4)}
{sec(5, "Number Talk: Who Has More?", s5)}''')
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# THURSDAY โ Geometry, Arrays & Word Problems
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
def thursday():
s1 = warmup(["3 + 3 + 3", "5 + 5 + 5", "4 + 4", "2 + 2 + 2 + 2"])
# 2: Shape review (reduced from 6 to 4)
s2 = '<p class="note">Name each shape and count its sides and corners (vertices).</p>'\
'<div class="mgrid c2">'
for shp, color in [("triangle", GREEN), ("square", BLUE), ("rectangle", RED), ("star", "#fbc02d")]:
s2 += f'<div class="abox" style="text-align:center;">{shape_svg(shp, color, 40)}'\
f'<p>Name: {b("5em")}</p>'\
f'<p style="font-size:11px;">Sides: {b("3em")} Corners: {b("3em")}</p></div>'
s2 += '</div>'
# 3: Arrays & repeated addition (reduced from 5 to 3)
s3 = '<p class="note">Write the repeated addition for each array.</p>'\
'<div class="mgrid c3">'
for rows, cols in [(2, 4), (3, 3), (4, 5)]:
s3 += f'<div class="abox" style="text-align:center;">{array_svg(rows, cols, BLUE)}'\
f'<p style="font-size:11px;">{rows} rows of {cols}</p>'\
f'<p>Total: {b("3em")}</p></div>'
s3 += '</div>'
# 4: Word problems โ reasoning (reduced from 5 to 3)
s4 = '<div class="wp">'\
'<p class="note">Read carefully. Think about what is happening. Draw if it helps!</p>'\
'<div class="mgrid c2">'
problems = [
"A muffin tray has 3 rows with 6 muffins in each row. How many muffins fit on the tray?",
"Lila cuts a sandwich into 4 equal parts and eats 1 part. What fraction of the sandwich did she eat? What fraction is left?",
"A classroom has 17 kids. Can everyone have a partner for the game, or will one kid be left over? Is 17 odd or even?",
]
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: ' + bl() + '</p></div>'
s4 += '</div></div>'
# 5: Create Your Own
s5 = '<div class="abox" style="background:#f3e5f5;">'\
'<p><b>Create Your Own</b> โ Draw an array with equal rows (any size up to 5ร5). '\
'Then write its repeated addition sentence.</p>'\
'<div style="min-height:80px; border-bottom:1px dashed #999;"></div>'\
'<p style="margin-top:6px;">My addition sentence: ' + bl() + '</p>'\
'</div>'
return page(31, "Thursday", "Geometry, Arrays & Word Problems",
f'''{sec(1, "Warm-up: Repeated Addition", s1)}
{sec(2, "Shape Review", s2)}
{sec(3, "Arrays & Repeated Addition", s3)}
{sec(4, "Word Problems: Think About What Is Happening", s4)}
{sec(5, "Challenge: Create Your Own", s5)}''')
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# FRIDAY โ Big Review & Self-Check
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
def friday():
s1 = warmup(["9 + 6", "17 โ 9", "7 + 7", "12 โ 5"])
# 2: Estimate First!
s2 = '<div class="abox" style="background:#fff3e0;">'\
'<p><b>Estimate First!</b> Estimate, then solve.</p>'\
'<div class="mgrid c2">'
for a_, b_, op in [(63, 28, "โ"), (37, 45, "+")]:
s2 += f'<div class="abox"><p>{a_} {op} {b_}</p>'\
f'<p>Estimate: {b("3em")} Exact: {b("3em")}</p></div>'
s2 += '</div></div>'
# 3: The whole year in 6 problems (reduced mixed review)
s3 = '<div class="abox">'\
'<p class="note">One problem from each big topic this year. Use any strategy!</p>'\
'<div class="mgrid c2">'
s3 += '<div class="abox"><p><b>Place value:</b> 500 + 60 + 2 = ' + b("4em") + '</p></div>'
s3 += '<div class="abox"><p><b>Regrouping:</b> 71 โ 36 = ' + b("4em") + '</p></div>'
s3 += '<div class="abox"><p><b>Money:</b> 2 quarters + 3 dimes = ' + b("3em") + 'ยข</p></div>'
s3 += '<div class="abox"><p><b>Time:</b> Half past 4 is ' + b("3em") + ' : ' + b("5em") + '</p></div>'
s3 += '<div class="abox"><p><b>Odd/Even:</b> 27 is ' + b("4em") + '</p></div>'
s3 += '<div class="abox"><p><b>Arrays:</b> 4 rows of 3 = ' + b("3em") + '</p></div>'
s3 += '</div></div>'
# 4: Number Talk โ final reasoning
s4 = '<div class="abox" style="background:#e3f2fd;">'\
'<p><b>Number Talk</b> โ Explain WITHOUT calculating.</p>'\
'<p>Which is bigger: <b>48 + 48</b> or <b>50 + 50</b>? '\
'How much bigger? Can you figure it out without adding either one?</p>'\
'<p style="font-size:11px;">My thinking: ' + bw() + '</p>'\
'</div>'
# 5: Self-check with emoji reflection โ whole year
s5 = '<div class="selfcheck">'\
'<p><b>Self-Check: How do you feel about this YEAR of math?</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>Addition & Subtraction</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>Time, Money & Measurement</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>Shapes, Patterns & Arrays</b></p>'\
'<p>๐ I got it! | ๐ Getting there | ๐ Need help</p>'\
'</div>'\
'</div>'\
'<p style="margin-top:10px;"><b>One thing I learned this year that I am proud of:</b> ' + bl() + '</p>'\
'<p><b>One thing I want to practice over the summer:</b> ' + bl() + '</p>'\
'<p><b>My favorite math topic was:</b> ' + bl() + '</p>'\
'</div>'
return page(31, "Friday", "Week 31 Review & Self-Check",
f'''{sec(1, "Warm-up: Mental Math", s1)}
{sec(2, "Estimate First!", s2)}
{sec(3, "The Whole Year in 6 Problems", s3)}
{sec(4, "Number Talk", s4)}
{sec(5, "Self-Check & Reflection", s5)}''')
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# TEACHER GUIDE
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
def teacher_guide():
return tg_page_multi(
"Week 31", "Final Review โ Teacher Guide",
tg_section_title("Monday: Place Value & Number Sense") +
tg_sec(1, "Warm-up", ["16, 9, 16, 9"]) +
tg_sec(2, "Place Value", ["8 means 8 tens (80); 300+10+6; 749; 438 < 483"]) +
tg_sec(3, "Number Talk", ["410 is bigger (399+10=409); Marisol is wrong โ compare tens first, 250 has 5 tens vs 0 tens"]) +
tg_sec(4, "Skip Counting", ["237, 257; 345, 445; 490, 500"]) +
tg_sec(5, "Word Problem", ["Chapter books 364; total 264+364 = 628"]) +
tg_note("Page break"),
tg_section_title("Tuesday: Addition & Subtraction") +
tg_sec(1, "Warm-up", ["14, 5, 16, 9"]) +
tg_sec(2, "Estimate First", ["48+34: est 50+30=80, exact 82; 72โ29: est 70โ30=40, exact 43"]) +
tg_sec(3, "Mixed +/โ", ["57+26=83 (regroup); 83โ45=38 (regroup); 38+41=79 (no); 60โ27=33 (regroup)"]) +
tg_sec(4, "Two Ways", ["46+39=85; friendly number: 46+40โ1=85; break apart: 40+30=70, 6+9=15, 70+15=85"]) +
tg_sec(5, "Word Problems", ["92โ58+25 = 59 muffins; Jo is wrong โ Kim needs 70โ35 = 35 more"]) +
tg_note("Page break"),
tg_section_title("Wednesday: Measurement, Time & Money") +
tg_sec(1, "Warm-up", ["50, 16, 25, 25"]) +
tg_sec(2, "Time", ["3:15, 7:40, 11:05"]) +
tg_sec(3, "Money", ["61ยข, 51ยข, 80ยข"]) +
tg_sec(4, "Estimate First", ["A = 6 cm, B = 9 cm (printed scale)"]) +
tg_sec(5, "Number Talk", ["Ava: 9 dimes = 90ยข vs 4 quarters = 100ยข โ Ben has more; count by 25s vs 10s"]) +
tg_note("Page break"),
tg_section_title("Thursday: Geometry & Arrays") +
tg_sec(1, "Warm-up", ["9, 15, 8, 8"]) +
tg_sec(2, "Shapes", ["triangle 3/3; square 4/4; rectangle 4/4; star 10/10 (accept 5 points)"]) +
tg_sec(3, "Arrays", ["8, 9, 20"]) +
tg_sec(4, "Word Problems", ["3 rows of 6 = 18 muffins; ate 1/4, left 3/4; 17 is odd โ one kid left over"]) +
tg_sec(5, "Create Own", ["Any equal-row array with matching addition sentence"]) +
tg_note("Page break"),
tg_section_title("Friday: Big Review & Self-Check") +
tg_sec(1, "Warm-up", ["15, 8, 14, 7"]) +
tg_sec(2, "Estimate First", ["63โ28: est ~35, exact 35; 37+45: est ~80, exact 82"]) +
tg_sec(3, "Year in 6 Problems", ["562; 35; 80ยข; 4:30; odd; 12"]) +
tg_sec(4, "Number Talk", ["50+50 is bigger by 4 (each 48 is 2 less than 50)"]) +
tg_sec(5, "Self-Check", ["Accept student self-assessment; discuss summer practice plans"])
)
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# 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", "Place Value & Number Sense Review"),
(tuesday, "Tuesday", "Addition & Subtraction Review"),
(wednesday, "Wednesday", "Measurement, Time & Money Review"),
(thursday, "Thursday", "Geometry, Arrays & Word Problems"),
(friday, "Friday", "Week 31 Review & Self-Check"),
]
for lesson_func, day, title in days:
html = lesson_func()
fname = f"Week_31_{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_31_Teacher_Guide.html")
with open(path, "w") as f:
f.write(html)
pdf_path = os.path.join(WEEK, "Week_31_Teacher_Guide.pdf")
HTML(filename=path).write_pdf(pdf_path)
print(f"Generated: {pdf_path}")
print("\nWeek 31 (rewritten to new standard) complete!")