advent of code 2025 in ts and nix
at main 5.2 kB view raw
1#!/usr/bin/env bun 2 3import { mkdir, readdir, rm } from "node:fs/promises"; 4import { join } from "node:path"; 5import { $ } from "bun"; 6 7const OUTPUT_DIR = join(import.meta.dir, "../output"); 8const VIS_DIR = join(import.meta.dir, "../vis"); 9 10console.log("🎨 Generating all visualizations...\n"); 11 12// Clean output directory 13await rm(OUTPUT_DIR, { recursive: true, force: true }); 14await mkdir(OUTPUT_DIR, { recursive: true }); 15 16// Auto-detect days from vis directory 17const entries = await readdir(VIS_DIR, { withFileTypes: true }); 18const days = entries 19 .filter((entry) => entry.isDirectory() && /^\d{2}$/.test(entry.name)) 20 .map((entry) => entry.name) 21 .sort(); 22 23// Generate each day's visualization 24for (const day of days) { 25 console.log(`📊 Day ${day}...`); 26 const dayDir = join(VIS_DIR, day); 27 const generateScript = join(dayDir, "generate.ts"); 28 29 // Run the generator 30 await $`cd ${dayDir} && bun ${generateScript}`; 31 32 // Copy the output to the output directory 33 const outputDayDir = join(OUTPUT_DIR, day); 34 await mkdir(outputDayDir, { recursive: true }); 35 await $`cp ${join(dayDir, "index.html")} ${outputDayDir}/index.html`; 36 37 console.log(` ✓ Generated ${day}`); 38} 39 40// Generate index page 41console.log("\n📄 Generating index page..."); 42 43// Day metadata 44const dayInfo: Record<string, { title: string; description: string }> = { 45 "04": { 46 title: "Paper Removal", 47 description: 48 "Watch papers being removed layer by layer from a grid. Papers with fewer than 4 neighbors (including diagonals) are accessible and removed each iteration.", 49 }, 50 "06": { 51 title: "Cephalopod Math", 52 description: 53 "Learn to read numbers like a cephalopod! Part 1 reads numbers vertically down columns, Part 2 reads digits column-by-column from right to left.", 54 }, 55 "07": { 56 title: "Tachyon Beam Splitting", 57 description: 58 "Watch tachyon beams split as they travel through a manifold. Each splitter (^) stops a beam and creates two new beams extending left and right.", 59 }, 60 "08": { 61 title: "Playground Junction Boxes", 62 description: 63 "3D visualization of junction boxes being connected by their shortest distances. Watch circuits form as connections merge isolated boxes into larger groups.", 64 }, 65 "09": { 66 title: "Movie Theater Floor", 67 description: 68 "Find the largest rectangle using red tiles as opposite corners. Part 1 allows any rectangle, Part 2 requires rectangles to only contain red/green tiles.", 69 }, 70 "10": { 71 title: "Factory Machines", 72 description: 73 "Configure indicator lights by pressing buttons that toggle specific lights. Find the minimum number of button presses to match the target configuration.", 74 }, 75}; 76 77const dayCards = days 78 .map((day) => { 79 const info = dayInfo[day]; 80 if (!info) return ""; 81 82 return ` <li> 83 <a href="${day}/index.html" class="day-item"> 84 <span class="day-number">Day ${parseInt(day, 10)}:</span> 85 <span class="day-title">${info.title}</span> 86 <span class="stars"> **</span> 87 </a> 88 <div class="day-description">${info.description}</div> 89 </li>`; 90 }) 91 .join("\n"); 92 93const indexHtml = `<!DOCTYPE html> 94<html lang="en"> 95<head> 96 <meta charset="UTF-8"> 97 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 98 <title>Advent of Code 2025 - Visualizations</title> 99 <style> 100 body { 101 background: #1e1e2e; 102 color: #cdd6f4; 103 font-family: "Source Code Pro", monospace; 104 font-size: 14pt; 105 font-weight: 300; 106 padding: 1rem; 107 } 108 a { 109 text-decoration: none; 110 color: #a6e3a1; 111 outline: 0; 112 } 113 a:hover, a:focus { 114 background-color: #181825 !important; 115 } 116 h1, h2 { 117 font-size: 1em; 118 font-weight: normal; 119 } 120 header { 121 white-space: nowrap; 122 margin-bottom: 2em; 123 } 124 header h1 { 125 display: inline-block; 126 margin: 0; 127 padding-right: 1em; 128 } 129 header h1 span { 130 color: #a6e3a1; 131 text-shadow: 0 0 2px #a6e3a1, 0 0 5px #a6e3a1; 132 } 133 main { 134 width: 60em; 135 margin: 0 auto; 136 min-height: 76vh; 137 } 138 article { 139 margin-bottom: 2em; 140 } 141 article h2 { 142 color: #cdd6f4; 143 margin-top: 1em; 144 margin-bottom: 1em; 145 } 146 .days-list { 147 list-style-type: none; 148 padding: 0; 149 } 150 .day-item { 151 display: block; 152 padding: 0.5em 0; 153 color: inherit; 154 } 155 .day-item:hover, .day-item:focus { 156 background-color: #181825 !important; 157 } 158 .day-number { 159 color: #a6adc8; 160 } 161 .day-title { 162 color: #cdd6f4; 163 } 164 .stars { 165 color: #f9e2af; 166 } 167 .day-description { 168 color: #a6adc8; 169 padding-left: 2.5em; 170 } 171 footer { 172 margin-top: 3em; 173 color: #a6adc8; 174 text-align: center; 175 font-size: 12px; 176 } 177 </style> 178</head> 179<body> 180 <header> 181 <h1><span>Advent of Code</span> 2025 - Visualizations</h1> 182 </header> 183 184 <main> 185 <article> 186 <h2>Interactive Problem Visualizations</h2> 187 <ul class="days-list"> 188${dayCards} 189 </ul> 190 </article> 191 192 </main> 193 194 <footer> 195 Made with ♥ by <a href="https://dunkirk.sh">Kieran Klukas</a> 196 <br> 197 <a href="https://adventofcode.com/2025">[Return to Advent of Code]</a> 198 </footer> 199</body> 200</html>`; 201 202await Bun.write(join(OUTPUT_DIR, "index.html"), indexHtml); 203 204console.log("\n✨ All visualizations generated successfully!"); 205console.log(`📁 Output directory: ${OUTPUT_DIR}`); 206console.log(`🌐 Open ${join(OUTPUT_DIR, "index.html")} to view\n`);