From dc84ce14889c19f211cd6cd2cc40400328aed934 Mon Sep 17 00:00:00 2001
From: Andreas Grois <andi@grois.info>
Date: Thu, 5 Sep 2024 23:40:30 +0200
Subject: Parser for Day10, maybe done.

---
 Day10.lean | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 136 insertions(+), 12 deletions(-)

(limited to 'Day10.lean')

diff --git a/Day10.lean b/Day10.lean
index d2ebec2..a9bc129 100644
--- a/Day10.lean
+++ b/Day10.lean
@@ -29,12 +29,42 @@ inductive Pipe
 | WN : Pipe
 deriving BEq
 
+instance : LawfulBEq Pipe where
+  eq_of_beq := by
+    intros a b
+    cases a <;> cases b
+    <;> simp
+    all_goals rfl
+  rfl := by
+    intro a
+    cases a
+    all_goals rfl
+
+
 inductive Tile
 | pipe : Pipe → Tile
 | ground : Tile
 | start : Tile
 deriving BEq
 
+instance : LawfulBEq Tile where
+  eq_of_beq := by
+    intros a b
+    cases a <;> cases b
+    <;> simp
+    all_goals try rfl
+    case pipe.pipe =>
+      intros h
+      exact eq_of_beq h
+  rfl := by
+    intro a
+    cases a
+    all_goals try rfl
+    case pipe =>
+      rename_i p
+      cases p
+      <;> rfl
+
 instance : Inhabited Tile where
   default := Tile.ground
 
@@ -335,11 +365,111 @@ private theorem Option.get_unfold {α : Type u} {v : α} : (some v).get (rfl) =
 private theorem Option.get_unfold' {α : Type u} {o : Option α} {v : α} (h₁ : o = some v) (h₂ : o.isSome) : o.get h₂ = v := by
   simp[h₁]
 
+private theorem Array.getElem!_eq_getElem {α : Type u} [Inhabited α] {a : Array α} {index : Nat} (h : index < a.size ): a[index] = a[index]! := by
+  unfold getElem getElem! instGetElem?OfGetElemOfDecidable Array.instGetElemNatLtSize decidableGetElem?
+  simp
+  split
+  <;> rename_i blah
+  <;> simp[h] at blah
+  assumption
+
+private theorem Array.get_push {α : Type u} (arr : Array α) (v : α) (index : Nat) (h₁ : index < arr.size) : arr[index] = (arr.push v)[index]'(by simp[Nat.lt_succ.mpr (Nat.le_of_lt h₁)]) := by
+  cases arr
+  unfold Array.push getElem Array.instGetElemNatLtSize Array.get
+  simp
+  rw[List.getElem_append]
+
 private theorem Area.ParseLine_leaves_start_if_some (previous : Area.Raw) (pos : Nat) (line : Substring) (h₁ : previous.height > 0) {res : (Nat × Area.Raw)} (h₂ : (Area.parseLine previous pos line h₁) = Except.ok res) (h₃ : previous.start.isSome) : Fin.val <$> res.2.start = Fin.val <$> previous.start := by
-  sorry
+  unfold Area.parseLine at h₂
+  split at h₂
+  case isTrue => simp at h₂; rw[←h₂]
+  case isFalse h₄ =>
+    split at h₂ ; exact h₂.rec
+    case isFalse h₅ =>
+      unfold bind Monad.toBind Except.instMonad Except.bind at h₂
+      simp at h₂
+      split at h₂; simp at h₂
+      case h_2 d1 tile _ =>
+        clear d1
+        split at h₂; exact h₂.rec
+        exact Area.ParseLine_leaves_start_if_some  { width := previous.width, height := previous.height, start := previous.start, fields := previous.fields.push tile } (pos + 1) (line.drop 1) h₁ h₂ h₃
+termination_by previous.width - pos
 
 private theorem Area.ParseLine_only_adds_to_fields (previous : Area.Raw) (pos : Nat) (line : Substring) (h₁ : previous.height > 0) {res : (Nat × Area.Raw)} (h₂ : (Area.parseLine previous pos line h₁) = Except.ok res) (index : Fin (previous.fields.size)) : previous.fields[index.val]! = res.2.fields[index.val]! := by
