)
+ : Day21Expr
+ =
+ match result.TryGetValue key with
+ | true, v -> v
+ | false, _ ->
+
+ if key = human then
+ let answer = Day21Expr.Variable
+ result.[human] <- answer
+ answer
+ else
+
+ match d.[key] with
+ | Day21Input.Literal v ->
+ let answer = Day21Expr.Literal (float v)
+ result.[key] <- answer
+ answer
+ | Day21Input.Calculated _ -> failwith "no never"
+ | Day21Input.Operation (s1, s2, op) ->
+ let v1 = convert human s1 d result
+ let v2 = convert human s2 d result
+ // One wave of simplification
+ let answer =
+ match v1, v2 with
+ | Day21Expr.Literal l1, Day21Expr.Literal l2 -> Day21Expr.Literal (compute l1 l2 op)
+ | _, _ -> Day21Expr.Calc (v1, v2, op)
+
+ result.[key] <- answer
+ answer
+
+ let part2 (lines : StringSplitEnumerator) : int64 =
+ let original, root, human = parse lines
+
+ let lhs, rhs =
+ match original.[root] with
+ | Day21Input.Literal _
+ | Day21Input.Calculated _ -> failwith "expected operation"
+ | Day21Input.Operation (s1, s2, _) -> s1, s2
+
+ let converted = Dictionary original.Count
+ let mutable lhs = convert human lhs original converted
+ let mutable rhs = convert human rhs original converted
+
+ let mutable answer = nan
+
+ while Double.IsNaN answer do
+ match lhs, rhs with
+ | Day21Expr.Literal l, Day21Expr.Variable
+ | Day21Expr.Variable, Day21Expr.Literal l -> answer <- l
+ | Day21Expr.Literal l, Day21Expr.Calc (v1, v2, op)
+ | Day21Expr.Calc (v1, v2, op), Day21Expr.Literal l ->
+ match v1, v2 with
+ | v1, Day21Expr.Literal v2 ->
+ lhs <- v1
+
+ rhs <-
+ match op with
+ | Day21Operation.Add -> Day21Expr.Literal (l - v2)
+ | Day21Operation.Times -> Day21Expr.Literal (l / v2)
+ | Day21Operation.Divide -> Day21Expr.Literal (l * v2)
+ | Day21Operation.Minus -> Day21Expr.Literal (l + v2)
+ | _ -> failwith "bad op"
+ | Day21Expr.Literal v1, v2 ->
+ lhs <- v2
+
+ rhs <-
+ match op with
+ | Day21Operation.Add -> Day21Expr.Literal (l - v1)
+ | Day21Operation.Times -> Day21Expr.Literal (l / v1)
+ | Day21Operation.Divide -> Day21Expr.Literal (v1 / l)
+ | Day21Operation.Minus -> Day21Expr.Literal (v1 - l)
+ | _ -> failwith "bad op"
+ | _, _ -> failwith "problem is too hard: had variables on both sides"
+ | Day21Expr.Variable, Day21Expr.Variable
+ | Day21Expr.Variable, Day21Expr.Calc _
+ | Day21Expr.Calc _, Day21Expr.Calc _
+ | Day21Expr.Calc _, Day21Expr.Variable -> failwith "one side is always a literal"
+ | Day21Expr.Literal _, Day21Expr.Literal _ -> failwith "can't both be literals"
+
+ round answer
diff --git a/BenchmarkDotNet.Artifacts/results/AdventOfCode2022.App.Benchmark21To25-report-github.md b/BenchmarkDotNet.Artifacts/results/AdventOfCode2022.App.Benchmark21To25-report-github.md
new file mode 100644
index 0000000..b0d2c02
--- /dev/null
+++ b/BenchmarkDotNet.Artifacts/results/AdventOfCode2022.App.Benchmark21To25-report-github.md
@@ -0,0 +1,14 @@
+``` ini
+
+BenchmarkDotNet=v0.13.2, OS=macOS 13.0.1 (22A400) [Darwin 22.1.0]
+Apple M1 Max, 1 CPU, 10 logical and 10 physical cores
+.NET SDK=7.0.100
+ [Host] : .NET 7.0.0 (7.0.22.51805), Arm64 RyuJIT AdvSIMD DEBUG
+ DefaultJob : .NET 7.0.0 (7.0.22.51805), Arm64 RyuJIT AdvSIMD
+
+
+```
+| Method | Day | IsPartOne | Mean | Error | StdDev |
+|---------- |---- |---------- |---------:|---------:|---------:|
+| **Benchmark** | **21** | **False** | **678.3 μs** | **13.00 μs** | **15.48 μs** |
+| **Benchmark** | **21** | **True** | **612.3 μs** | **9.40 μs** | **8.79 μs** |
diff --git a/BenchmarkDotNet.Artifacts/results/AdventOfCode2022.App.Benchmark21To25-report.csv b/BenchmarkDotNet.Artifacts/results/AdventOfCode2022.App.Benchmark21To25-report.csv
new file mode 100644
index 0000000..ed9e189
--- /dev/null
+++ b/BenchmarkDotNet.Artifacts/results/AdventOfCode2022.App.Benchmark21To25-report.csv
@@ -0,0 +1,3 @@
+Method,Job,AnalyzeLaunchVariance,EvaluateOverhead,MaxAbsoluteError,MaxRelativeError,MinInvokeCount,MinIterationTime,OutlierMode,Affinity,EnvironmentVariables,Jit,Platform,PowerPlanMode,Runtime,AllowVeryLargeObjects,Concurrent,CpuGroups,Force,HeapAffinitizeMask,HeapCount,NoAffinitize,RetainVm,Server,Arguments,BuildConfiguration,Clock,EngineFactory,NuGetReferences,Toolchain,IsMutator,InvocationCount,IterationCount,IterationTime,LaunchCount,MaxIterationCount,MaxWarmupIterationCount,MemoryRandomization,MinIterationCount,MinWarmupIterationCount,RunStrategy,UnrollFactor,WarmupCount,Day,IsPartOne,Mean,Error,StdDev
+Benchmark,DefaultJob,False,Default,Default,Default,Default,Default,Default,0000000000,Empty,RyuJit,Arm64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 7.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,21,False,678.3 μs,13.00 μs,15.48 μs
+Benchmark,DefaultJob,False,Default,Default,Default,Default,Default,Default,0000000000,Empty,RyuJit,Arm64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 7.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,21,True,612.3 μs,9.40 μs,8.79 μs
diff --git a/BenchmarkDotNet.Artifacts/results/AdventOfCode2022.App.Benchmark21To25-report.html b/BenchmarkDotNet.Artifacts/results/AdventOfCode2022.App.Benchmark21To25-report.html
new file mode 100644
index 0000000..ef51f30
--- /dev/null
+++ b/BenchmarkDotNet.Artifacts/results/AdventOfCode2022.App.Benchmark21To25-report.html
@@ -0,0 +1,31 @@
+
+
+
+
+AdventOfCode2022.App.Benchmark21To25-20221221-100214
+
+
+
+
+
+BenchmarkDotNet=v0.13.2, OS=macOS 13.0.1 (22A400) [Darwin 22.1.0]
+Apple M1 Max, 1 CPU, 10 logical and 10 physical cores
+.NET SDK=7.0.100
+ [Host] : .NET 7.0.0 (7.0.22.51805), Arm64 RyuJIT AdvSIMD DEBUG
+ DefaultJob : .NET 7.0.0 (7.0.22.51805), Arm64 RyuJIT AdvSIMD
+
+
+
+
+Method | Day | IsPartOne | Mean | Error | StdDev |
+
+Benchmark | 21 | False | 678.3 μs | 13.00 μs | 15.48 μs |
+
Benchmark | 21 | True | 612.3 μs | 9.40 μs | 8.79 μs |
+
+
+
diff --git a/README.md b/README.md
index acf2d38..fb04c86 100644
--- a/README.md
+++ b/README.md
@@ -9,3 +9,5 @@ BenchmarkDotNet reports:
* [Day 1 through Day 5](./BenchmarkDotNet.Artifacts/results/AdventOfCode2022.App.Benchmark1To5-report-github.md).
* [Day 6 through Day 10](./BenchmarkDotNet.Artifacts/results/AdventOfCode2022.App.Benchmark6To10-report-github.md).
* [Day 11 through Day 15](./BenchmarkDotNet.Artifacts/results/AdventOfCode2022.App.Benchmark11To15-report-github.md).
+* [Day 16 through Day 20](./BenchmarkDotNet.Artifacts/results/AdventOfCode2022.App.Benchmark16To20-report-github.md).
+* [Day 21 through Day 25](./BenchmarkDotNet.Artifacts/results/AdventOfCode2022.App.Benchmark21To25-report-github.md).