diff options
| author | Andreas Grois <andi@grois.info> | 2023-12-09 20:58:59 +0100 |
|---|---|---|
| committer | Andreas Grois <andi@grois.info> | 2023-12-09 20:58:59 +0100 |
| commit | 14b20b12a06abffb37e7ddd7527a0ace64121b4e (patch) | |
| tree | fe07818dc3aaf17212826e7b96fa4fa00d72894a /Day9.lean | |
| parent | 32b6bf7bbe6124a0a1c69f46dac996806a1409c9 (diff) | |
Day 9
Diffstat (limited to 'Day9.lean')
| -rw-r--r-- | Day9.lean | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/Day9.lean b/Day9.lean new file mode 100644 index 0000000..24cd19d --- /dev/null +++ b/Day9.lean @@ -0,0 +1,61 @@ +import «Common» + +namespace Day9 + +private def parseLine (line : String) : Except String $ List Int := + line.split Char.isWhitespace + |> List.map String.trim + |> List.filter String.notEmpty + |> List.mapM String.toInt? + |> Option.toExcept s!"Failed to parse numbers in line \"{line}\"" + +def parse (input : String) : Except String $ List $ List Int := + let lines := input.splitOn "\n" |> List.map String.trim |> List.filter String.notEmpty + lines.mapM parseLine + +------------------------------------------------------------------------------------------- + +private def differences : List Int → List Int +| [] => [] +| _ :: [] => [] +| a :: b :: as => (a - b) :: differences (b::as) + +private theorem differences_length_independent_arg (a b : Int) (bs : List Int) : (differences (a :: bs)).length = (differences (b :: bs)).length := by + induction bs <;> simp[differences] + +-- BEWARE: Extrapolate needs the input reversed. +private def extrapolate : List Int → Int +| [] => 0 +| a :: as => + if a == 0 && as.all (· == 0) then + 0 + else + have : List.length (Day9.differences (a :: as)) < Nat.succ (List.length as) := by + simp_arith[differences] + induction (as) <;> simp_arith[differences] + case cons b bs hb => rw[←differences_length_independent_arg] + assumption + a + extrapolate (differences (a :: as)) +termination_by extrapolate a => a.length + +def part1 : List (List Int) → Int := + List.foldl Int.add 0 ∘ List.map (extrapolate ∘ List.reverse) + +------------------------------------------------------------------------------------------- + +def part2 : List (List Int) → Int := + List.foldl Int.add 0 ∘ List.map extrapolate + +------------------------------------------------------------------------------------------- + +open DayPart +instance : Parse ⟨9, by simp⟩ (ι := List (List Int)) where + parse := parse + +instance : Part ⟨9,_⟩ Parts.One (ι := List (List Int)) (ρ := Int) where + run := some ∘ part1 + +instance : Part ⟨9,_⟩ Parts.Two (ι := List (List Int)) (ρ := Int) where + run := some ∘ part2 + +------------------------------------------------------------------------------------------- |
