|
1 | 1 | package AdventOfCode2022
|
2 | 2 |
|
3 | 3 | object Day21:
|
4 |
| - def parse(input: Seq[String], part2: Boolean): collection.mutable.Map[String, () => Long] = |
5 |
| - val monkeys = collection.mutable.Map[String, () => Long]() |
6 |
| - input.foreach { line => |
7 |
| - val Array(name, rest: _*) = line.split("[: ]+"): @unchecked |
8 |
| - monkeys(name) = rest match |
9 |
| - case Seq(number) => () => number.toLong |
10 |
| - case Seq(left, operation, right) => operation match |
11 |
| - case _ if name == "root" && part2 => () => (monkeys(left)() - monkeys(right)()).abs |
12 |
| - case "+" => () => monkeys(left)() + monkeys(right)() |
13 |
| - case "-" => () => monkeys(left)() - monkeys(right)() |
14 |
| - case "*" => () => monkeys(left)() * monkeys(right)() |
15 |
| - case "/" => () => monkeys(left)() / monkeys(right)() |
| 4 | + sealed trait Monkey |
| 5 | + case class Number(value: Long) extends Monkey |
| 6 | + case class Operation(left: String, operation: String, right: String) extends Monkey |
| 7 | + |
| 8 | + def parse(input: Seq[String]): Map[String, Monkey] = |
| 9 | + input.map { |
| 10 | + case s"$name: $left $operation $right" => name -> Operation(left, operation, right) |
| 11 | + case s"$name: $value" => name -> Number(value.toLong) |
16 | 12 | }
|
17 |
| - monkeys |
| 13 | + .toMap |
18 | 14 |
|
19 |
| - def part1(input: Seq[String]): Long = parse(input, false)("root")() |
| 15 | + def calculate(monkeys: Map[String, Monkey]): Map[String, Long] = |
| 16 | + val result = collection.mutable.Map[String, Long]() |
| 17 | + def compute(name: String) = result.getOrElseUpdate(name, helper(name)) |
| 18 | + def helper(name: String): Long = monkeys(name) match |
| 19 | + case Number(value) => value |
| 20 | + case Operation(left, operation, right) => operation match |
| 21 | + case "+" => compute(left) + compute(right) |
| 22 | + case "-" => compute(left) - compute(right) |
| 23 | + case "*" => compute(left) * compute(right) |
| 24 | + case "/" => compute(left) / compute(right) |
20 | 25 |
|
21 |
| - def part2(input: Seq[String]): Long = |
22 |
| - val monkeys = parse(input, true) |
| 26 | + compute("root") |
| 27 | + result.toMap |
| 28 | + end calculate |
23 | 29 |
|
24 |
| - def check(n: Long): Long = |
25 |
| - monkeys("humn") = () => n |
26 |
| - monkeys("root")() |
| 30 | + def part1(input: Seq[String]): Long = |
| 31 | + val monkeys = parse(input) |
| 32 | + val results = calculate(monkeys) |
| 33 | + results("root") |
| 34 | + |
| 35 | + def part2(input: Seq[String]): Long = |
| 36 | + val monkeys = parse(input) |
| 37 | + val results = calculate(monkeys) |
27 | 38 |
|
28 |
| - def helper(prev: Long, n: Long, step: Long): Long = |
29 |
| - val next = n + step |
30 |
| - val result = check(next) |
31 |
| - if result == 0 then next |
32 |
| - else if result < prev then helper(result, next, step) |
33 |
| - else helper(result, next, step / -2) |
| 39 | + def helper(name: String, value: Long): Option[Long] = monkeys(name) match |
| 40 | + case Number(_) => Option.when(name == "humn")(value) |
| 41 | + case Operation(left, _, right) if name == "root" => |
| 42 | + val first = helper(right, results(left)) |
| 43 | + val second = helper(left, results(right)) |
| 44 | + first.orElse(second) |
| 45 | + case Operation(left, operation, right) => |
| 46 | + val first = operation match |
| 47 | + case "+" => helper(right, value - results(left)) |
| 48 | + case "-" => helper(right, results(left) - value) |
| 49 | + case "*" => if results(left) != 0 then helper(right, value / results(left)) else None |
| 50 | + case "/" => if value != 0 then helper(right, results(left) / value) else None |
| 51 | + val second = operation match |
| 52 | + case "+" => helper(left, value - results(right)) |
| 53 | + case "-" => helper(left, value + results(right)) |
| 54 | + case "*" => if results(right) != 0 then helper(left, value / results(right)) else None |
| 55 | + case "/" => helper(left, value * results(right)) |
| 56 | + first.orElse(second) |
34 | 57 |
|
35 |
| - helper(check(0), 0, 1 << 60) |
| 58 | + helper("root", -1).get |
36 | 59 | end part2
|
37 | 60 |
|
38 | 61 | def main(args: Array[String]): Unit =
|
|
0 commit comments