-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.ts
executable file
·109 lines (89 loc) · 2.76 KB
/
main.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
#!/usr/bin/env deno run --allow-read
import { assertEquals } from "https://deno.land/[email protected]/testing/asserts.ts";
import { Coord, SparseCoordArray, sum } from "../../2020/utils.ts";
type Line = [Coord, Coord];
type Input = Line[];
export type LineCoverage = SparseCoordArray<number>;
export const MIN_LINE_COVERAGE = 2;
const parseCoord = (s: string): Coord => {
const [s1, s2] = s.split(",");
return [parseInt(s1, 10), parseInt(s2, 10)];
};
export const parseInput = (string: string): Input => {
const lines = string.trim().split(/\s*\n\s*/);
return lines.map((line) => {
const [fromString, toString] = line.split(/\s*->\s*/);
return [parseCoord(fromString), parseCoord(toString)];
});
};
const text = await Deno.readTextFile("input.txt");
const input = parseInput(text);
const orderPairBy = (index: 0 | 1) =>
([from, to]: Line): Line => from[index] > to[index] ? [to, from] : [from, to];
export const countSpotsAboveMinLineCoverage = (
lineCoverage: LineCoverage,
): number => {
return sum(
Object.values(lineCoverage).flatMap((row) =>
Object.values(row).filter((n) => n >= MIN_LINE_COVERAGE).length
),
);
};
export const calculateCoverage = (
input: Input,
enableDiagonals: boolean,
callback: (lineCoverage: LineCoverage) => void = () => {},
): LineCoverage => {
const lineCoverage: LineCoverage = {};
const inreaseLineCoverageAt = ([x, y]: Coord) => {
lineCoverage[y] ??= {};
lineCoverage[y][x] ??= 0;
lineCoverage[y][x]++;
};
input.map(orderPairBy(1)).map(orderPairBy(0)).forEach(
([[fromX, fromY], [toX, toY]]) => {
if (fromX === toX) {
const x = fromX;
for (let y = fromY; y <= toY; y++) {
inreaseLineCoverageAt([x, y]);
}
} else if (fromY === toY) {
const y = fromY;
for (let x = fromX; x <= toX; x++) {
inreaseLineCoverageAt([x, y]);
}
} else {
if (enableDiagonals) {
for (let x = fromX; x <= toX; x++) {
const y = fromY + (x - fromX) * Math.sign(toY - fromY);
inreaseLineCoverageAt([x, y]);
}
}
}
callback(lineCoverage);
},
);
return lineCoverage;
};
const part1 = (input: Input): number => {
return countSpotsAboveMinLineCoverage(calculateCoverage(input, false));
};
const example = parseInput(`
0,9 -> 5,9
8,0 -> 0,8
9,4 -> 3,4
2,2 -> 2,1
7,0 -> 7,4
6,4 -> 2,0
0,9 -> 2,9
3,4 -> 1,4
0,0 -> 8,8
5,5 -> 8,2
`);
assertEquals(part1(example), 5, "Example is wrong!");
console.log("Result part 1: " + part1(input));
const part2 = (input: Input): number => {
return countSpotsAboveMinLineCoverage(calculateCoverage(input, true));
};
assertEquals(part2(example), 12, "Example is wrong!");
console.log("Result part 2: " + part2(input));