Skip to content

Commit

Permalink
16/2024
Browse files Browse the repository at this point in the history
  • Loading branch information
breadadams committed Dec 16, 2024
1 parent 08991f2 commit d03d5c2
Show file tree
Hide file tree
Showing 4 changed files with 261 additions and 0 deletions.
17 changes: 17 additions & 0 deletions 2024/16/example.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#################
#...#...#...#..E#
#.#.#.#.#.#.#.#.#
#.#.#.#...#...#.#
#.#.#.#.###.#.#.#
#...#.#.#.....#.#
#.#.#.#.#.#####.#
#.#...#.#.#.....#
#.#.#####.#.###.#
#.#.#.......#...#
#.#.###.#####.###
#.#.#...#.....#.#
#.#.#.#####.###.#
#.#.#.........#.#
#.#.#.#########.#
#S#.............#
#################
25 changes: 25 additions & 0 deletions 2024/16/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { expect, describe, test } from "bun:test";
import { part1, part2 } from ".";
import { getInputs } from "../../utils/get-inputs";

const { exampleInput, puzzleInput } = await getInputs("2024/16");

describe("part 1", () => {
test("example", () => {
expect(part1(exampleInput)).toBe(11048);
});

test("puzzle", () => {
expect(part1(puzzleInput)).toBe(92432);
});
});

describe("part 2", () => {
test("example", () => {
expect(part2(exampleInput)).toBe(64);
});

test("puzzle", () => {
expect(part2(puzzleInput)).toBe(458);
});
});
218 changes: 218 additions & 0 deletions 2024/16/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
import { timePart1, timePart2 } from "../../utils/time-part";

const parseInput = (input: string) => {
return input.split("\n").map((row) => row.split(""));
};

type InputMap = ReturnType<typeof parseInput>;

const findCell = (char: string, map: InputMap) => {
const y = map.findIndex((row) => row.includes(char));
const x = map[y].indexOf(char);

return { x, y };
};

const getStartingPosition = (map: InputMap) => findCell("S", map);
const getEndPosition = (map: InputMap) => findCell("E", map);

const DIRECTIONS = ["N", "E", "S", "W"] as const;
type Direction = (typeof DIRECTIONS)[number];

type Coordinate = { x: number; y: number };

const positionToKey = (position: Coordinate, direction?: Direction) => {
const positionKey = `${position.x},${position.y}`;

if (direction) {
return `${positionKey}:${direction}`;
}

return positionKey;
};

const rotate = (
direction: Direction,
{ clockwise } = { clockwise: true }
): Direction => {
if (direction === "N" && !clockwise) {
return "W";
}

return DIRECTIONS[
(DIRECTIONS.indexOf(direction) + (clockwise ? 1 : -1)) % DIRECTIONS.length
];
};

const MOVEMENTS = {
N: { x: 0, y: -1 },
E: { x: 1, y: 0 },
S: { x: 0, y: 1 },
W: { x: -1, y: 0 },
} satisfies Record<Direction, Coordinate>;

const move = (position: Coordinate, direction: Direction) => {
const movement = MOVEMENTS[direction];

return { x: position.x + movement.x, y: position.y + movement.y };
};

const readCell = ({ x, y }: Coordinate, map: InputMap) => map[y]?.[x];

type QueueEntry = {
direction: Direction;
position: Coordinate;
score: number;
visited: Coordinate[];
};

const getBestScore = (map: InputMap) => {
const start = getStartingPosition(map);
const end = getEndPosition(map);

const queue: QueueEntry[] = [
{
direction: "E",
position: start,
score: 0,
visited: [start],
},
];

const globalVisited = new Set<string>();
let bestScore: number | null = null;

while (queue.length) {
queue.sort((a, b) => a.score - b.score);

const route = queue.shift()!;
const baseKey = positionToKey(route.position, route.direction);

if (globalVisited.has(baseKey)) {
continue;
}
globalVisited.add(baseKey);

if (route.position.x === end.x && route.position.y === end.y) {
if (typeof bestScore !== "number" || route.score < bestScore) {
bestScore = route.score;
}

continue;
}

const movedForward = move(route.position, route.direction);
const cell = readCell(movedForward, map);

if (cell !== "#") {
queue.push({
...route,
position: movedForward,
score: route.score + 1,
visited: [...route.visited, movedForward],
});
}

queue.push({
...route,
direction: rotate(route.direction),
score: route.score + 1000,
visited: [...route.visited],
});

queue.push({
...route,
direction: rotate(route.direction, { clockwise: false }),
score: route.score + 1000,
visited: [...route.visited],
});
}

return bestScore ?? 0;
};

export const part1 = timePart1((input: string) => {
const map = parseInput(input);
const bestScore = getBestScore(map);

return bestScore;
});

export const part2 = timePart2((input: string) => {
const map = parseInput(input);
const bestScore = getBestScore(map);
const startingPosition = getStartingPosition(map);
const endPosition = getEndPosition(map);

const queue: QueueEntry[] = [
{
visited: [startingPosition],
position: startingPosition,
direction: "E",
score: 0,
},
];

const globalVisited = new Map<string, number>();
const pathsToEnd: QueueEntry["visited"][] = [];

while (queue.length) {
const route = queue.shift()!;
const baseKey = positionToKey(route.position, route.direction);

if (
route.score > bestScore ||
(globalVisited.has(baseKey) && globalVisited.get(baseKey)! < route.score)
) {
continue;
}

globalVisited.set(baseKey, route.score);

if (
route.position.x === endPosition.x &&
route.position.y === endPosition.y &&
route.score === bestScore
) {
pathsToEnd.push(route.visited);
continue;
}

const movedForward = move(route.position, route.direction);
const cell = readCell(movedForward, map);

if (cell !== "#") {
queue.push({
...route,
position: movedForward,
score: route.score + 1,
visited: [...route.visited, movedForward],
});
}

queue.push({
...route,
direction: rotate(route.direction),
score: route.score + 1000,
visited: [...route.visited],
});

queue.push({
...route,
direction: rotate(route.direction, { clockwise: false }),
score: route.score + 1000,
visited: [...route.visited],
});
}

const bestSeats = new Set<string>();

for (const pathToGoal of pathsToEnd) {
for (const position of pathToGoal) {
const key = positionToKey(position);
bestSeats.add(key);
}
}

return bestSeats.size;
});
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

| Day | Part 1 | Part 2 |
| :----------------------------------------: | :----: | :----: |
| [16](https://adventofcode.com/2024/day/16) |||
| [15](https://adventofcode.com/2024/day/15) |||
| [14](https://adventofcode.com/2024/day/14) |||
| [13](https://adventofcode.com/2024/day/13) |||
Expand Down

0 comments on commit d03d5c2

Please sign in to comment.