From 24d7fab85b2eb1b7996fd0ceccdd0377f1ce087b Mon Sep 17 00:00:00 2001
From: Andreas Grois <andi@grois.info>
Date: Fri, 1 Dec 2023 23:21:14 +0100
Subject: Day 1

---
 Day1.lean | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)
 create mode 100644 Day1.lean

(limited to 'Day1.lean')

diff --git a/Day1.lean b/Day1.lean
new file mode 100644
index 0000000..9f265b8
--- /dev/null
+++ b/Day1.lean
@@ -0,0 +1,73 @@
+import Common.Helpers
+import Common.Option
+import Common.DayPart
+
+namespace Day1
+
+def parse (input : String) : Option $ List String :=
+  some $ input.split Char.isWhitespace |> List.filter (not ∘ String.isEmpty)
+
+-- Both parts could still be improved by doing two searches, one from the left, one from the right
+
+def part1 (instructions : List String) : Option Nat :=
+  let firstLast := λ (o : Option Nat × Option Nat) (c : Char) ↦
+    let digit := match c with
+    | '0' => some 0
+    | '1' => some 1
+    | '2' => some 2
+    | '3' => some 3
+    | '4' => some 4
+    | '5' => some 5
+    | '6' => some 6
+    | '7' => some 7
+    | '8' => some 8
+    | '9' => some 9
+    | _ => none
+    if let some digit := digit then
+      match o.fst with
+      | none => (some digit, some digit)
+      | some _ => (o.fst, some digit)
+    else
+      o
+  let scanLine := λ (l : String) ↦ l.foldl firstLast (none, none)
+  let numbers := instructions.mapM ((uncurry Option.zip) ∘ scanLine)
+  let numbers := numbers.map λ l ↦ l.map λ (a, b) ↦ 10*a + b
+  numbers.map (List.foldl (.+.) 0)
+
+def part2 (instructions : List String) : Option Nat :=
+  -- once I know how to prove stuff propery, I'm going to improve this. Maybe.
+  let instructions := instructions.map String.toList
+  let updateState := λ (o : Option Nat × Option Nat) (n : Nat) ↦ match o.fst with
+    | none => (some n, some n)
+    | some _ => (o.fst, some n)
+  let extract_digit := λ (o : Option Nat × Option Nat) (l : List Char) ↦
+    match l with
+    | '0' :: _ | 'z' :: 'e' :: 'r' :: 'o' :: _ => (updateState o 0)
+    | '1' :: _ | 'o' :: 'n' :: 'e' :: _ => (updateState o 1)
+    | '2' :: _ | 't' :: 'w' :: 'o' :: _ => (updateState o 2)
+    | '3' :: _ | 't' :: 'h' :: 'r' :: 'e' :: 'e' :: _ => (updateState o 3)
+    | '4' :: _ | 'f' :: 'o' :: 'u' :: 'r' :: _ => (updateState o 4)
+    | '5' :: _ | 'f' :: 'i' :: 'v' :: 'e' :: _ => (updateState o 5)
+    | '6' :: _ | 's' :: 'i' :: 'x' :: _ => (updateState o 6)
+    | '7' :: _ | 's' :: 'e' :: 'v' :: 'e' :: 'n' :: _ => (updateState o 7)
+    | '8' :: _ | 'e' :: 'i' :: 'g' :: 'h' :: 't' :: _ => (updateState o 8)
+    | '9' :: _ | 'n' :: 'i' :: 'n' :: 'e' :: _ => (updateState o 9)
+    | _ => o
+  let rec firstLast := λ (o : Option Nat × Option Nat) (l : List Char) ↦
+    match l with
+    | [] => o
+    | _ :: cs => firstLast (extract_digit o l) cs
+  let scanLine := λ (l : List Char) ↦ firstLast (none, none) l
+  let numbers := instructions.mapM ((uncurry Option.zip) ∘ scanLine)
+  let numbers := numbers.map λ l ↦ l.map λ (a, b) ↦ 10*a + b
+  numbers.map (List.foldl (.+.) 0)
+
+open DayPart
+instance : Parse ⟨1, by simp⟩ (ι := List String) where
+  parse := parse
+
+instance : Part ⟨1, _⟩ Parts.One (ι := List String) (ρ := Nat) where
+  run := part1
+
+instance : Part ⟨1, _⟩ Parts.Two (ι := List String) (ρ := Nat) where
+  run := part2
-- 
cgit v1.2.3

