advent of code 2025 in ts and nix
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}; 66 67const dayCards = days 68 .map((day) => { 69 const info = dayInfo[day]; 70 if (!info) return ""; 71 72 return ` <li> 73 <a href="${day}/index.html" class="day-item"> 74 <span class="day-number">Day ${parseInt(day, 10)}:</span> 75 <span class="day-title">${info.title}</span> 76 <span class="stars"> **</span> 77 </a> 78 <div class="day-description">${info.description}</div> 79 </li>`; 80 }) 81 .join("\n"); 82 83const indexHtml = `<!DOCTYPE html> 84<html lang="en"> 85<head> 86 <meta charset="UTF-8"> 87 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 88 <title>Advent of Code 2025 - Visualizations</title> 89 <style> 90 body { 91 background: #1e1e2e; 92 color: #cdd6f4; 93 font-family: "Source Code Pro", monospace; 94 font-size: 14pt; 95 font-weight: 300; 96 padding: 1rem; 97 } 98 a { 99 text-decoration: none; 100 color: #a6e3a1; 101 outline: 0; 102 } 103 a:hover, a:focus { 104 background-color: #181825 !important; 105 } 106 h1, h2 { 107 font-size: 1em; 108 font-weight: normal; 109 } 110 header { 111 white-space: nowrap; 112 margin-bottom: 2em; 113 } 114 header h1 { 115 display: inline-block; 116 margin: 0; 117 padding-right: 1em; 118 } 119 header h1 span { 120 color: #a6e3a1; 121 text-shadow: 0 0 2px #a6e3a1, 0 0 5px #a6e3a1; 122 } 123 main { 124 width: 60em; 125 margin: 0 auto; 126 min-height: 76vh; 127 } 128 article { 129 margin-bottom: 2em; 130 } 131 article h2 { 132 color: #cdd6f4; 133 margin-top: 1em; 134 margin-bottom: 1em; 135 } 136 .days-list { 137 list-style-type: none; 138 padding: 0; 139 } 140 .day-item { 141 display: block; 142 padding: 0.5em 0; 143 color: inherit; 144 } 145 .day-item:hover, .day-item:focus { 146 background-color: #181825 !important; 147 } 148 .day-number { 149 color: #a6adc8; 150 } 151 .day-title { 152 color: #cdd6f4; 153 } 154 .stars { 155 color: #f9e2af; 156 } 157 .day-description { 158 color: #a6adc8; 159 padding-left: 2.5em; 160 } 161 footer { 162 margin-top: 3em; 163 color: #a6adc8; 164 text-align: center; 165 font-size: 12px; 166 } 167 </style> 168</head> 169<body> 170 <header> 171 <h1><span>Advent of Code</span> 2025 - Visualizations</h1> 172 </header> 173 174 <main> 175 <article> 176 <h2>Interactive Problem Visualizations</h2> 177 <ul class="days-list"> 178${dayCards} 179 </ul> 180 </article> 181 182 </main> 183 184 <footer> 185 Made with ♥ by <a href="https://dunkirk.sh">Kieran Klukas</a> 186 <br> 187 <a href="https://adventofcode.com/2025">[Return to Advent of Code]</a> 188 </footer> 189</body> 190</html>`; 191 192await Bun.write(join(OUTPUT_DIR, "index.html"), indexHtml); 193 194console.log("\n✨ All visualizations generated successfully!"); 195console.log(`📁 Output directory: ${OUTPUT_DIR}`); 196console.log(`🌐 Open ${join(OUTPUT_DIR, "index.html")} to view\n`);