From b428712b5804e9efd66fff554204db2c1d669e37 Mon Sep 17 00:00:00 2001
From: Andreas Grois <andi@grois.info>
Date: Sat, 2 Dec 2023 13:04:27 +0100
Subject: Day 2

---
 Day2.lean | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 97 insertions(+)
 create mode 100644 Day2.lean

(limited to 'Day2.lean')

diff --git a/Day2.lean b/Day2.lean
new file mode 100644
index 0000000..f0eff56
--- /dev/null
+++ b/Day2.lean
@@ -0,0 +1,97 @@
+import Common
+
+structure Draw (α : Type) where
+  red : α
+  green : α
+  blue : α
+  deriving Repr
+
+structure Game where
+  id : Nat
+  draw : List $ Draw Nat
+  deriving Repr
+
+def parse (input : String) : Option $ List Game :=
+  let lines := input.splitTrim (. == '\n')
+  let lines := lines.filter (not ∘ String.isEmpty)
+  let parse_single_line : (String → Option Game):= λ (l : String) ↦ do
+    let parse_id := λ (s : String) ↦ do
+      let rest ← if s.startsWith "Game " then some (s.drop 5) else none
+      rest.toNat?
+    let parse_draw := λ (s : String) ↦ do
+      let s := s.splitTrim (· == ',')
+      let findAndRemoveTail := λ (s : String) (t : String) ↦
+        if s.endsWith t then
+          some $ String.dropRight s (t.length)
+        else
+          none
+      let update_draw_parse := λ (pd : Option (Draw (Option String))) (c : String) ↦ do
+        let old ← pd
+        let red := findAndRemoveTail c " red"
+        let green := findAndRemoveTail c " green"
+        let blue := findAndRemoveTail c " blue"
+        match red, green, blue with
+        | some red, none, none => match old.red with
+          | none => some $ {old with red := some red}
+          | some _ => none
+        | none, some green, none => match old.green with
+          | none => some $ {old with green := some green}
+          | some _ => none
+        | none, none, some blue => match old.blue with
+          | none => some $ {old with blue := some blue}
+          | some _ => none
+        | _, _, _  => none
+      let parsed_draw ← s.foldl update_draw_parse (some $ Draw.mk none none none)
+      let parsed_draw := {
+        red := String.toNat? <$> parsed_draw.red,
+        green := String.toNat? <$> parsed_draw.green,
+        blue := String.toNat? <$> parsed_draw.blue : Draw _}
+      let extractOrFail := λ (s : Option $ Option Nat) ↦ match s with
+        | none => some 0
+        | some none => none
+        | some $ some x => some x
+      let red ← extractOrFail parsed_draw.red
+      let green ← extractOrFail parsed_draw.green
+      let blue ← extractOrFail parsed_draw.blue
+      pure { red := red, blue := blue, green := green : Draw _}
+    let parse_draws := λ s ↦ List.mapM parse_draw $ s.splitTrim (· == ';')
+    let (id, draw) ← match l.splitTrim (· == ':') with
+    | [l, r] => Option.zip (parse_id l) (parse_draws r)
+    | _ => none
+    pure { id := id, draw := draw}
+  lines.mapM parse_single_line
+
+def part1 (games : List Game) : Nat :=
+  let draw_possible := λ g ↦ g.red ≤ 12 && g.green ≤ 13 && g.blue ≤ 14
+  let possible := flip List.all draw_possible
+  let possible_games := games.filter (possible ∘ Game.draw)
+  possible_games.map Game.id |> List.foldl Nat.add 0
+
+def part2 (games : List Game) : Nat :=
+  let powerOfGame := λ (g : Game) ↦
+    let minReq := λ (c : Draw Nat → Nat) ↦
+      g.draw.map c |> List.maximum? |> flip Option.getD 0
+    minReq Draw.red * minReq Draw.green * minReq Draw.blue
+  let powers := games.map powerOfGame
+  powers.foldl Nat.add 0
+
+open DayPart
+instance : Parse ⟨2, by simp⟩ (ι := List Game) where
+  parse := parse
+
+instance : Part ⟨2,_⟩ Parts.One (ι := List Game) (ρ := Nat) where
+  run := some ∘ part1
+
+instance : Part ⟨2,_⟩ Parts.Two (ι := List Game) (ρ := Nat) where
+  run := some ∘ part2
+
+def testInput : String :=
+"Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green
+Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue
+Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red
+Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red
+Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green"
+
+ -- #eval part1 <$> parse testInput
+
+ -- #eval part2 <$> parse testInput
-- 
cgit v1.2.3

