@@ -170,6 +170,44 @@ object Day21 {
170170 }
171171 }
172172
173+ /**
174+ * Solution, which finds the derivative w.r.t. humn to get the slope
175+ * and then solves linear equation to find humn.
176+ * Assumes expression is linear w.r.t. humn.
177+ */
178+ object DerivativePart2Solution extends Part2Solution {
179+
180+ override def findHumn (monkeys : Monkeys ): Long = {
181+ val humnMonkeys = makeHumnMonkeys(monkeys) + (humn -> Job .Number (0 )) // evaluate at 0
182+ val evalName = makeEvalName[BigDecimal ](humnMonkeys).andThen(_.get) // always get, because all variables set
183+
184+ def deriveName (name : String ): BigDecimal = {
185+ if (name == humn)
186+ 1
187+ else
188+ deriveJob(humnMonkeys(name))
189+ }
190+
191+ def deriveJob (job : Job ): BigDecimal = job match {
192+ case Job .Number (_) => 0
193+ case Job .Operation (lhs, op, rhs) =>
194+ op match {
195+ case Op .Add => deriveName(lhs) + deriveName(rhs)
196+ case Op .Sub => deriveName(lhs) - deriveName(rhs)
197+ case Op .Mul =>
198+ deriveName(lhs) * evalName(rhs) + evalName(lhs) * deriveName(rhs)
199+ case Op .Div =>
200+ (deriveName(lhs) * evalName(rhs) - evalName(lhs) * deriveName(rhs)) / (evalName(rhs) * evalName(rhs))
201+ }
202+ }
203+
204+ val y0 = evalName(root)
205+ val dy0 = deriveName(root) // derivative at 0
206+ val x0 = y0 / - dy0
207+ x0.setScale(0 , BigDecimal .RoundingMode .HALF_UP ).longValue
208+ }
209+ }
210+
173211
174212 def parseMonkey (s : String ): (String , Job ) = s match {
175213 case s " $name: $lhs $opStr $rhs" =>
0 commit comments