Skip to content

Commit 914864a

Browse files
committed
[ts] 2024:05: Solve day05
1 parent 3e60e7e commit 914864a

File tree

1 file changed

+118
-0
lines changed

1 file changed

+118
-0
lines changed

2024/day05/day05.ts

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// @ts-ignore - tl_ls is missing @types/node
2+
import { EOL } from "node:os";
3+
// @ts-ignore - tl_ls doesn't know about Bun
4+
const inputSections = (await Bun.file("input").text()).trim().split(`${EOL}${EOL}`);
5+
6+
declare global {
7+
interface Array<T> {
8+
biFilter(filter: (subj: T) => boolean): [Array<T>, Array<T>];
9+
getMiddle(): T;
10+
remove(candidate: T): void;
11+
}
12+
}
13+
14+
Array.prototype.biFilter = function<T>(this: Array<T>, filter: (subj: T) => boolean) {
15+
const matches: Array<T> = [];
16+
const unmatches: Array<T> = [];
17+
this.forEach((elem: T) => {
18+
if (filter(elem)) matches.push(elem);
19+
else unmatches.push(elem);
20+
});
21+
return [matches, unmatches];
22+
}
23+
Array.prototype.getMiddle = function<T>(this: Array<T>) {
24+
const middleInx = (this.length - 1) / 2;
25+
if (middleInx % 1 != 0) {
26+
console.error("Invalid middle index", middleInx, "for Array", this);
27+
}
28+
return this[middleInx];
29+
}
30+
Array.prototype.remove = function<T>(this: Array<T>, candidate: T) {
31+
let inx = this.indexOf(candidate);
32+
while (inx != -1) {
33+
this.splice(inx, 1);
34+
inx = this.indexOf(candidate);
35+
}
36+
}
37+
38+
const rules: Array<[number, number]> = inputSections[0]
39+
.split(EOL)
40+
.map((ruleLine: string) => (
41+
ruleLine.split("|").map((rulePart) => parseInt(rulePart))
42+
));
43+
const updates: Array<Array<number>> = inputSections[1]
44+
.split(EOL)
45+
.map((updateLine: string) => (
46+
updateLine.split(",").map((updatePart) => parseInt(updatePart))
47+
));
48+
49+
const dependencyMap: Map<number, Array<number>> = new Map();
50+
for (let [earlier, later] of rules) {
51+
// Push to existing array
52+
dependencyMap.get(later)?.push(earlier)
53+
// or set new array if none exists
54+
?? dependencyMap.set(later, [earlier]);
55+
}
56+
57+
function isValidUpdate(update: Array<number>): boolean {
58+
const banList: Array<number> = [];
59+
for (let page of update) {
60+
if (banList.includes(page)) return false;
61+
62+
const newBans = dependencyMap.get(page);
63+
if (newBans) banList.push(...newBans);
64+
}
65+
return true;
66+
}
67+
68+
69+
const [validUpdates, invalidUpdates] = updates.biFilter(isValidUpdate);
70+
71+
const solution1 = validUpdates
72+
.map((validUpdate) => validUpdate.getMiddle())
73+
.reduce((acc, middleNum) => acc + middleNum);
74+
75+
const solution2 = invalidUpdates
76+
.map((invalidUpdate) => {
77+
// Enumerate relevant dependencies
78+
const missingDependencies: Map<number, Array<number>> = new Map();
79+
for (let page of invalidUpdate) {
80+
let pageDependencies = dependencyMap.get(page);
81+
pageDependencies = pageDependencies
82+
? [...pageDependencies].filter((n) => invalidUpdate.includes(n))
83+
: [];
84+
missingDependencies.set(page, pageDependencies);
85+
}
86+
87+
console.log("update:", invalidUpdate);
88+
89+
// Re-construct the update in a valid order
90+
invalidUpdate = [];
91+
while (missingDependencies.size > 0) {
92+
let loopc = 0;
93+
for (let [page, dependencies] of missingDependencies.entries()) {
94+
if (loopc > missingDependencies.size) {
95+
console.error("Infinite loop!");
96+
// @ts-ignore - tl_ls is missing @types/node
97+
process.exit();
98+
}
99+
100+
if (dependencies.length > 0) {
101+
continue;
102+
}
103+
104+
loopc = 0;
105+
invalidUpdate.push(page);
106+
missingDependencies.delete(page);
107+
for (let [otherPage, _] of missingDependencies) {
108+
missingDependencies.get(otherPage)!.remove(page);
109+
}
110+
}
111+
}
112+
113+
return invalidUpdate;
114+
}).map((validUpdate) => validUpdate.getMiddle())
115+
.reduce((acc, middleNum) => acc + middleNum);
116+
117+
console.log("Part 1:", solution1);
118+
console.log("Part 2:", solution2);

0 commit comments

Comments
 (0)