#!/usr/bin/env node /** * Transform collecting-asteroids-2.html into collecting-asteroids-3.html * Output goes to stdout for review before saving. */ import { readFileSync } from 'fs'; import { resolve } from 'path'; const root = resolve(import.meta.dirname, '../..'); const v2Html = readFileSync(resolve(root, 'output/html/collecting-asteroids-2.html'), 'utf-8'); // Page configs for v3 const pages = [ { comment: 'PAGE 1: ships 11(2), 9(2), 13(6) — R-L-R', hero: 'splitter4', footer: 'cabin3', cargoBays: [7, 8, 9], ships: [11, 9, 13], oldAsteroidTypes: ['asteroid7', 'asteroid14'], newAsteroidTypes: ['asteroid3', 'asteroid10'], asteroidValues: [3, 2, 1, 4, 5, 2, 3, 6, 5, 4, 1, 6], }, { comment: 'PAGE 2: ships 12(3), 12(3), 18(4) — L-R-L', hero: 'splitter7', footer: 'cabin6', cargoBays: [1, 2, 3], ships: [12, 12, 18], oldAsteroidTypes: ['asteroid4', 'asteroid11'], newAsteroidTypes: ['asteroid6', 'asteroid13'], asteroidValues: [4, 5, 3, 6, 2, 7, 4, 3, 5, 2, 6, 4], }, { comment: 'PAGE 3: ships 9(5), 11(3), 11(2) — R-L-R', hero: 'splitter1', footer: 'cabin9', cargoBays: [4, 5, 6], ships: [9, 11, 11], oldAsteroidTypes: ['asteroid10', 'asteroid3'], newAsteroidTypes: ['asteroid2', 'asteroid8'], asteroidValues: [2, 4, 1, 3, 5, 2, 1, 3, 4, 6, 5, 2], }, { comment: 'PAGE 4: ships 15(4), 17(5), 11(2) — L-R-L', hero: 'splitter6', footer: 'cabin2', cargoBays: [7, 8, 9], ships: [15, 17, 11], oldAsteroidTypes: ['asteroid16', 'asteroid5'], newAsteroidTypes: ['asteroid12', 'asteroid15'], asteroidValues: [4, 3, 5, 2, 6, 1, 3, 4, 6, 2, 5, 4], }, { comment: 'PAGE 5: ships 7(2), 9(4), 7(2) — R-L-R', hero: 'splitter2', footer: 'cabin5', cargoBays: [1, 2, 3], ships: [7, 9, 7], oldAsteroidTypes: ['asteroid2', 'asteroid13'], newAsteroidTypes: ['asteroid1', 'asteroid9'], asteroidValues: [3, 1, 4, 2, 5, 1, 6, 2, 3, 4, 5], }, { comment: 'PAGE 6: ships 18(4), 18(5), 14(3) — L-R-L', hero: 'splitter8', footer: 'cabin7', cargoBays: [4, 5, 6], ships: [18, 18, 14], oldAsteroidTypes: ['asteroid8', 'asteroid12'], newAsteroidTypes: ['asteroid5', 'asteroid16'], asteroidValues: [3, 4, 5, 6, 2, 4, 7, 3, 2, 5, 6, 4, 3, 7], }, { comment: 'PAGE 7: ships 10(2), 16(3), 22(6) — R-L-R', hero: 'splitter9', footer: 'cabin4', cargoBays: [7, 8, 9], ships: [10, 16, 22], oldAsteroidTypes: ['asteroid15', 'asteroid6'], newAsteroidTypes: ['asteroid11', 'asteroid7'], asteroidValues: [4, 3, 2, 6, 5, 3, 7, 4, 5, 2, 6, 4], }, { comment: 'PAGE 8: ships 26(0), 18(0), 30(0) — UNSOLVABLE — L-R-L', hero: 'splitter5', footer: 'cabin1', cargoBays: [1, 2, 3], ships: [26, 18, 30], oldAsteroidTypes: ['asteroid9', 'asteroid1'], newAsteroidTypes: ['asteroid14', 'asteroid4'], asteroidValues: [6, 4, 5, 3, 7, 2, 4, 6, 5, 7, 3, 4, 6], }, { comment: 'PAGE 9: ships 8(2), 18(3), 28(8) — R-L-R', hero: 'splitter3', footer: 'cabin8', cargoBays: [4, 5, 6], ships: [8, 18, 28], oldAsteroidTypes: ['asteroid11', 'asteroid4'], newAsteroidTypes: ['asteroid10', 'asteroid6'], asteroidValues: [4, 3, 2, 5, 6, 3, 4, 7, 2, 5, 4, 6, 3, 7, 5], }, ]; // Split HTML into pages // Pages are delimited by /, ``); // 2. Replace hero image html = html.replace( /splitters\/splitter\d+\.png/, `splitters/${config.hero}.png` ); // 3. Replace footer image html = html.replace( /footers\/cabin\d+\.jpeg/, `footers/${config.footer}.jpeg` ); // 4. Replace cargo bay images (3 per page, in order) let cbIdx = 0; html = html.replace( /pack4-cargobay\/cargo-bay\d+\.png/g, (match) => `pack4-cargobay/cargo-bay${config.cargoBays[cbIdx++]}.png` ); // 5. Replace ship capacity numbers (text-xl spans inside blue circles) let shipIdx = 0; html = html.replace( /()(\d+)(<\/span>)/g, (match, pre, val, post) => `${pre}${config.ships[shipIdx++]}${post}` ); // 6. Replace asteroid type images for (let i = 0; i < config.oldAsteroidTypes.length; i++) { const oldType = config.oldAsteroidTypes[i]; const newType = config.newAsteroidTypes[i]; html = html.replaceAll( `pack3-asteroids/${oldType}.png`, `pack3-asteroids/${newType}.png` ); } // 7. Replace asteroid values (text-2xl spans, sequential) let avIdx = 0; html = html.replace( /(]*>)(\d+)(<\/span>)/g, (match, pre, val, post) => { if (avIdx < config.asteroidValues.length) { return `${pre}${config.asteroidValues[avIdx++]}${post}`; } return match; } ); // Sanity check if (shipIdx !== 3) { console.error(`WARNING: Page ${pageIdx + 1} — replaced ${shipIdx} ship values (expected 3)`); } if (avIdx !== config.asteroidValues.length) { console.error(`WARNING: Page ${pageIdx + 1} — replaced ${avIdx} asteroid values (expected ${config.asteroidValues.length})`); } if (cbIdx !== 3) { console.error(`WARNING: Page ${pageIdx + 1} — replaced ${cbIdx} cargo bay refs (expected 3)`); } return html; } // Transform all pages const newPages = pageBlocks.map((block, i) => transformPage(block, pages[i], i)); // Assemble const result = header + newPages.join('') + footer; // Write to temp file import { writeFileSync } from 'fs'; const tmpPath = resolve(root, 'output/html/.collecting-asteroids-3-tmp.html'); writeFileSync(tmpPath, result); console.log(`Output written to: ${tmpPath}`); console.log(`Total lines: ${result.split('\n').length}`); // Print summary of changes per page for (let i = 0; i < pages.length; i++) { const p = pages[i]; console.log(`\nPage ${i + 1}: hero=${p.hero} footer=${p.footer} cargoBays=[${p.cargoBays}]`); console.log(` Ships: [${p.ships}] Asteroids: [${p.asteroidValues}]`); console.log(` Types: ${p.oldAsteroidTypes} → ${p.newAsteroidTypes}`); }