1
+ package com .macasaet ;
2
+
3
+ import org .junit .jupiter .api .Test ;
4
+
5
+ import java .util .Collections ;
6
+ import java .util .HashMap ;
7
+ import java .util .Map ;
8
+ import java .util .stream .StreamSupport ;
9
+
10
+ /**
11
+ * --- Day 21: Monkey Math ---
12
+ * <a href="https://adventofcode.com/2022/day/21">https://adventofcode.com/2022/day/21</a>
13
+ */
14
+ public class Day21 {
15
+
16
+ public record Monkey (String name , Job job ) {
17
+ public long yell (final Map <String , Monkey > monkeys , final Map <String , Long > results ) {
18
+ return job ().yell (monkeys , results );
19
+ }
20
+
21
+ public Simplification simplify (final Map <String , Monkey > monkeys , final Map <String , Long > results ) {
22
+ return job ().simplify (monkeys , results );
23
+ }
24
+
25
+ public static Monkey parse (final String line ) {
26
+ final var components = line .split (": " );
27
+ final var name = components [0 ].trim ();
28
+ final var job = Job .parse (components [1 ].trim ());
29
+ return new Monkey (name , job );
30
+ }
31
+ }
32
+
33
+ public interface Simplification {
34
+ Simplification simplify ();
35
+ }
36
+
37
+ record Expression (Simplification x , Operation operation , Simplification y ) implements Simplification {
38
+
39
+ public Simplification simplify () {
40
+ final var simpleX = x ().simplify ();
41
+ final var simpleY = y ().simplify ();
42
+ if (!x ().equals (simpleX ) || !y ().equals (simpleY )) {
43
+ return new Expression (simpleX , operation (), simpleY );
44
+ } else if (x () instanceof Value && y () instanceof Value ) {
45
+ return new Value (operation ().operate (((Value ) x ).value (), ((Value ) y ).value ()));
46
+ } else if (operation () == Operation .IS_EQUAL ) {
47
+ if (x () instanceof final Value constant && y () instanceof final Expression expression ) {
48
+ // e.g. 5=2/x or 5=x/2
49
+ final var inverse = expression .operation ().inverse ();
50
+ if (expression .x () instanceof Value ) {
51
+ // e.g. 5=2/x
52
+ if (expression .operation .isSymmetric ()) {
53
+ // e.g. 2=5x -> 10=x
54
+ final var lValue = new Expression (constant , inverse , expression .x ()).simplify ();
55
+ return new Expression (lValue , Operation .IS_EQUAL , expression .y ());
56
+ } else {
57
+ // e.g. 5=2/x -> 5x=2
58
+ final var lValue = new Expression (constant , inverse , expression .y ());
59
+ return new Expression (lValue , Operation .IS_EQUAL , expression .x ());
60
+ }
61
+ } else if (expression .y () instanceof Value ) {
62
+ // e.g. 5=x/2 -> 5*2=x -> 10=x
63
+ final var lValue = new Expression (constant , inverse , expression .y ()).simplify ();
64
+ return new Expression (lValue , Operation .IS_EQUAL , expression .x ());
65
+ }
66
+ // cannot simplify further
67
+ return this ;
68
+ } else if (x () instanceof final Expression expression && y () instanceof final Value constant ) {
69
+ // e.g. 5/x=2 or x/5=2
70
+ final var inverse = expression .operation ().inverse ();
71
+ if (expression .x () instanceof Value ) {
72
+ // e.g. 5/x=2 or x/5=2
73
+ if (expression .operation ().isSymmetric ()) {
74
+ // e.g. 2x=5 -> x=5*2 -> x=10
75
+ final var rValue = new Expression (constant , inverse , expression .x ()).simplify ();
76
+ return new Expression (expression .y (), Operation .IS_EQUAL , rValue );
77
+ } else {
78
+ // e.g. 5/x=2 -> 5=2x
79
+ final var rValue = new Expression (constant , inverse , expression .y ());
80
+ return new Expression (expression .x (), Operation .IS_EQUAL , rValue );
81
+ }
82
+ } else if (expression .y () instanceof Value ) {
83
+ // e.g. x/5=2 -> x=2*5 -> x=10
84
+ final var rValue = new Expression (constant , inverse , expression .y ()).simplify ();
85
+ return new Expression (expression .x (), Operation .IS_EQUAL , rValue );
86
+ }
87
+ // cannot simplify further
88
+ return this ;
89
+ }
90
+ }
91
+ return this ;
92
+ }
93
+
94
+ public String toString () {
95
+ return "(" + x () + ") " + operation () + " (" + y () + ")" ;
96
+ }
97
+ }
98
+
99
+ record Value (long value ) implements Simplification {
100
+ public String toString () {
101
+ return "" + value ();
102
+ }
103
+
104
+ public Simplification simplify () {
105
+ return this ;
106
+ }
107
+ }
108
+
109
+ record Variable () implements Simplification {
110
+ public String toString () {
111
+ return "x" ;
112
+ }
113
+
114
+ public Simplification simplify () {
115
+ return this ;
116
+ }
117
+ }
118
+
119
+ public interface Job {
120
+ long yell (final Map <String , Monkey > monkeys , final Map <String , Long > results );
121
+
122
+ Simplification simplify (final Map <String , Monkey > monkeys , final Map <String , Long > results );
123
+
124
+ static Job parse (final String string ) {
125
+ final var components = string .trim ().split (" " );
126
+ if (components .length == 1 ) {
127
+ return Yell .parse (string .trim ());
128
+ }
129
+ return Math .parse (components );
130
+ }
131
+ }
132
+
133
+ public enum Operation {
134
+ Add {
135
+ public long operate (final long x , final long y ) {
136
+ return x + y ;
137
+ }
138
+
139
+ public Operation inverse () {
140
+ return Subtract ;
141
+ }
142
+
143
+ public boolean isSymmetric () {
144
+ return true ;
145
+ }
146
+ },
147
+ Subtract {
148
+ public long operate (final long x , final long y ) {
149
+ return x - y ;
150
+ }
151
+
152
+ public Operation inverse () {
153
+ return Add ;
154
+ }
155
+
156
+ public boolean isSymmetric () {
157
+ return false ;
158
+ }
159
+ },
160
+ Multiply {
161
+ public long operate (final long x , final long y ) {
162
+ return x * y ;
163
+ }
164
+
165
+ public Operation inverse () {
166
+ return Divide ;
167
+ }
168
+
169
+ public boolean isSymmetric () {
170
+ return true ;
171
+ }
172
+ },
173
+ Divide {
174
+ public long operate (final long x , final long y ) {
175
+ return x / y ;
176
+ }
177
+
178
+ public Operation inverse () {
179
+ return Multiply ;
180
+ }
181
+
182
+ public boolean isSymmetric () {
183
+ return false ;
184
+ }
185
+ },
186
+ IS_EQUAL {
187
+ public long operate (final long x , final long y ) {
188
+ // what a horrible hack, who would do this?
189
+ return x == y ? 1L : 0L ;
190
+ }
191
+
192
+ public Operation inverse () {
193
+ return IS_EQUAL ;
194
+ }
195
+
196
+ public boolean isSymmetric () {
197
+ return true ;
198
+ }
199
+ };
200
+
201
+ public abstract long operate (long x , long y );
202
+
203
+ public abstract Operation inverse ();
204
+
205
+ public abstract boolean isSymmetric ();
206
+
207
+ public String toString () {
208
+ return switch (this ) {
209
+ case Add -> "+" ;
210
+ case Subtract -> "-" ;
211
+ case Multiply -> "*" ;
212
+ case Divide -> "/" ;
213
+ case IS_EQUAL -> "=" ;
214
+ };
215
+ }
216
+
217
+ public static Operation parse (final String operator ) {
218
+ return switch (operator .trim ()) {
219
+ case "+" -> Add ;
220
+ case "-" -> Subtract ;
221
+ case "*" -> Multiply ;
222
+ case "/" -> Divide ;
223
+ default -> throw new IllegalArgumentException ("Invalid operator: " + operator );
224
+ };
225
+ }
226
+ }
227
+
228
+ public record Unknown () implements Job {
229
+ public long yell (Map <String , Monkey > monkeys , Map <String , Long > results ) {
230
+ throw new UnsupportedOperationException (); // Oof
231
+ }
232
+
233
+ public Simplification simplify (Map <String , Monkey > monkeys , Map <String , Long > results ) {
234
+ return new Variable ();
235
+ }
236
+ }
237
+
238
+ record Yell (long number ) implements Job {
239
+ public long yell (Map <String , Monkey > monkeys , Map <String , Long > results ) {
240
+ return number ;
241
+ }
242
+
243
+ public Simplification simplify (Map <String , Monkey > monkeys , Map <String , Long > results ) {
244
+ return new Value (number ());
245
+ }
246
+
247
+ public static Yell parse (final String string ) {
248
+ return new Yell (Integer .parseInt (string ));
249
+ }
250
+ }
251
+
252
+ public record Math (String monkeyX , Operation operation , String monkeyY ) implements Job {
253
+
254
+ public long yell (Map <String , Monkey > monkeys , Map <String , Long > results ) {
255
+ final var x = getVariable (monkeyX (), monkeys , results );
256
+ final var y = getVariable (monkeyY (), monkeys , results );
257
+ return operation ().operate (x , y );
258
+ }
259
+
260
+ public Simplification simplify (Map <String , Monkey > monkeys , Map <String , Long > results ) {
261
+ final var x = monkeys .get (monkeyX ()).simplify (monkeys , results );
262
+ final var y = monkeys .get (monkeyY ()).simplify (monkeys , results );
263
+ if (x instanceof final Value xValue && y instanceof final Value yValue ) {
264
+ return new Value (operation ().operate (xValue .value (), yValue .value ()));
265
+ }
266
+ return new Expression (x , operation (), y );
267
+ }
268
+
269
+ long getVariable (final String monkeyName , final Map <String , Monkey > monkeys , final Map <String , Long > results ) {
270
+ if (results .containsKey (monkeyName )) {
271
+ return results .get (monkeyName );
272
+ }
273
+ final var result = monkeys .get (monkeyName ).yell (monkeys , results );
274
+ results .put (monkeyName , result );
275
+ return result ;
276
+ }
277
+
278
+ public static Math parse (final String [] components ) {
279
+ final var monkeyX = components [0 ].trim ();
280
+ final var operation = Operation .parse (components [1 ].trim ());
281
+ final var monkeyY = components [2 ].trim ();
282
+ return new Math (monkeyX , operation , monkeyY );
283
+ }
284
+ }
285
+
286
+ protected static Map <String , Monkey > getInput () {
287
+ final Map <String , Monkey > result = new HashMap <>();
288
+ StreamSupport .stream (new LineSpliterator ("day-21.txt" ), false )
289
+ .map (Monkey ::parse )
290
+ .forEach (monkey -> result .put (monkey .name (), monkey ));
291
+ return Collections .unmodifiableMap (result );
292
+ }
293
+
294
+ @ Test
295
+ public final void part1 () {
296
+ final var monkeys = getInput ();
297
+ final var results = new HashMap <String , Long >();
298
+ final var result = monkeys .get ("root" ).yell (monkeys , results );
299
+
300
+ System .out .println ("Part 1: " + result );
301
+ }
302
+
303
+ @ Test
304
+ public final void part2 () {
305
+ final var monkeys = new HashMap <>(getInput ());
306
+ final var results = new HashMap <String , Long >();
307
+ final var oldRoot = monkeys .get ("root" );
308
+ final var oldJob = (Math ) oldRoot .job ();
309
+ monkeys .put ("root" , new Monkey ("root" , new Math (oldJob .monkeyX (), Operation .IS_EQUAL , oldJob .monkeyY ())));
310
+ monkeys .put ("humn" , new Monkey ("humn" , new Unknown ()));
311
+
312
+ var simplification = monkeys .get ("root" ).simplify (monkeys , results );
313
+ while (true ) {
314
+ final var candidate = simplification .simplify ();
315
+ if (candidate .equals (simplification )) {
316
+ break ;
317
+ }
318
+ simplification = candidate ;
319
+ }
320
+ System .out .println ("Part 2: " + simplification );
321
+ }
322
+
323
+ }
0 commit comments