Files
timothykim.net/static/factoring.html
T
timothykim 7d43c3b4c0
Build and Push Docker Image / build (push) Successful in 19s
add factoring worksheet page
2026-07-10 15:00:31 -04:00

296 lines
7.1 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Factoring Worksheets</title>
<link href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;700;800&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: 'Nunito', sans-serif;
background: #f5f5f5;
color: #111;
}
/* Screen nav */
.screen-nav {
position: fixed;
top: 0; left: 0; right: 0;
background: #111;
color: white;
padding: 8px 20px;
display: flex;
align-items: center;
gap: 8px;
z-index: 100;
flex-wrap: wrap;
}
.screen-nav label {
font-weight: 800;
font-size: 13px;
}
.nav-actions {
margin-left: auto;
display: flex;
gap: 8px;
}
.action-btn {
background: white;
border: none;
color: #111;
padding: 6px 16px;
border-radius: 20px;
cursor: pointer;
font-family: 'Nunito', sans-serif;
font-weight: 800;
font-size: 13px;
}
.action-btn:hover { background: #ddd; }
/* Worksheet */
.worksheet {
max-width: 680px;
margin: 68px auto 40px;
padding: 32px 36px;
background: white;
}
.ws-header {
text-align: center;
margin-bottom: 28px;
border-bottom: 2px solid #111;
padding-bottom: 14px;
}
.ws-title {
font-size: 1.8rem;
font-weight: 800;
letter-spacing: 1px;
}
.ws-meta {
display: flex;
gap: 40px;
justify-content: center;
margin-top: 10px;
font-size: 0.9rem;
}
.ws-meta div { display: flex; align-items: center; gap: 6px; }
.ws-meta span {
border-bottom: 1.5px solid #111;
min-width: 130px;
display: inline-block;
height: 18px;
}
/* Problems */
.section { margin-bottom: 24px; }
.problems-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 8px 40px;
}
.problem {
display: flex;
align-items: baseline;
gap: 6px;
font-size: 1.2rem;
font-weight: 700;
padding: 7px 4px;
border-bottom: 1px solid #e0e0e0;
}
.prob-num {
min-width: 26px;
font-size: 0.78rem;
font-weight: 800;
color: #999;
flex-shrink: 0;
}
.answer-line {
border-bottom: 2px solid #111;
min-width: 34px;
display: inline-block;
height: 20px;
vertical-align: bottom;
}
.box-blank {
display: inline-flex;
align-items: center;
justify-content: center;
width: 30px;
height: 30px;
border: 2px solid #111;
border-radius: 4px;
vertical-align: middle;
}
.section-divider {
border: none;
border-top: 1.5px dashed #ccc;
margin: 22px 0;
}
h1 {
font-size: 1.2em;
margin-bottom: 10px;
font-weight: bold;
}
.hint {
font-size: 0.7rem;
font-weight: 700;
color: #999;
margin-left: 8px;
}
/* Print */
@media print {
body { background: white; }
.screen-nav { display: none !important; }
.worksheet { margin: 0; padding: 0; }
.ws-header {
margin-bottom: 14px;
padding-bottom: 8px;
}
.ws-title { font-size: 1.4rem; }
.ws-meta { margin-top: 6px; font-size: 0.82rem; }
.ws-meta span { min-width: 110px; }
.section { margin-bottom: 0; }
.section-divider { margin: 8px 0; }
.problems-grid { gap: 2px 40px; }
.problem {
font-size: 1.02rem;
padding: 4px 4px;
border-bottom-color: #ccc;
margin-left: 30px;
margin-bottom: 10px;
}
.answer-line { height: 16px; min-width: 30px; }
.box-blank { width: 24px; height: 24px; }
}
@page { margin: 0.6in; }
</style>
</head>
<body>
<nav class="screen-nav" id="nav">
<label>Factoring Practice</label>
</nav>
<div id="worksheets-container"></div>
<script>
function randInt(lo, hi) { return lo + Math.floor(Math.random() * (hi - lo + 1)); }
function gcd(a, b) { return b ? gcd(b, a % b) : a; }
// Generate one factoring term: a + b = x(y + z), where x is the GCF.
// gcd(y, z) === 1 guarantees x is the true GCF, not just a common factor.
function genTerm() {
while (true) {
const x = randInt(2, 9);
const y = randInt(1, 9);
const z = randInt(1, 9);
if (y === z) continue;
if (gcd(y, z) !== 1) continue;
const a = x * y, b = x * z;
if (a > 50 || b > 50) continue;
return { x, y, z, a, b };
}
}
const PER_PART = 8;
function genUnique(n) {
const seen = new Set();
const out = [];
while (out.length < n) {
const t = genTerm();
const key = t.a + '+' + t.b + '=' + t.x; // dedupe on the displayed equation
if (seen.has(key)) continue;
seen.add(key);
out.push(t);
}
return out;
}
function renderProblems() {
// Part I - Factor: given a + b, write the factored form
const partA = genUnique(PER_PART).map((t, i) =>
`<div class="problem"><span class="prob-num">${i+1}.</span>` +
`<span>${t.a} + ${t.b} = ` +
`<span class="answer-line"></span>(<span class="answer-line"></span> + <span class="answer-line"></span>)` +
`</span></div>`
).join('');
// Part II - Expand: given x(y + z), write the sum
const partB = genUnique(PER_PART).map((t, i) =>
`<div class="problem"><span class="prob-num">${i+1}.</span>` +
`<span>${t.x}(${t.y} + ${t.z}) = ` +
`<span class="answer-line"></span> + <span class="answer-line"></span>` +
`</span></div>`
).join('');
// Part III - Find the common factor: fill the box
const partC = genUnique(PER_PART).map((t, i) =>
`<div class="problem"><span class="prob-num">${i+1}.</span>` +
`<span>${t.a} + ${t.b} = <span class="box-blank"></span>(${t.y} + ${t.z})</span></div>`
).join('');
return `
<div class="section"><h1>Part I. Factor out the common factor.</h1><div class="problems-grid">${partA}</div></div>
<hr class="section-divider">
<div class="section"><h1>Part II. Multiply it back out.</h1><div class="problems-grid">${partB}</div></div>
<hr class="section-divider">
<div class="section"><h1>Part III. Fill in the common factor.</h1><div class="problems-grid">${partC}</div></div>
`;
}
function buildWorksheet() {
return `
<div class="worksheet" id="ws">
<div class="ws-header">
<div class="ws-title">Factoring the Common Factor</div>
<div class="ws-meta">
<div>Name: <span></span></div>
<div>Date: <span></span></div>
</div>
</div>
<div class="problems" id="problems">
${renderProblems()}
</div>
</div>`;
}
const container = document.getElementById('worksheets-container');
const nav = document.getElementById('nav');
container.innerHTML = buildWorksheet();
// Action buttons
const actions = document.createElement('div');
actions.className = 'nav-actions';
const randomizeBtn = document.createElement('button');
randomizeBtn.className = 'action-btn';
randomizeBtn.textContent = '🔀 Randomize';
randomizeBtn.onclick = () => {
document.getElementById('problems').innerHTML = renderProblems();
};
const printBtn = document.createElement('button');
printBtn.className = 'action-btn';
printBtn.textContent = '🖨 Print';
printBtn.onclick = () => window.print();
actions.appendChild(randomizeBtn);
actions.appendChild(printBtn);
nav.appendChild(actions);
</script>
</body>
</html>