-  sorry
+  unfold Area.parseLine at h₂
+  split at h₂
+  case isTrue => simp at h₂; rw[←h₂]
+  case isFalse h₃ =>
+    split at h₂; exact h₂.rec
+    case isFalse h₄ =>
+      unfold bind Monad.toBind Except.instMonad Except.bind at h₂
+      simp at h₂
+      split at h₂; simp at h₂
+      case h_2 d1 tile _ =>
+        clear d1
+        split at h₂
+        case' isFalse =>
+          have h₅ := Area.ParseLine_only_adds_to_fields { width := previous.width, height := previous.height, start := previous.start, fields := previous.fields.push tile } (pos + 1) (line.drop 1) h₁ h₂ (Fin.castLE (by simp) index)
+        case' isTrue =>
+          split at h₂; exact h₂.rec
+          have h₅ := Area.ParseLine_only_adds_to_fields { width := previous.width, height := previous.height, start := some ⟨previous.width * (previous.height - 1) + pos, _⟩, fields := previous.fields.push tile } (pos + 1) (line.drop 1) h₁ h₂ (Fin.castLE (by simp) index)
+        all_goals
+          simp at h₅
+          rw[←h₅]
+          have h₆ : ↑index < (previous.fields.push tile).size := by simp; exact Nat.lt_succ.mpr (Nat.le_of_lt index.isLt)
+          simp[←Array.getElem!_eq_getElem]
+          simp[←Array.getElem!_eq_getElem h₆]
+          apply Array.get_push
+termination_by previous.width - pos
+
+private theorem Area.ParseLine_start_at_tile (previous : Area.Raw) (pos : Nat) (line : Substring) (h₁ : previous.height > 0) (h₂ : previous.fields.size = previous.width * (previous.height - 1) + pos) (h₃ : previous.start = none) {res : Area.Raw} {added : Nat} (h₄ : (Area.parseLine previous pos line h₁) = Except.ok (added, res)) : match res.start with | none => True | some s => res.fields[s]! = Tile.start := by
+  split; trivial
+  case h_2 d1 index hindex =>
+    clear d1
+    unfold Area.parseLine at h₄
+    simp at h₄
+    split at h₄
+    case isTrue => simp at h₄; rw[h₄.right] at h₃; rw[hindex] at h₃; contradiction
+    case isFalse d2 =>
+      clear d2
+      split at h₄
+      case isTrue => exact h₄.rec
+      case isFalse h₅ =>
+        unfold bind Monad.toBind Except.instMonad Except.bind at h₄
+        simp at h₄
+        split at h₄; contradiction
+        case h_2 d3 t ht =>
+          clear d3
+          split at h₄
+          case isTrue h₆ =>
+            split at h₄; exact h₄.rec
+            case isFalse h₇ =>
+              have h₈ : (previous.fields.push t)[previous.width * (previous.height - 1) + pos]! = t := by
+                have := Array.get_push_eq previous.fields t
+                simp[h₂, Array.getElem!_eq_getElem] at this
+                assumption
+              have : t = Tile.start := (beq_iff_eq t Tile.start).mp h₆
+              subst t
+              have : previous.width * (previous.height - 1) + pos < previous.width * previous.height := by
+                have := Nat.mul_pred previous.width previous.height
+                simp only [Nat.pred_eq_sub_one] at this
+                rw[this]
+                have : previous.width ≤ previous.width*previous.height := Nat.le_mul_of_pos_right _ h₁
+                rw[←Nat.sub_add_comm this]
+                omega
+              have h₉ := Area.ParseLine_only_adds_to_fields { width := previous.width, height := previous.height, start := some ⟨previous.width * (previous.height - 1) + pos, this⟩, fields := previous.fields.push Tile.start } (pos + 1) (line.drop 1) h₁ h₄ ⟨previous.width * (previous.height - 1) + pos, (by simp_all)⟩
+              simp at h₉
+              have h₁₀ := Area.ParseLine_leaves_start_if_some { width := previous.width, height := previous.height, start := some ⟨previous.width * (previous.height - 1) + pos, this⟩, fields := previous.fields.push Tile.start } (pos + 1) (line.drop 1) h₁ h₄ rfl
+              simp[hindex] at h₁₀
+              simp[←h₁₀] at h₉ h₈
+              simp[←h₉]
+              assumption
+          case isFalse =>
+            have : (previous.fields.push t).size = previous.width * (previous.height - 1) + (pos + 1) := by simp_arith[h₂]
+            have h₆ := Area.ParseLine_start_at_tile { width := previous.width, height := previous.height, start := previous.start, fields := previous.fields.push t } (pos + 1) (line.drop 1) h₁ this h₃ h₄
+            simp[hindex] at h₆
+            assumption
+termination_by previous.width - pos
 
 private theorem Area.ParseLines_start_position (input : Area.Raw) (lines : List String) (h₁ : (Area.parseLines input lines).isOk) (h₀ : input.fields.size = input.width * input.height) (h₂ : match input.start with | .some i => input.fields[i]! = Tile.start | .none => True) :
   match (Except.get (Area.parseLines input lines) h₁).start with
