Solve 2024-16 (part 1)
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="2024-16" type="BunRunConfiguration">
|
||||
<option name="program" value="2024/16/run.ts" />
|
||||
<option name="workingDirectory" value="$PROJECT_DIR$" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
@@ -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<typeof start>();
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -0,0 +1,78 @@
|
||||
export class PriorityQueue<T> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user