-
Notifications
You must be signed in to change notification settings - Fork 0
/
day15.js
126 lines (105 loc) · 2.92 KB
/
day15.js
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
115
116
117
118
119
120
121
122
123
124
125
126
'use strict' // Finding the least risky path thru labyrinth.
const { assert, loadData, parseInt } = require('./core/utils')
const rawInput = [loadData(module.filename), 0, 0, 0]
rawInput[3] = loadData('day15d.txt')
/** @param {number} dsn */
const parse = (dsn) => {
let data = rawInput[dsn]
if (data && (data = data.split('\n').filter(v => Boolean(v))).length) {
return data.map(row => Array.from(row).map(parseInt))
}
return data
}
const dirs = [[0, -1], [-1, 0], [0, 1], [1, 0]], nDirs = dirs.length
/** @param {number[][]} risksOfXY */
const solve = (risksOfXY) => {
const cumulativeRisks = []
const height = risksOfXY.length, width = height && risksOfXY[0].length
let wasChanged
for (let y = 0; y < height; ++y) {
cumulativeRisks.push(new Array(width).fill(Number.MAX_SAFE_INTEGER))
}
const findBestPreviousScoreFor = (x0, y0) => {
let lesser = Number.MAX_SAFE_INTEGER
for (let i = 0, x, y, value; i < nDirs && ([x, y] = dirs[i]); ++i) {
if ((x += x0) >= 0 && (y += y0) >= 0 && x < width && y < height) {
if ((value = cumulativeRisks[y][x]) < lesser) {
lesser = value
}
}
}
return lesser
}
const borderCoordsFor = (x1, y1) => {
const coords = []
for (let i = 0; i < x1; ++i) coords.push([i, y1])
for (let i = 0; i < y1; ++i) coords.push([x1, i])
coords.push([x1, y1])
return coords
}
const expandRisksMapTo = (x1, y1) => {
let coords = borderCoordsFor(x1, y1), v
for (const [x, y] of coords) {
v = findBestPreviousScoreFor(x, y) + risksOfXY[y][x]
if (cumulativeRisks[y][x] > v) {
cumulativeRisks[y][x] = v
wasChanged = true
}
}
}
cumulativeRisks[0][0] = 0
do {
wasChanged = false
for (let i = 1; i < height; ++i) {
expandRisksMapTo(i, i)
}
} while (wasChanged)
return cumulativeRisks[height - 1][width - 1]
}
/**
* @param {*[]} input
*/
const puzzle1 = (input) => solve(input)
/**
* @param {*[]} input
* @param {TOptions} options
*/
const puzzle2 = (input, options) => {
const data = [], testData = options.isDemo && parse(3)
const height = input.length, width = height && input[0].length
for (let y = 0; y < 5 * height; ++y) {
const row = new Array(5 * width)
for (let r, src, x = 0; x < 5 * width; ++x) {
if (y < height) {
if (x < width) {
row[x] = input[y][x]
} else {
row[x] = (r = row[x - width] + 1) > 9 ? r = r - 9 : r
}
} else {
src = data[y - height]
row[x] = (r = src[x] + 1) > 9 ? r = r - 9 : r
}
}
if (testData) {
for (let i = 0; i < width; ++i) assert(row[i] === testData[y][i], 'bad data')
}
data.push(row)
}
return solve(data)
}
// Example (demo) data.
rawInput[1] = `
1163751742
1381373672
2136511328
3694931569
7463417111
1319128137
1359912421
3125421639
1293138521
2311944581`
module.exports = { parse, puzzles: [puzzle1, puzzle2] }
/*
*/