this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

down a rabbit hole, bleh

+347 -14
+196 -2
2023/day10/part2.ts
··· 1 1 export function answer(input: string): number { 2 - console.log(input); 3 - return 42; 2 + const m = input.split("\n").map((l) => l.split("")); 3 + const loop = findMainLoop(m); 4 + 5 + // Update the S tile to what it should actually be 6 + m[loop[0].y][loop[0].x] = tileFromDirs([ 7 + dirFromCoord(loop[0], loop[loop.length - 1])!, 8 + dirFromCoord(loop[0], loop[1])!, 9 + ]); 10 + 11 + const isInPath = ({ x, y }: Coord, p: Path): boolean => 12 + p.some((s) => s.x === x && s.y === y); 13 + 14 + const inCache = new Array(m.length) 15 + .fill(null) 16 + .map(() => new Array(m[0].length).fill(null)); 17 + 18 + for (const [y, row] of m.entries()) { 19 + let inBounds = false; 20 + let state: "out" | "in" | "on" = "out"; 21 + let lastFlip; 22 + for (const [x, curr] of row.entries()) { 23 + if (isInPath({ x, y }, loop)) { 24 + state = "on"; 25 + if ("|J7LF".includes(curr)) { 26 + if ( 27 + !lastFlip || 28 + curr === "|" || 29 + ("|L".includes(lastFlip) && curr === "J") || 30 + ("|F".includes(lastFlip) && curr === "7") 31 + ) { 32 + inBounds = !inBounds; 33 + lastFlip = curr; 34 + } 35 + } 36 + } else { 37 + state = inBounds ? "in" : "out"; 38 + } 39 + inCache[y][x] = state; 40 + } 41 + } 42 + console.log( 43 + inCache 44 + .map((row, y) => 45 + row 46 + .map((c, x) => { 47 + if (c === "on") return newChar(m[y][x]); 48 + if (c === "in") return "x"; 49 + return "."; 50 + }) 51 + .join(""), 52 + ) 53 + .join("\n"), 54 + ); 55 + return inCache 56 + .map((row) => row.map((c) => (c === "in" ? 1 : 0))) 57 + .flat() 58 + .reduce<number>((sum, x) => sum + x, 0); 59 + } 60 + 61 + const newChar = (c: string): string => { 62 + switch (c) { 63 + case "F": 64 + return "┌"; 65 + case "7": 66 + return "┐"; 67 + case "L": 68 + return "└"; 69 + case "J": 70 + return "┘"; 71 + case "-": 72 + return "─"; 73 + case "|": 74 + return "│"; 75 + } 76 + return c; 77 + }; 78 + 79 + const tileFromDirs = (dirs: [Dir, Dir]): string => { 80 + switch (dirs.sort().join("")) { 81 + case "EN": 82 + return "L"; 83 + case "ES": 84 + return "F"; 85 + case "EW": 86 + return "-"; 87 + case "NS": 88 + return "|"; 89 + case "NW": 90 + return "J"; 91 + case "SW": 92 + return "7"; 93 + } 94 + throw "invalid dirs"; 95 + }; 96 + 97 + type Dir = "N" | "S" | "E" | "W"; 98 + const dirs: Dir[] = ["N", "S", "E", "W"]; 99 + 100 + type Map = string[][]; 101 + type Coord = { x: number; y: number }; 102 + type Path = [Coord, Coord, ...Coord[]]; 103 + 104 + const findStart = (m: Map): Coord => { 105 + for (const [y, row] of m.entries()) { 106 + for (const [x, c] of row.entries()) { 107 + if (c === "S") return { x, y }; 108 + } 109 + } 110 + throw "no start?!"; 111 + }; 112 + 113 + const findMainLoop = (m: Map): Path => { 114 + const start = findStart(m); 115 + 116 + const paths: Path[] = new Array(4) 117 + .fill(null) 118 + .map((_, i) => [start, move(start, dirs[i])]); 119 + 120 + for (const pathStart of paths) { 121 + const path = followPath(m, pathStart); 122 + if (isLoop(m, path)) return path; 123 + } 124 + throw "did not find main loop"; 125 + }; 126 + 127 + const possibleDirs = (m: Map, c: Coord): Dir[] => { 128 + switch (m[c.y][c.x]) { 129 + case "|": 130 + return ["N", "S"]; 131 + case "-": 132 + return ["W", "E"]; 133 + case "L": 134 + return ["N", "E"]; 135 + case "J": 136 + return ["N", "W"]; 137 + case "7": 138 + return ["S", "W"]; 139 + case "F": 140 + return ["S", "E"]; 141 + case ".": 142 + case "S": 143 + default: 144 + return []; 145 + } 146 + }; 147 + 148 + const dirFromCoord = (curr: Coord, target: Coord): Dir | null => { 149 + if (sameCoords(move(curr, "N"), target)) return "N"; 150 + if (sameCoords(move(curr, "S"), target)) return "S"; 151 + if (sameCoords(move(curr, "E"), target)) return "E"; 152 + if (sameCoords(move(curr, "W"), target)) return "W"; 153 + return null; 154 + }; 155 + 156 + const isInBounds = (m: Map, c: Coord): boolean => 157 + c.x < m[0].length && c.y < m.length; 158 + 159 + const sameCoords = (c1: Coord, c2: Coord) => c1.x === c2.x && c1.y === c2.y; 160 + const isLoop = (m: Map, p: Path) => { 161 + const next = nextStep(m, p); 162 + if (next === "end") return false; 163 + return sameCoords(next, p[0]); 164 + }; 165 + 166 + const move = ({ x, y }: Coord, d: Dir): Coord => { 167 + switch (d) { 168 + case "N": 169 + return { x, y: y - 1 }; 170 + case "S": 171 + return { x, y: y + 1 }; 172 + case "E": 173 + return { x: x + 1, y }; 174 + case "W": 175 + return { x: x - 1, y }; 176 + } 177 + }; 178 + 179 + const nextStep = (m: Map, p: Path): Coord | "end" => { 180 + const last = p[p.length - 1]; 181 + const secondToLast = p[p.length - 2]; 182 + const dir = possibleDirs(m, last).filter( 183 + (d) => d !== dirFromCoord(last, secondToLast), 184 + ); 185 + if (dir.length !== 1) return "end"; 186 + return move(last, dir[0]); 187 + }; 188 + 189 + function followPath(m: Map, path: Path): Path { 190 + let curr: Coord | "end" = path[1]; 191 + do { 192 + curr = nextStep(m, path); 193 + if (curr === "end" || !isInBounds(m, curr) || isLoop(m, path)) break; 194 + path.push(curr); 195 + } while (!isLoop(m, path) || !isInBounds(m, curr)); 196 + 197 + return path; 4 198 } 5 199 6 200 if (import.meta.main) {
+128 -2
2023/day10/puzzle.md
··· 131 131 132 132 Find the single giant loop starting at `S`. *How many steps along the loop does it take to get from the starting position to the point farthest from the starting position?* 133 133 134 - To begin, [get your puzzle input](10/input). 134 + Your puzzle answer was `7145`. 135 + 136 + The first half of this puzzle is complete! It provides one gold star: \* 137 + 138 + \--- Part Two --- 139 + ---------- 140 + 141 + You quickly reach the farthest point of the loop, but the animal never emerges. Maybe its nest is *within the area enclosed by the loop*? 142 + 143 + To determine whether it's even worth taking the time to search for such a nest, you should calculate how many tiles are contained within the loop. For example: 144 + 145 + ``` 146 + ........... 147 + .S-------7. 148 + .|F-----7|. 149 + .||.....||. 150 + .||.....||. 151 + .|L-7.F-J|. 152 + .|..|.|..|. 153 + .L--J.L--J. 154 + ........... 155 + 156 + ``` 157 + 158 + The above loop encloses merely *four tiles* - the two pairs of `.` in the southwest and southeast (marked `I` below). The middle `.` tiles (marked `O` below) are *not* in the loop. Here is the same loop again with those regions marked: 159 + 160 + ``` 161 + ........... 162 + .S-------7. 163 + .|F-----7|. 164 + .||OOOOO||. 165 + .||OOOOO||. 166 + .|L-7OF-J|. 167 + .|II|O|II|. 168 + .L--JOL--J. 169 + .....O..... 170 + 171 + ``` 172 + 173 + In fact, there doesn't even need to be a full tile path to the outside for tiles to count as outside the loop - squeezing between pipes is also allowed! Here, `I` is still within the loop and `O` is still outside the loop: 174 + 175 + ``` 176 + .......... 177 + .S------7. 178 + .|F----7|. 179 + .||OOOO||. 180 + .||OOOO||. 181 + .|L-7F-J|. 182 + .|II||II|. 183 + .L--JL--J. 184 + .......... 185 + 186 + ``` 187 + 188 + In both of the above examples, `*4*` tiles are enclosed by the loop. 189 + 190 + Here's a larger example: 191 + 192 + ``` 193 + .F----7F7F7F7F-7.... 194 + .|F--7||||||||FJ.... 195 + .||.FJ||||||||L7.... 196 + FJL7L7LJLJ||LJ.L-7.. 197 + L--J.L7...LJS7F-7L7. 198 + ....F-J..F7FJ|L7L7L7 199 + ....L7.F7||L7|.L7L7| 200 + .....|FJLJ|FJ|F7|.LJ 201 + ....FJL-7.||.||||... 202 + ....L---J.LJ.LJLJ... 203 + 204 + ``` 205 + 206 + The above sketch has many random bits of ground, some of which are in the loop (`I`) and some of which are outside it (`O`): 207 + 208 + ``` 209 + OF----7F7F7F7F-7OOOO 210 + O|F--7||||||||FJOOOO 211 + O||OFJ||||||||L7OOOO 212 + FJL7L7LJLJ||LJIL-7OO 213 + L--JOL7IIILJS7F-7L7O 214 + OOOOF-JIIF7FJ|L7L7L7 215 + OOOOL7IF7||L7|IL7L7| 216 + OOOOO|FJLJ|FJ|F7|OLJ 217 + OOOOFJL-7O||O||||OOO 218 + OOOOL---JOLJOLJLJOOO 219 + 220 + ``` 221 + 222 + In this larger example, `*8*` tiles are enclosed by the loop. 223 + 224 + Any tile that isn't part of the main loop can count as being enclosed by the loop. Here's another example with many bits of junk pipe lying around that aren't connected to the main loop at all: 225 + 226 + ``` 227 + FF7FSF7F7F7F7F7F---7 228 + L|LJ||||||||||||F--J 229 + FL-7LJLJ||||||LJL-77 230 + F--JF--7||LJLJ7F7FJ- 231 + L---JF-JLJ.||-FJLJJ7 232 + |F|F-JF---7F7-L7L|7| 233 + |FFJF7L7F-JF7|JL---7 234 + 7-L-JL7||F7|L7F-7F7| 235 + L.L7LFJ|||||FJL7||LJ 236 + L7JLJL-JLJLJL--JLJ.L 237 + 238 + ``` 239 + 240 + Here are just the tiles that are *enclosed by the loop* marked with `I`: 241 + 242 + ``` 243 + FF7FSF7F7F7F7F7F---7 244 + L|LJ||||||||||||F--J 245 + FL-7LJLJ||||||LJL-77 246 + F--JF--7||LJLJIF7FJ- 247 + L---JF-JLJIIIIFJLJJ7 248 + |F|F-JF---7IIIL7L|7| 249 + |FFJF7L7F-JF7IIL---7 250 + 7-L-JL7||F7|L7F-7F7| 251 + L.L7LFJ|||||FJL7||LJ 252 + L7JLJL-JLJLJL--JLJ.L 253 + 254 + ``` 255 + 256 + In this last example, `*10*` tiles are enclosed by the loop. 257 + 258 + Figure out whether you have time to search for the nest by calculating the area within the loop. *How many tiles are enclosed by the loop?* 135 259 136 260 Answer: 137 261 138 - You can also [Shareon [Twitter](https://twitter.com/intent/tweet?text=%22Pipe+Maze%22+%2D+Day+10+%2D+Advent+of+Code+2023&url=https%3A%2F%2Fadventofcode%2Ecom%2F2023%2Fday%2F10&related=ericwastl&hashtags=AdventOfCode) [Mastodon](javascript:void(0);)] this puzzle. 262 + Although it hasn't changed, you can still [get your puzzle input](10/input). 263 + 264 + You can also [Shareon [Twitter](https://twitter.com/intent/tweet?text=I%27ve+completed+Part+One+of+%22Pipe+Maze%22+%2D+Day+10+%2D+Advent+of+Code+2023&url=https%3A%2F%2Fadventofcode%2Ecom%2F2023%2Fday%2F10&related=ericwastl&hashtags=AdventOfCode) [Mastodon](javascript:void(0);)] this puzzle.
+23 -10
2023/day10/test.ts
··· 2 2 import * as p1 from "./part1.ts"; 3 3 import * as p2 from "./part2.ts"; 4 4 5 + // ..F7. 6 + // .FJ|. 7 + // SJ.L7 8 + // |F--J 9 + // LJ... 10 + const examples = ["..F7.", ".FJ|.", "SJ.L7", "|F--J", "LJ..."].join("\n"); 11 + const examples2 = [ 12 + "FF7FSF7F7F7F7F7F---7", 13 + "L|LJ||||||||||||F--J", 14 + "FL-7LJLJ||||||LJL-77", 15 + "F--JF--7||LJLJ7F7FJ-", 16 + "L---JF-JLJ.||-FJLJJ7", 17 + "|F|F-JF---7F7-L7L|7|", 18 + "|FFJF7L7F-JF7|JL---7", 19 + "7-L-JL7||F7|L7F-7F7|", 20 + "L.L7LFJ|||||FJL7||LJ", 21 + "L7JLJL-JLJLJL--JLJ.L", 22 + ].join("\n"); 5 23 Deno.test("part1", () => { 6 - // ..F7. 7 - // .FJ|. 8 - // SJ.L7 9 - // |F--J 10 - // LJ... 11 - const examples = ["..F7.", ".FJ|.", "SJ.L7", "|F--J", "LJ..."].join("\n"); 12 24 assertEquals(p1.answer(examples), 8); 25 + assertEquals(p2.answer(examples2), 10); 13 26 }); 14 27 15 - // Deno.test("part2", () => { 16 - // const examples = ["abc", "def"].join("\n"); 17 - // assertEquals(p2.answer(examples), 42); 18 - // }); 28 + Deno.test("part2", () => { 29 + assertEquals(p2.answer(examples), 1); 30 + assertEquals(p2.answer(examples2), 10); 31 + });