-
Notifications
You must be signed in to change notification settings - Fork 0
/
21.js
119 lines (104 loc) · 2.77 KB
/
21.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
const isTesting = false;
const input = isTesting
? `root: pppw + sjmn
dbpl: 5
cczh: sllz + lgvd
zczc: 2
ptdq: humn - dvpt
dvpt: 3
lfqf: 4
humn: 5
ljgn: 2
sjmn: drzm * dbpl
sllz: 4
pppw: cczh / lfqf
lgvd: ljgn * ptdq
drzm: hmdt - zczc
hmdt: 32`
: ``;
const monkeys = input
.split("\n")
.map((s) => s.trim().split(": "))
.map(([monkey, job]) => ({
monkey,
job: !Number.isNaN(Number(job)) ? Number(job) : job.split(" "),
}));
const op = (sign) => {
switch (sign) {
case "+":
return (a, b) => a + b;
case "-":
return (a, b) => a - b;
case "*":
return (a, b) => a * b;
case "/":
return (a, b) => a / b;
}
};
const reverseOp = (sign, knownValueIsB) => {
switch (sign) {
case "+":
// X + B = C -> X = C - B
// A + X = C -> X = C - A
return (b, c) => c - b;
case "-":
// X - B = C -> X = C + B
// A - X = C -> X = A - C
return knownValueIsB ? (b, c) => c + b : (a, c) => a - c;
case "*":
// X * B = C -> X = C / B
// A * X = C -> X = C / A
return (b, c) => c / b;
case "/":
// X / B = C -> X = C * B
// A / X = C -> X = A / C
return knownValueIsB ? (b, c) => c * b : (a, c) => a / c;
}
};
const willYell = (monkey, cache = {}) => {
if (cache[monkey] === undefined) {
const { job } = monkeys.find((m) => m.monkey === monkey);
if (typeof job === "number") {
cache[monkey] = job;
} else {
const [a, sign, b] = job;
cache[monkey] = op(sign)(willYell(a, cache), willYell(b, cache));
}
}
return cache[monkey];
};
const hasHuman = (monkey) => {
if (monkey === "humn") return true;
const { job } = monkeys.find((m) => m.monkey === monkey);
if (typeof job === "number") {
return false;
} else {
const [a, , b] = job;
return hasHuman(a) || hasHuman(b);
}
};
const yellReverse = (outerValue, monkey) => {
if (monkey === "humn") return outerValue;
const { job } = monkeys.find((m) => m.monkey === monkey);
if (typeof job === "number") return job;
const [a, sign, b] = job;
const aHasHuman = hasHuman(a);
const treeWithHuman = aHasHuman ? a : b;
const valueFromNonHumanTree = willYell(aHasHuman ? b : a, {});
const valueToMatch =
monkey === "root"
? valueFromNonHumanTree
: reverseOp(sign, aHasHuman)(valueFromNonHumanTree, outerValue);
console.log(
monkey,
`human is in ${treeWithHuman} [${aHasHuman ? "A" : "B"}]`,
aHasHuman
? `HUMAN ${sign} ${valueFromNonHumanTree} = ${outerValue}`
: `${valueFromNonHumanTree} ${sign} HUMAN = ${outerValue}`,
"->",
`HUMAN = ${valueToMatch}`
);
return yellReverse(valueToMatch, treeWithHuman);
};
console.log("Part 1", willYell("root"));
console.log("Part 2", yellReverse(null, "root"));