@@ -400,7 +530,9 @@ private theorem Area.ParseLines_start_position (input : Area.Raw) (lines : List
                   rw[hlo₂.right]
                   exact h₂
               case none =>
-                sorry
+                have h₆ := Area.ParseLine_start_at_tile { width := input.width, height := input.height + 1, start := Option.map (Fin.castLE (Nat.mul_le_succ_right _ _)) input.start, fields := input.fields } 0 l.toSubstring (Nat.succ_pos _) h₀ (by simp[his]) h₃
+                simp[ho] at h₆
+                assumption
             rw[←h₅ this]
             rfl
 
@@ -426,7 +558,7 @@ private theorem Area.ParseRaw_start_position_aux :
       case isFalse => rw[←hr] at h₁; contradiction
       case isTrue =>
         rename_i hs _
-        have : 0 < (String.splitTrim (fun x => x == '\n') input).length := by simp at hs; unfold List.isEmpty at hs; split at hs; contradiction; rename_i hx; simp[hx]
+        have : 0 < (String.splitTrim (fun x => x == '\n') input).length := by let hs := List.isEmpty_eq_false.mpr hs; unfold List.isEmpty at hs; split at hs; contradiction; rename_i hx; simp[hx]
         have := Area.ParseLines_start_position { width := (String.splitTrim (fun x => x == '\n') input)[0].length, height := 0, start := none, fields := #[] } (String.splitTrim (fun x => x == '\n') input) (hr.substr h₁)
         simp at this
         subst r
@@ -438,14 +570,6 @@ private theorem Area.ParseRaw_start_position_aux :
           subst index₂
           exact this
 
-private theorem Array.getElem!_eq_getElem {α : Type u} [Inhabited α] {a : Array α} {index : Nat} (h : index < a.size ): a[index] = a[index]! := by
-  unfold getElem getElem! instGetElem?OfGetElemOfDecidable Array.instGetElemNatLtSize decidableGetElem?
-  simp
-  split
-  <;> rename_i blah
-  <;> simp[h] at blah
-  assumption
-
 private theorem Area.ParseRaw_start_position :
   ∀ (input : String), (h₁ : (Area.parseRaw input).isOk) → (h₂ : (Except.get (Area.parseRaw input) h₁).start.isSome) → (Except.get (Area.parseRaw input) h₁).fields[(Except.get (Area.parseRaw input) h₁).start.get h₂]'((Area.ParseRaw_array_size input h₁).substr ((Except.get (Area.parseRaw input) h₁).start.get h₂).isLt) = Tile.start := by
   intros input h₁ h₂
-- 
cgit v1.2.3

