-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday18.ts
114 lines (99 loc) · 2.72 KB
/
day18.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import type { Day } from './Day.ts';
import type { Pos } from './utils.ts';
export class DayImpl implements Day {
private readonly input: Pos[];
constructor(input: string) {
this.input = this.parseInput(input);
}
parseInput(input: string) {
return input
.trim()
.split('\n')
.map((line: string) => {
return line
.split(',')
.map(Number) as Pos;
});
}
partOne() {
return findPath(this.input, 1024);
}
partTwo() {
const obstacles = this.input;
let latestPossible = 0;
let firstImpossible = obstacles.length;
while (firstImpossible - latestPossible > 1) {
const middle = Math.trunc((firstImpossible + latestPossible) / 2);
const isPossible = findPath(obstacles, middle) > -1;
if (isPossible) {
latestPossible = middle;
}
else {
firstImpossible = middle;
}
}
const bummer = obstacles[firstImpossible - 1];
return `${bummer[0]},${bummer[1]}`;
}
}
export function findPath(obstacles: Pos[], length: number) {
const gridSize = getGridSize(obstacles);
const obstacleSet = new Set<string>();
for (let i = 0; i < length; ++i) {
obstacleSet.add(getKey(obstacles[i]));
}
let queue = [{ pos: [0, 0] as Pos, cost: 0 }];
const visited = new Map<string, number>();
let minResult = Infinity;
visited.set(getKey(queue[0].pos), 0);
while (queue.length > 0) {
const next = [];
for (const entry of queue) {
const candidates: Pos[] = [
[entry.pos[0] + 1, entry.pos[1]],
[entry.pos[0] - 1, entry.pos[1]],
[entry.pos[0], entry.pos[1] - 1],
[entry.pos[0], entry.pos[1] + 1],
];
for (const pos of candidates) {
if (pos[0] < 0 || pos[0] > gridSize) {
continue;
}
if (pos[1] < 0 || pos[1] > gridSize) {
continue;
}
if (obstacleSet.has(getKey(pos))) {
continue;
}
const currentCost = getOrDefault(visited, getKey(pos), Infinity);
const nextCost = entry.cost + 1;
if (nextCost >= currentCost) {
continue;
}
next.push({ pos, cost: nextCost });
visited.set(getKey(pos), nextCost);
if (pos[0] === gridSize && pos[1] === gridSize) {
if (entry.cost <= minResult) {
minResult = entry.cost;
}
}
}
}
queue = next;
}
if (minResult !== Infinity) {
return minResult + 1;
}
else {
return -1;
}
}
function getKey(pos: Pos) {
return `${pos[0]}:${pos[1]}`;
}
function getGridSize(obstacles: Pos[]) {
return Math.max(...obstacles.flatMap(pos => pos));
}
function getOrDefault<K, V>(map: Map<K, V>, key: K, def: V): V {
return map.get(key) ?? def;
}