Skip to content

Commit fbfc13d

Browse files
committed
wip
1 parent 335ee64 commit fbfc13d

File tree

4 files changed

+33
-34
lines changed

4 files changed

+33
-34
lines changed

Aoc2024/Day08/Parser.lean

+3-8
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,15 @@ import Aoc2024.Day08.Examples
22
import Aoc2024.Day08.Types
33
import Aoc2024.Utils
44
import Std
5-
open Std.Internal.Parsec.String
6-
open Std.Internal.Parsec
75

8-
instance : Bind List where bind := List.bind
9-
instance : Pure List where pure := List.pure
10-
11-
private def decorateWithCoordinates (s: String): List (Point × Char) := do
6+
private def decorateWithCoordinates (s: String): List PointAndChar := do
127
let (y, line) <- s.splitOn "\n" |> .enum
138
let (x, c) <- line.toList.enum
14-
pure (⟨x, y⟩, c)
9+
pure ⟨⟨x, y⟩, c
1510

1611
def parseInput (s : String): PuzzleInput :=
1712
let decoratedChars := decorateWithCoordinates s
18-
let (xs, ys) := decoratedChars.map (·.1.toPair) |>.unzip
13+
let (xs, ys) := decoratedChars.map (·.point.toPair) |>.unzip
1914
let width := xs.max?.map (· + 1 |>.toNat) |>.getD 0
2015
let height := ys.max?.map (· + 1 |>.toNat) |>.getD 0
2116
let bounds: Rectangle := { topLeft := Point.origin, width, height }

Aoc2024/Day08/Solve.lean

+8-20
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,20 @@ open Std (HashMap)
77

88
-- Part 1
99

10-
private def groupByChar (decoratedChars : List (Point × Char)) : List (Char × List Point) :=
11-
decoratedChars.groupBy (λ (_, c1) (_, c2) => c1 == c2) |>.map (λ l => (l.head!.2, l.map (·.1)))
10+
private def removeDots (decoratedChars : List PointAndChar) : List PointAndChar := decoratedChars.filter (·.char != '.')
1211

13-
#guard groupByChar [(⟨0, 0⟩, 'a'), (⟨1, 0⟩, 'a'), (⟨0, 1⟩, 'b'), (⟨1, 1⟩, 'b')] == [
14-
('a', [⟨0, 0⟩, ⟨1, 0⟩]),
15-
('b', [⟨0, 1⟩, ⟨1, 1⟩])
16-
]
17-
18-
private instance hashableChar: Hashable Char where hash c := c.toNat |> hash
19-
20-
private def removeDots (decoratedChars : List (Point × Char)) : List (Point × Char) :=
21-
decoratedChars.filter (λ (_, c) => c != '.')
12+
private def getAntennaeGroups (input : PuzzleInput) : List (List Point) :=
13+
input.decoratedChars |> removeDots |>.groupByAndTransformValues (·.char) (·.point) |>.values
2214

2315
private def findAntinodes (antennaGroup : List Point) : List Point := do
2416
let antenna1 <- antennaGroup
2517
let antenna2 <- antennaGroup
2618
if antenna1 != antenna2 then
2719
return antenna2.add (antenna1.vectorTo antenna2)
28-
else
29-
[]
30-
31-
private def getAntennaeGroups (input : PuzzleInput) : List (List Point) :=
32-
input.decoratedChars |> removeDots |>.toArray.groupByKey (·.2) |>.map (λ _ v => v.map (·.1) |>.toList) |>.values
20+
[]
3321

3422
private def solvePart1 (input : PuzzleInput) : Int :=
35-
getAntennaeGroups input |>.bind findAntinodes |>.filter (input.bounds.contains) |>.toSet.size
23+
getAntennaeGroups input |>.flatMap findAntinodes |>.filter (input.bounds.contains) |>.toSet.size
3624

3725
def parseAndSolvePart1 (s : String): Int := parseInput s |> solvePart1
3826

@@ -44,15 +32,15 @@ private def combinationPairs [BEq α] (xs : List α) : List (α × α) := do
4432
let [x1, x2] <- xs.combinations 2 | []
4533
return (x1, x2)
4634

47-
private def isInLineWith (pair : (Point × Point)) (point : Point) : Bool :=
35+
private def Point.isColinearWith (point : Point) (pair : (Point × Point)) : Bool :=
4836
let (p1, p2) := pair
4937
let v1 := p1.vectorTo p2
5038
let v2 := p1.vectorTo point
5139
v1.x * v2.y == v1.y * v2.x
5240

