-
Notifications
You must be signed in to change notification settings - Fork 0
/
04.ts
94 lines (83 loc) · 2.53 KB
/
04.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
import {loadData, sum} from '../shared/utils';
type Numbers = Array<number>;
type Board = Array<Array<number>>;
type Data = [Numbers, Array<Board>];
export const parseData = (data: Array<string>): Data => [
/* istanbul ignore next */
data.shift()?.split(',').map(Number) ?? [],
data.map(board =>
board.split('\n').map(row =>
row
.split(/\ +/)
.filter(v => v.trim() !== '')
.map(Number)
)
),
];
/* istanbul ignore next */
export const parse = async (): Promise<Data> =>
parseData((await loadData(2021, 4)).split('\n\n'));
function hasBoardWon(board: Board, numbers: Numbers): boolean {
for (let row of board) {
if (row.every(n => numbers.includes(n))) {
return true;
}
}
for (let col = 0; col < board[0].length; col += 1) {
if (board.map(row => row[col]).every(n => numbers.includes(n))) {
return true;
}
}
return false;
}
function unmarkedNumbers(board: Board, numbers: Numbers): Numbers {
return board
.reduce((nums, row) => nums.concat(...row), [])
.filter(n => !numbers.includes(n));
}
function getWinningNumbersForBoard(board: Board, numbers: Numbers): Numbers {
for (let i = 0; i < numbers.length; i += 1) {
if (hasBoardWon(board, numbers.slice(0, i))) {
return numbers.slice(0, i);
}
}
/* istanbul ignore next */
return numbers;
}
function getBestBoard(
boards: Array<Board>,
numbers: Numbers,
comparison: (n1: Numbers, n2: Numbers) => boolean
): [Board | null, Numbers] {
let winningNumbers: Numbers = [];
let winningBoard: Board | null = null;
for (let board of boards) {
const boardNumbers = getWinningNumbersForBoard(board, numbers);
if (winningBoard == null || comparison(boardNumbers, winningNumbers)) {
winningBoard = board;
winningNumbers = boardNumbers;
}
}
return [winningBoard, winningNumbers];
}
function getBoardValue(board: Board, numbers: Numbers): number {
return sum(unmarkedNumbers(board, numbers)) * numbers[numbers.length - 1];
}
export const part1 = ([numbers, boards]: Data): number => {
const [bestBoard, bestNumbers] = getBestBoard(
boards,
numbers,
(n1, n2) => n1.length < n2.length
);
/* istanbul ignore next */
return bestBoard == null ? NaN : getBoardValue(bestBoard, bestNumbers);
};
export const part2 = ([numbers, boards]: Data): number => {
const [bestBoard, bestNumbers] = getBestBoard(
boards,
numbers,
(n1, n2) => n1.length > n2.length
);
/* istanbul ignore next */
return bestBoard == null ? NaN : getBoardValue(bestBoard, bestNumbers);
};