-
Notifications
You must be signed in to change notification settings - Fork 0
/
Day21Test.scala
137 lines (109 loc) · 4.74 KB
/
Day21Test.scala
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
127
128
129
130
131
132
133
134
135
136
137
package org.lemon.advent.year2022
import org.lemon.advent._
class Day21Test extends UnitTest {
case class ExpressionContext(expressions: Map[String, Expression])
sealed trait Expression:
def resolve(using context: ExpressionContext): Option[Long]
def simplify(using context: ExpressionContext): Expression
case class Literal(n: Long) extends Expression:
override def resolve(using context: ExpressionContext) = Some(n)
override def simplify(using context: ExpressionContext) = this
case class Reference(name: String) extends Expression:
override def resolve(using context: ExpressionContext) = context.expressions(name).resolve
override def simplify(using context: ExpressionContext) = context.expressions(name).simplify
sealed trait BinaryOperation extends Expression:
def lhs: Expression
def rhs: Expression
def op(x: Long, y: Long): Long
def copy(lhs: Expression, rhs: Expression): BinaryOperation
override def resolve(using context: ExpressionContext) = for x <- lhs.resolve; y <- rhs.resolve yield op(x, y)
override def simplify(using context: ExpressionContext) = resolve match
case Some(value) => Literal(value)
case None => copy(lhs = lhs.simplify, rhs = rhs.simplify)
case class Add(lhs: Expression, rhs: Expression) extends BinaryOperation:
override def op(x: Long, y: Long) = x + y
case class Subtract(lhs: Expression, rhs: Expression) extends BinaryOperation:
override def op(x: Long, y: Long) = x - y
case class Multiply(lhs: Expression, rhs: Expression) extends BinaryOperation:
override def op(x: Long, y: Long) = x * y
case class Divide(lhs: Expression, rhs: Expression) extends BinaryOperation:
override def op(x: Long, y: Long) = x / y
case object Unknown extends Expression:
override def resolve(using context: ExpressionContext) = None
override def simplify(using context: ExpressionContext) = this
def parseExpression(line: String): (String, Expression) = line match
case s"$v: $lhs $op $rhs" => (
v,
op match
case "+" => Add(Reference(lhs), Reference(rhs))
case "-" => Subtract(Reference(lhs), Reference(rhs))
case "*" => Multiply(Reference(lhs), Reference(rhs))
case "/" => Divide(Reference(lhs), Reference(rhs))
)
case s"$v: $lit" => (v, Literal(lit.toLong))
def part1(in: Seq[String]) =
val monkeys = in.map(parseExpression).toMap
given ExpressionContext = ExpressionContext(monkeys)
monkeys("root").resolve.get
def solve(simplifiedExpression: Expression, knownValue: Long): Long =
simplifiedExpression match
case Unknown => knownValue
case Add(Literal(n), rhs) => solve(rhs, knownValue - n)
case Add(lhs, Literal(n)) => solve(lhs, knownValue - n)
case Subtract(Literal(n), rhs) => solve(rhs, n - knownValue)
case Subtract(lhs, Literal(n)) => solve(lhs, n - -knownValue)
case Multiply(Literal(n), rhs) => solve(rhs, knownValue / n)
case Multiply(lhs, Literal(n)) => solve(lhs, knownValue / n)
case Divide(Literal(n), rhs) => solve(rhs, n / knownValue)
case Divide(lhs, Literal(n)) => solve(lhs, n * knownValue)
case _ => ???
def part2(in: Seq[String]) =
val monkeys = in.map(parseExpression).toMap
given ExpressionContext = ExpressionContext(monkeys + ("humn" -> Unknown))
val root = monkeys("root").asInstanceOf[BinaryOperation]
val lhs = root.lhs.resolve
val rhs = root.rhs.resolve
lhs.map(solve(root.rhs.simplify, _)).orElse(rhs.map(solve(root.lhs.simplify, _))).get
test("part 1 example") {
val in = """|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""".stripMargin
part1(in.linesIterator.toSeq) shouldBe 152
}
test("part 1") {
part1(readLines(file(2022)(21))) shouldBe 168502451381566L
}
test("part 2 example") {
val in = """|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""".stripMargin
part2(in.linesIterator.toSeq) shouldBe 301
}
test("part 2") {
part2(readLines(file(2022)(21))) shouldBe 3343167719435L
}
}