diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 3f4f28f..f88392f 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -44,7 +44,9 @@ "Bash(pnpm pdf:*)", "Bash(mv freighter-trade1.png freighter1.png)", "Bash(mv freighter-mining1.png freighter11.png)", - "Bash(mv freighter-science1.png freighter12.png)" + "Bash(mv freighter-science1.png freighter12.png)", + "Bash(sort -t'\\(' -k2 -n)", + "Bash(grep -o 'scale\\(3.50\\).\\\\{0,200\\\\}')" ] } } diff --git a/src/scripts/generate-worksheet3.mjs b/src/scripts/generate-worksheet3.mjs new file mode 100644 index 0000000..48bf089 --- /dev/null +++ b/src/scripts/generate-worksheet3.mjs @@ -0,0 +1,311 @@ +/** + * Generate space-worksheet3.html — 9-page static HTML worksheet + * combining task patterns from worksheet1 and worksheet2. + * + * Usage: node src/scripts/generate-worksheet3.mjs + * Output: output/html/space-worksheet3.html + */ + +import fs from 'fs'; +import path from 'path'; + +const ROOT = process.cwd(); + +// ── Icon pools ────────────────────────────────────────────────────────────── +const pack1Icons = fs.readdirSync(path.join(ROOT, 'assets/icons/pack1')) + .filter(f => f.endsWith('.png')) + .map(f => `assets/icons/pack1/${f}`); + +const pack2Icons = fs.readdirSync(path.join(ROOT, 'assets/icons/pack2')) + .filter(f => f.endsWith('.png')) + .map(f => `assets/icons/pack2/${f}`); + +function shuffle(arr) { + const a = [...arr]; + for (let i = a.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [a[i], a[j]] = [a[j], a[i]]; + } + return a; +} + +function randInt(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; +} + +function randSign() { + return Math.random() < 0.5 ? 1 : -1; +} + +function pickAlignment() { + const opts = ['justify-start', 'justify-center', 'justify-end']; + return opts[Math.floor(Math.random() * opts.length)]; +} + +// ── Problem generators ────────────────────────────────────────────────────── + +// Pattern 1: A + B ± C (A:8-16, B:4-8, C:1-3) +function genPattern1() { + const problems = []; + const seen = new Set(); + while (problems.length < 20) { + const A = randInt(8, 16); + const B = randInt(4, 8); + const C = randInt(1, 3); + const sign = randSign(); + const expr = sign > 0 ? `${A} + ${B} + ${C}` : `${A} + ${B} − ${C}`; + const result = A + B + sign * C; + if (result >= 0 && !seen.has(expr)) { + seen.add(expr); + problems.push(expr); + } + } + return problems; +} + +// Pattern 2: 5 × N ± C (N:1-5, C:1-6) +function genPattern2() { + const problems = []; + const seen = new Set(); + while (problems.length < 20) { + const N = randInt(1, 5); + const C = randInt(1, 6); + const sign = randSign(); + const expr = sign > 0 ? `5 × ${N} + ${C}` : `5 × ${N} − ${C}`; + const result = 5 * N + sign * C; + if (result >= 0 && !seen.has(expr)) { + seen.add(expr); + problems.push(expr); + } + } + return problems; +} + +// Pattern 3: A × B ± C (A,B:1-4, C:1-8) +function genPattern3() { + const problems = []; + const seen = new Set(); + while (problems.length < 20) { + const A = randInt(1, 4); + const B = randInt(1, 4); + const C = randInt(1, 8); + const sign = randSign(); + const expr = sign > 0 ? `${A} × ${B} + ${C}` : `${A} × ${B} − ${C}`; + const result = A * B + sign * C; + if (result >= 0 && !seen.has(expr)) { + seen.add(expr); + problems.push(expr); + } + } + return problems; +} + +// Pattern 4: A + B + C (A:12-24, B:±6-10, C:±2-5, result 0-40) +function genPattern4() { + const problems = []; + const seen = new Set(); + while (problems.length < 20) { + const A = randInt(12, 24); + const signB = randSign(); + const B = randInt(6, 10); + const signC = randSign(); + const C = randInt(2, 5); + const result = A + signB * B + signC * C; + if (result >= 0 && result <= 40) { + const bPart = signB > 0 ? `+ ${B}` : `− ${B}`; + const cPart = signC > 0 ? `+ ${C}` : `− ${C}`; + const expr = `${A} ${bPart} ${cPart}`; + if (!seen.has(expr)) { + seen.add(expr); + problems.push(expr); + } + } + } + return problems; +} + +// Pattern 5: mixed fives (5+5+5, 5×N, 5×N±5) +function genPattern5() { + const problems = []; + const seen = new Set(); + + // Type A: 5+5+5 (2,3,4 fives) + for (const count of [2, 3, 4]) { + const expr = Array(count).fill('5').join(' + '); + problems.push(expr); + seen.add(expr); + } + + // Type B: 5×N (N:1-12) + const ns = shuffle([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]); + for (const n of ns) { + if (problems.length >= 20) break; + const expr = `5 × ${n}`; + if (!seen.has(expr)) { + seen.add(expr); + problems.push(expr); + } + } + + // Type C: 5×N±5 (fill remaining) + while (problems.length < 20) { + const N = randInt(2, 12); + const sign = randSign(); + const expr = sign > 0 ? `5 × ${N} + 5` : `5 × ${N} − 5`; + if (!seen.has(expr)) { + seen.add(expr); + problems.push(expr); + } + } + + return shuffle(problems); +} + +// Pattern 6: A×B + C×D (A:2-4, B:1-3, C:2-3, D:1-2) +function genPattern6() { + const problems = []; + const seen = new Set(); + while (problems.length < 20) { + const A = randInt(2, 4); + const B = randInt(1, 3); + const C = randInt(2, 3); + const D = randInt(1, 2); + const expr = `${A} × ${B} + ${C} × ${D}`; + if (!seen.has(expr)) { + seen.add(expr); + problems.push(expr); + } + } + return problems; +} + +const generators = [genPattern1, genPattern2, genPattern3, genPattern4, genPattern5, genPattern6, genPattern1, genPattern2, genPattern3]; + +// ── Page config ───────────────────────────────────────────────────────────── +const pages = [ + { hero: 'assets/hero-images/spaceship1.jpeg', footer: 'assets/footers/planet1.jpeg', dir: 'flex-row-reverse', pack: 'pack1', gen: 0 }, + { hero: 'assets/hero-images/spaceship2.jpeg', footer: 'assets/footers/planet2.jpeg', dir: '', pack: 'pack1', gen: 1 }, + { hero: 'assets/hero-images/spaceship3.png', footer: 'assets/footers/planet3.jpeg', dir: 'flex-row-reverse', pack: 'pack1', gen: 2 }, + { hero: 'assets/hero-images/spaceship4.jpeg', footer: 'assets/footers/planet4.jpeg', dir: '', pack: 'pack2', gen: 3 }, + { hero: 'assets/hero-images/spaceship5.jpeg', footer: 'assets/footers/planet5.jpeg', dir: 'flex-row-reverse', pack: 'pack2', gen: 4, fivesHint: true }, + { hero: 'assets/hero-images/spaceship6.jpeg', footer: 'assets/footers/planet6.jpeg', dir: '', pack: 'pack2', gen: 5 }, + { hero: 'assets/hero-images/spaceship7.jpeg', footer: 'assets/footers/planet7.jpeg', dir: 'flex-row-reverse', pack: 'pack1', gen: 6 }, + { hero: 'assets/hero-images/spaceship8.jpeg', footer: 'assets/footers/planet8.jpeg', dir: '', pack: 'pack1', gen: 7 }, + { hero: 'assets/hero-images/spaceship9.jpeg', footer: 'assets/footers/planet9.jpeg', dir: 'flex-row-reverse', pack: 'pack1', gen: 8 }, +]; + +// ── Assign icons per section (3 pages share a pool) ───────────────────────── +// Section 1 (pages 0-2): pack1 shuffled +// Section 2 (pages 3-5): pack2 shuffled +// Section 3 (pages 6-8): pack1 re-shuffled +const iconSections = [ + shuffle(pack1Icons), // pages 0-2: 60 icons + shuffle(pack2Icons), // pages 3-5: 60 icons + shuffle(pack1Icons), // pages 6-8: 60 icons (reuse pack1, different shuffle) +]; + +// ── Build HTML ────────────────────────────────────────────────────────────── +function buildProblemCard(icon, expression, alignment, iconSize) { + return `
Собери ресурсы, решая примеры!
+