-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.ts
90 lines (73 loc) · 2.38 KB
/
index.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
interface Rule {
before: number
after: number
}
function parseRules(rulesSection: string[]): Rule[] {
return rulesSection.map((line) => {
const [before, after] = line.split('|').map(Number)
return { before, after }
})
}
function isValidSequence(sequence: number[], rules: Rule[]): boolean {
const applicableRules = rules.filter(
rule => sequence.includes(rule.before) && sequence.includes(rule.after),
)
return applicableRules.every((rule) => {
const beforeIndex = sequence.indexOf(rule.before)
const afterIndex = sequence.indexOf(rule.after)
return beforeIndex < afterIndex
})
}
function getMiddleNumber(sequence: number[]): number {
return sequence[Math.floor(sequence.length / 2)]
}
export function part1(input: string) {
const [rulesSection, updatesSection] = groups(input)
const rules = parseRules(rulesSection)
const updates = updatesSection.map(line => line.split(',').map(Number))
return updates
.filter(update => isValidSequence(update, rules))
.map(getMiddleNumber)
.reduce((sum, num) => sum + num, 0)
}
function buildGraph(sequence: number[], rules: Rule[]): Map<number, number[]> {
const graph = new Map<number, number[]>()
sequence.forEach(n => graph.set(n, []))
rules.forEach((rule) => {
if (sequence.includes(rule.before) && sequence.includes(rule.after)) {
const adjacentNodes = graph.get(rule.before) || []
adjacentNodes.push(rule.after)
graph.set(rule.before, adjacentNodes)
}
})
return graph
}
function topologicalSort(sequence: number[], rules: Rule[]): number[] {
const graph = buildGraph(sequence, rules)
const visited = new Set<number>()
const sorted: number[] = []
function visit(node: number) {
if (visited.has(node))
return
visited.add(node)
const neighbors = graph.get(node) || []
for (const neighbor of neighbors)
visit(neighbor)
sorted.unshift(node)
}
sequence.forEach((node) => {
if (!visited.has(node))
visit(node)
})
return sorted
}
export function part2(input: string) {
const [rulesSection, updatesSection] = groups(input)
const rules = parseRules(rulesSection)
const updates = updatesSection.map(line => line.split(',').map(Number))
return updates
.filter(update => !isValidSequence(update, rules))
.map(update => topologicalSort(update, rules))
.map(getMiddleNumber)
.reduce((sum, num) => sum + num, 0)
}