5341
private def solvePart2 (input : PuzzleInput) : Int :=
54-
let antennaePairs := getAntennaeGroups input |>.bind combinationPairs
55-
let isAntinode (point : Point) : Bool := antennaePairs.any (λ pair => isInLineWith pair point)
42+
let antennaePairs := getAntennaeGroups input |>.flatMap combinationPairs
43+
let isAntinode (point : Point) : Bool := antennaePairs.any point.isColinearWith -- exploiting special property of the input
5644
input.bounds.allPoints.countP isAntinode
5745

5846
def parseAndSolvePart2 (s : String): Int := parseInput s |> solvePart2

Aoc2024/Day08/Types.lean

+12-4
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,23 @@ def Rectangle.contains (r : Rectangle) (p : Point) : Bool :=
3232
r.topLeft.x ≤ p.x && p.x < r.topLeft.x + r.width &&
3333
r.topLeft.y ≤ p.y && p.y < r.topLeft.y + r.height
3434

35+
#guard Rectangle.contains { topLeft := Point.origin, width := 2, height := 2 } { x := 1, y := 1 }
36+
#guard !Rectangle.contains { topLeft := Point.origin, width := 2, height := 2 } { x := 2, y := 2 }
37+
3538
def Rectangle.allPoints (r : Rectangle) : List Point := do
3639
let x <- intRange r.topLeft.x (r.topLeft.x + r.width)
3740
let y <- intRange r.topLeft.y (r.topLeft.y + r.height)
3841
return { x := x, y := y }
3942

40-
#guard Rectangle.contains { topLeft := Point.origin, width := 2, height := 2 } { x := 1, y := 1 }
41-
#guard !Rectangle.contains { topLeft := Point.origin, width := 2, height := 2 } { x := 2, y := 2 }
43+
#guard Rectangle.allPoints { topLeft := Point.origin, width := 2, height := 2 } ==
44+
[{ x := 0, y := 0 }, { x := 0, y := 1 }, { x := 1, y := 0 }, { x := 1, y := 1 }]
45+
46+
structure PointAndChar where
47+
point: Point
48+
char: Char
49+
deriving Repr, Inhabited, BEq, Hashable
4250

4351
structure PuzzleInput where
4452
bounds : Rectangle
45-
decoratedChars : List (Point × Char)
46-
deriving Repr, Inhabited, BEq
53+
decoratedChars : List PointAndChar
54+
deriving Repr, Inhabited, BEq, Hashable

Aoc2024/Utils.lean

+10-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import Std
22
import Batteries
33
open Std.Internal.Parsec.String
44
open Std.Internal.Parsec
5-
open Std (HashSet)
5+
open Std (HashSet HashMap)
66

77
-- https://brandonrozek.com/blog/writing-unit-tests-lean-4/
88
def Except.deq [DecidableEq α] [DecidableEq β] : DecidableEq (Except α β) := by
@@ -166,7 +166,13 @@ namespace List
166166
#guard [1, 2, 3].combinations 4 == []
167167
#guard [1, 2, 3, 4].combinations 2 == [[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
168168

169-
-- xs.bind (λ x => (xs.filter (· != x)).combinations n.map (x :: ·))
169+
def groupByKey [BEq α] [Hashable α] (key : β → α) (xs : List β): HashMap α (List β) :=
170+
xs.toArray.groupByKey key |>.map (λ _ v => v.toList)
171+
172+
def groupByAndTransformValues [BEq α] [Hashable α] (key : β → α) (f : β → γ) (xs : List β): HashMap α (List γ) :=
173+
xs.groupByKey key |>.map (λ _ v => v.map f)
174+
175+
def flatMap {α : Type u} {β : Type v} (a : List α) (b : α → List β) : List β := join (map b a)
170176

171177
end List
172178

@@ -217,3 +223,5 @@ def intRange (m n : Int) : List Int :=
217223
#guard intRange 0 3 == [0, 1, 2]
218224
#guard intRange (-3) 2 == [-3, -2, -1, 0, 1]
219225
#guard intRange 1 1 == []
226+
227+
instance hashableChar: Hashable Char where hash c := c.toNat |> hash

0 commit comments

Comments
 (0)