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