From c32296f2431cc20e6f2a7cd7922e5f640c442f79 Mon Sep 17 00:00:00 2001 From: Pascal Syma Date: Tue, 17 Dec 2024 16:09:21 +0100 Subject: [PATCH] Solve 2024-16 (part 1) --- 2024/16/2024-16.run.xml | 7 +++ 2024/16/index.test.ts | 95 +++++++++++++++++++++++++++++++++++++++++ 2024/16/index.ts | 43 +++++++++++++++++++ 2024/16/run.ts | 12 ++++++ utils/queue.ts | 78 +++++++++++++++++++++++++++++++++ 5 files changed, 235 insertions(+) create mode 100644 2024/16/2024-16.run.xml create mode 100644 2024/16/index.test.ts create mode 100644 2024/16/index.ts create mode 100644 2024/16/run.ts create mode 100644 utils/queue.ts diff --git a/2024/16/2024-16.run.xml b/2024/16/2024-16.run.xml new file mode 100644 index 0000000..33524e2 --- /dev/null +++ b/2024/16/2024-16.run.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/2024/16/index.test.ts b/2024/16/index.test.ts new file mode 100644 index 0000000..f891aac --- /dev/null +++ b/2024/16/index.test.ts @@ -0,0 +1,95 @@ +import { describe, expect, it } from 'bun:test'; +import { solveFirst, solveSecond } from './index.ts'; + +describe('2024-16', () => { + it('first', () => { + const testInput = `############### +#.......#....E# +#.#.###.#.###.# +#.....#.#...#.# +#.###.#####.#.# +#.#.#.......#.# +#.#.#####.###.# +#...........#.# +###.#.#####.#.# +#...#.....#.#.# +#.#.#.###.#.#.# +#.....#...#.#.# +#.###.#.#.#.#.# +#S..#.....#...# +###############`; + if (process.env.NODE_ENV === 'production') { + expect(solveFirst(testInput)).toBe(7036); + expect( + solveFirst(`################# +#...#...#...#..E# +#.#.#.#.#.#.#.#.# +#.#.#.#...#...#.# +#.#.#.#.###.#.#.# +#...#.#.#.....#.# +#.#.#.#.#.#####.# +#.#...#.#.#.....# +#.#.#####.#.###.# +#.#.#.......#...# +#.#.###.#####.### +#.#.#...#.....#.# +#.#.#.#####.###.# +#.#.#.........#.# +#.#.#.#########.# +#S#.............# +#################`) + ).toBe(11048); + expect( + solveFirst(`#################################################### +#......................................#..........E# +#......................................#...........# +#....................#.................#...........# +#....................#.................#...........# +#....................#.................#...........# +#....................#.................#...........# +#....................#.................#...........# +#....................#.................#...........# +#....................#.................#...........# +#....................#.................#...........# +#....................#.............................# +#S...................#.............................# +####################################################`) + ).toBe(5078); + expect( + solveFirst(`########################### +#######################..E# +######################..#.# +#####################..##.# +####################..###.# +###################..##...# +##################..###.### +#################..####...# +################..#######.# +###############..##.......# +##############..###.####### +#############..####.......# +############..###########.# +###########..##...........# +##########..###.########### +#########..####...........# +########..###############.# +#######..##...............# +######..###.############### +#####..####...............# +####..###################.# +###..##...................# +##..###.################### +#..####...................# +#.#######################.# +#S........................# +###########################`) + ).toBe(21148); + } + }); + it('second', () => { + // TODO: add second input + const testInput = ``; + // TODO: add second solution + expect(solveSecond(testInput)).toBe(0); + }); +}); diff --git a/2024/16/index.ts b/2024/16/index.ts new file mode 100644 index 0000000..3c71adf --- /dev/null +++ b/2024/16/index.ts @@ -0,0 +1,43 @@ +import { findCoordsOfDigit } from '../../utils/coordinates.ts'; +import { PriorityQueue } from '../../utils/queue.ts'; + +export function solveFirst(input: string): number { + const map = input.split('\n'); + const [x, y] = findCoordsOfDigit(map, 'S')[0]; + const start = { x, y, score: 0, dx: 1, dy: 0 }; + const possibleOptions = new PriorityQueue(); + + possibleOptions.enqueue(start, 0); + const visited = new Set<`${number}:${number}:${number}:${number}`>(); + visited.add(`${start.x}:${start.y}:${start.dx}:${start.dy}`); + + while (possibleOptions.size() > 0) { + const el = possibleOptions.dequeue()!!; + visited.add(`${el.node.x}:${el.node.y}:${el.node.dx}:${el.node.dy}`); + if (map[el.node.y][el.node.x] === 'E') { + return el.node.score; + } + for (let [nx, ny, score, ndx, ndy] of [ + [ + el.node.x + el.node.dx, + el.node.y + el.node.dy, + el.node.score + 1, + el.node.dx, + el.node.dy + ], + [el.node.x, el.node.y, el.node.score + 1000, el.node.dy, -el.node.dx], + [el.node.x, el.node.y, el.node.score + 1000, -el.node.dy, el.node.dx] + ]) { + if (map[ny][nx] === '#') continue; + if (visited.has(`${nx}:${ny}:${ndx}:${ndy}`)) continue; + possibleOptions.enqueue({ x: nx, y: ny, score, dx: ndx, dy: ndy }, score); + } + } + return 0; +} + +export function solveSecond(input: string): number { + // TODO: add code + + return 0; +} diff --git a/2024/16/run.ts b/2024/16/run.ts new file mode 100644 index 0000000..88783cd --- /dev/null +++ b/2024/16/run.ts @@ -0,0 +1,12 @@ +import { join } from 'path'; +import { solveFirst, solveSecond } from './index.ts'; + +const input = await Bun.file(join(__dirname, 'input.txt')).text(); + +const firstAnswer = solveFirst(input); + +console.log(firstAnswer); + +const secondAnswer = solveSecond(input); + +console.log(secondAnswer); diff --git a/utils/queue.ts b/utils/queue.ts new file mode 100644 index 0000000..fcf969b --- /dev/null +++ b/utils/queue.ts @@ -0,0 +1,78 @@ +export class PriorityQueue { + private readonly values: { node: T; priority: number }[] = []; + + enqueue(node: T, priority: number) { + this.values.push({ node, priority }); + this._bubbleUp(); + } + + dequeue() { + if (this.values.length === 0) return null; + + const min = this.values[0]; + const end = this.values.pop(); + + if (this.values.length > 0) { + this.values[0] = end!; + this._sinkDown(); + } + + return min; + } + + size() { + return this.values.length; + } + + _bubbleUp() { + let idx = this.values.length - 1; + const element = this.values[idx]; + + while (idx > 0) { + const parentIdx = Math.floor((idx - 1) / 2); + const parent = this.values[parentIdx]; + + if (element.priority >= parent.priority) break; + + this.values[parentIdx] = element; + this.values[idx] = parent; + idx = parentIdx; + } + } + + _sinkDown() { + let idx = 0; + const length = this.values.length; + const element = this.values[0]; + + while (true) { + const leftChildIdx = 2 * idx + 1; + const rightChildIdx = 2 * idx + 2; + let leftChild, rightChild; + let swap = null; + + if (leftChildIdx < length) { + leftChild = this.values[leftChildIdx]; + if (leftChild.priority < element.priority) { + swap = leftChildIdx; + } + } + + if (rightChildIdx < length) { + rightChild = this.values[rightChildIdx]; + if ( + (swap === null && rightChild.priority < element.priority) || + (swap !== null && rightChild.priority < leftChild!.priority) + ) { + swap = rightChildIdx; + } + } + + if (swap === null) break; + + this.values[idx] = this.values[swap]; + this.values[swap] = element; + idx = swap; + } + } +}