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