2121-- solution. You can delete the type signatures completely and GHC
2222-- will recommend what should go in place of the underscores.
2323module AOC2025.Day09 (
24- -- day09a,
25- -- day09b
24+ day09a ,
25+ day09b
2626
2727)
2828where
2929
3030import AOC.Prelude
3131import qualified Data.Graph.Inductive as G
32+ import Data.List (partition )
3233import qualified Data.IntMap as IM
3334import qualified Data.IntMap.NonEmpty as NEIM
3435import qualified Data.IntSet as IS
@@ -55,19 +56,94 @@ day09a =
5556 MkSol
5657 { sParse =
5758 noFail $
58- lines
59+ mapMaybe (listV2 . map ( read @ Int ) . splitOn " , " ) . lines
5960 , sShow = show
6061 , sSolve =
6162 noFail $
62- id
63+ \ pts -> maximum
64+ [ (x + 1 ) * (y + 1 )
65+ | p: ps <- tails pts
66+ , q <- ps
67+ , let V2 x y = abs $ p - q
68+ ]
69+
6370 }
6471
72+ lineTo' x y = S. fromList (lineTo x y) -- <> S.fromList [x,y]
73+
6574day09b :: _ :~> _
6675day09b =
6776 MkSol
6877 { sParse = sParse day09a
78+ -- , sShow = ('\n':) . displayAsciiSet '.' '#'
6979 , sShow = show
70- , sSolve =
71- noFail $
72- id
80+ , sSolve = \ pts -> do
81+ let loopPts = zip pts (tail pts ++ [head pts])
82+ border = foldMap (uncurry lineTo') loopPts
83+ Just bb@ (V2 bmin bmax) = boundingBox' pts
84+ loopMe turn = fold <$> go loopPts
85+ where
86+ go ((p,q): xs) = (++) <$> newPoints <*> go xs
87+ where
88+ turnedMotion = motion <> turn
89+ motion = case signum (q - p) of
90+ V2 0 1 -> North
91+ V2 1 0 -> East
92+ V2 0 (- 1 ) -> South
93+ V2 (- 1 ) 0 -> West
94+ _ -> undefined
95+ newPoints = for (lineTo p q) \ r ->
96+ let toEdge = traceShowId . takeWhile (inBoundingBox bb) . drop 1 $ iterate (+ dirPoint turnedMotion) r
97+ (toLine, rest) = span (`S.notMember` border) toEdge
98+ in S. fromList toLine <$ guard (not (null rest))
99+ go [] = Just []
100+ interior <- loopMe East <> loopMe West
101+ let allPoints = interior <> border <> S. fromList pts
102+ maximumMay
103+ [ S. size rect
104+ | p: ps <- tails pts
105+ , q <- ps
106+ , let rect = traceShow (p,q) $ fillBoundingBox (V2 (min <$> p <*> q) (max <$> p <*> q))
107+ , S. null $ rect `S.difference` allPoints
108+ ]
109+ -- filled = fillBoundingBox bb
110+ -- let (verts, horiz) = partition (\(p, q) -> view _x p == view _x q) $ zipWith (,) pts (tail pts ++ [head pts])
111+ -- Just bb@(V2 bmin bmax) = boundingBox' pts
112+ -- filled = fillBoundingBox bb
113+ -- vertLines = foldMap (uncurry lineTo') verts
114+ -- horizLines = foldMap (uncurry lineTo') horiz
115+ -- inside = S.union (vertLines <> horizLines) $ flip S.filter filled \(V2 x y) ->
116+ -- odd (S.size (S.filter (\(V2 x' y') -> y' < y && x' == x) horizLines))
117+ -- && odd (S.size (S.filter (\(V2 x' y') -> x' < x && y' == y) vertLines))
118+ -- in inside
119+ -- let ptLoop = foldMap S.fromList $ zipWith lineTo pts (tail pts ++ [head pts])
120+ -- Just bb@(V2 bmin bmax) = boundingBox' pts
121+ -- filled = fillBoundingBox bb
122+ -- cand1 = floodFill ((`S.difference` ptLoop) . (`S.intersection` filled) . cardinalNeighbsSet) (S.fromList $ V2 <$> toList bmin <*> toList bmax)
123+ -- cand2 = (filled `S.difference` cand1) <> ptLoop
124+ -- -- lineTo :: Point -> Point -> [Point]
125+ -- in cand2
126+
127+ -- -- | Flood fill from a starting set
128+ -- floodFill ::
129+ -- Ord a =>
130+ -- -- | Expansion (be sure to limit allowed points)
131+ -- (a -> Set a) ->
132+ -- -- | Start points
133+ -- Set a ->
134+ -- -- | Flood filled
135+ -- Set a
136+ -- floodFill f = snd . floodFillCount f
137+
138+
139+ -- let (map snd->rs, map snd->gs) = partition (even . fst) $ zip [0..] pts
140+ -- rPairs = (zip rs (tail rs ++ [head rs])) <&> \(V2 x y, V2 x' y') ->
141+ -- fillBoundingBox (V2 (V2 (min x x') (min y y')) (V2 (max x x') (max y y')))
142+ -- gPairs = (zip gs (tail gs ++ [head gs])) <&> \(V2 x y, V2 x' y') ->
143+ -- fillBoundingBox (V2 (V2 (min x x') (min y y')) (V2 (max x x') (max y y')))
144+ -- in maximum
145+ -- [ S.size (xs <> ys)
146+ -- | xs <- rPairs
147+ -- , ys <- gPairs
148+ -- ]
73149 }
0 commit comments