From 266e00cabe466e30a5f89009ccf530868e97455d Mon Sep 17 00:00:00 2001 From: Andreas Grois Date: Mon, 2 Sep 2024 18:10:35 +0200 Subject: First draft of input-parsing function for Day 10. Fail to prove anything for it... --- Day10.lean | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 1 deletion(-) (limited to 'Day10.lean') diff --git a/Day10.lean b/Day10.lean index c3508a2..27c3c14 100644 --- a/Day10.lean +++ b/Day10.lean @@ -1,3 +1,113 @@ +import «Common» + namespace Day10 --- I'm going to go with a Dijkstra graph search here. +structure Coordinate (width : Nat) (height : Nat) where + x : Fin width + y : Fin height + +def Coordinate.toIndex {w h : Nat} (c : Coordinate w h) : Fin (w*h) := + Fin.mk (c.x.val * c.y.val) (Nat.mul_lt_mul_of_lt_of_lt c.x.isLt c.y.isLt) + +def Coordinate.fromIndex {w h : Nat} (index : Fin (w*h)) : Coordinate w h := + have : w > 0 := + have := index.isLt + match w with + | Nat.zero => absurd ((Nat.zero_mul h).subst this) (Nat.not_lt_zero index.val) + | Nat.succ ww => Nat.succ_pos ww + { + x := ⟨index.val % w, Nat.mod_lt index.val this⟩ + y := ⟨index.val / w, Nat.div_lt_of_lt_mul index.isLt⟩ + } + +inductive Pipe +| NS : Pipe +| WE : Pipe +| NE : Pipe +| ES : Pipe +| SW : Pipe +| WN : Pipe +deriving BEq + +inductive Tile +| pipe : Pipe → Tile +| ground : Tile +| start : Tile +deriving BEq + +-- The invariants are maybe overdoing it a bit, but (in the voice of king Leonidas) "This is Lean4!" +structure Area where + width : Nat + height : Nat + start : Coordinate width height + fields : Array Tile + size_invariant : fields.size = width * height + start_invariant : fields[start.toIndex] = Tile.start + start_invariant2 : ∀ (index : Fin (width*height)), (index ≠ start.toIndex) → fields[index] ≠ Tile.start + +inductive Area.ParseError +| NoInput +| UnexpectedCharacter +| NoStart +| MoreThanOneStart +| NotRectangular + +private structure Area.Raw where + width : Nat + height : Nat + start : Nat + fields : Array Tile + +private def Area.ParseRaw (input : String) : Except Area.ParseError Area.Raw := do + let lines := input.splitTrim (· == '\n') + -- Treat the first line special. We use it to establish width + match lines with + | [] => throw Area.ParseError.NoInput + | l :: ls => + let mut width := 0 + let mut arr : Array Tile := Array.empty + let mut start : Option Nat := none + for c in l.toSubstring do + let tile ← parse_character c |> Option.toExcept Area.ParseError.UnexpectedCharacter + arr := arr.push tile + if tile == Tile.start then + if start.isNone then + start := some width + else + throw Area.ParseError.MoreThanOneStart + width := width + 1 + let mut height := 1 + for line in ls do + let mut thisWidth := 0 + for c in line.toSubstring do + let tile ← parse_character c |> Option.toExcept Area.ParseError.UnexpectedCharacter + arr := arr.push tile + if tile == Tile.start then + if start.isNone then + start := some (thisWidth * height) + else + throw Area.ParseError.MoreThanOneStart + thisWidth := thisWidth +1 + height := height + 1 + if thisWidth != width then + throw Area.ParseError.NotRectangular + if let some s := start then + return { + width := width, + height := height, + start := s, + fields := arr + } + else + throw Area.ParseError.NoStart +where + parse_character : Char → Option Tile := λ c ↦ match c with + | '|' => some $ Tile.pipe Pipe.NS + | '-' => some $ Tile.pipe Pipe.WE + | 'L' => some $ Tile.pipe Pipe.NE + | 'J' => some $ Tile.pipe Pipe.WN + | '7' => some $ Tile.pipe Pipe.SW + | 'F' => some $ Tile.pipe Pipe.ES + | 'S' => some Tile.start + | '.' => some Tile.ground + | _ => none -- cgit v1.2.3