-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path12.js
110 lines (88 loc) · 2.24 KB
/
12.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
const R = require('ramda')
const { parseLines, parseDecimal, applyN, lcm } = require('../utils')
const REGEX_MOON = /^<x=(-?\d+), y=(-?\d+), z=(-?\d+)>$/
const parseMoon = R.pipe(
R.match(REGEX_MOON),
R.slice(1, 4),
R.map(parseDecimal),
(pos) => ({
pos,
vel: [0, 0, 0],
}),
)
const parseMoons = R.pipe(
parseLines,
R.map(parseMoon),
R.addIndex(R.map)((x, i) => ({ ...x, i })),
)
const getPairGravity = ([{ pos: a }, { pos: b }]) =>
R.pipe(
R.zip,
R.map(
R.apply(
R.cond([
[R.lt, R.always(+1)],
[R.gt, R.always(-1)],
[R.equals, R.always(0)],
]),
),
),
)(a, b)
const getPairsGravity = R.pipe(R.map(getPairGravity), (x) =>
x.reduce(R.pipe(R.zip, R.map(R.apply(R.add)))),
)
const getGravities = R.pipe(
R.converge(R.xprod, [R.identity, R.identity]),
R.filter(([{ i: a }, { i: b }]) => a !== b),
R.groupBy(R.path([0, 'i'])),
R.values,
R.map(getPairsGravity),
)
const v3add = ([x0, y0, z0], [x1, y1, z1]) => [x0 + x1, y0 + y1, z0 + z1]
const applyGravities = R.pipe(
R.converge(R.zip, [R.identity, getGravities]),
R.map(([x, g]) => ({
...x,
vel: v3add(x.vel, g),
})),
)
const applyVelocities = R.map((x) => ({ ...x, pos: v3add(x.pos, x.vel) }))
const step = R.pipe(applyGravities, applyVelocities)
const propEnergy = (prop) => R.pipe(R.prop(prop), R.map(Math.abs), R.sum)
const getMoonEnergy = R.converge(R.multiply, [
propEnergy('pos'),
propEnergy('vel'),
])
const getEnergy = R.pipe(R.map(getMoonEnergy), R.sum)
const part1 = R.pipe(parseMoons, applyN(step, 1000), getEnergy)
const getStateHash = (dim) =>
R.pipe(
R.converge(R.pair, [
R.pipe(R.pluck('pos'), R.map(R.nth(dim))),
R.pipe(R.pluck('vel'), R.map(R.nth(dim))),
]),
)
const getDimPeriod = R.curry((dim, input) => {
let state = parseMoons(input)
const getDimStateHash = getStateHash(dim)
const initHash = getDimStateHash(state)
for (let i = 1; ; i++) {
state = step(state)
if (R.equals(getDimStateHash(state), initHash)) {
return i
}
}
})
const part2 = (input) =>
[
getDimPeriod(0, input),
getDimPeriod(1, input),
getDimPeriod(2, input),
].reduce(lcm)
module.exports = {
parseMoons,
step,
getEnergy,
part1,
part2,
}