summary refs log tree commit diff
path: root/10/Main.hs
diff options
context:
space:
mode:
authortzlil <tzlils@protonmail.com>2024-04-21 00:05:58 +0300
committertzlil <tzlils@protonmail.com>2024-04-21 00:05:58 +0300
commit4e1d02c73b1366617fc2d8d54b3a080f423c1538 (patch)
tree77842d1f9c84b14f9fd1c360a1e0358e03b1a55f /10/Main.hs
parent3dda0ec7cb4477259a1be52565fe27e0312b9d3b (diff)
finished day10
Diffstat (limited to '10/Main.hs')
-rw-r--r--10/Main.hs60
1 files changed, 60 insertions, 0 deletions
diff --git a/10/Main.hs b/10/Main.hs
new file mode 100644
index 0000000..0988b6d
--- /dev/null
+++ b/10/Main.hs
@@ -0,0 +1,60 @@
+module Main where
+import Algebra.Graph
+import Data.List
+import Data.Bifunctor (first, second, bimap)
+import Data.Foldable (fold)
+import Data.Monoid
+import Data.Tree (drawForest, Tree(Node))
+import Algebra.Graph.ToGraph (dfsForestFrom, preSet)
+import Data.Set (toList)
+import Debug.Trace
+
+-- convert map to graph
+maze tiles = fold [f tile (x,y) | (y, row) <- enumerate tiles, (x, tile) <- enumerate row] where
+  enumerate = zip [0..]
+  pipe f g = (,First Nothing) . (Overlay.((Connect . Vertex) <*> Vertex . f) <*> (Connect . Vertex <*> Vertex . g))
+  f '.' = (,) . Vertex <*> (const (First Nothing))
+  f '|' = pipe (second (+1)) (second $ subtract 1)
+  f '-' = pipe (first (+1)) (first $ subtract 1)
+  f 'L' = pipe (second $ subtract 1) (first (+1))
+  f 'J' = pipe (second $ subtract 1) (first $ subtract 1)
+  f '7' = pipe (second (+1)) (first $ subtract 1)
+  f 'F' = pipe (second (+1)) (first (+1))
+  f 'S' = (Empty,) . First . Just
+
+mainloop :: [String] -> [(Int, Int)]
+mainloop tiles = circuit where
+  (g, First (Just s)) = maze tiles
+  -- connect start to the appropriate tiles
+  g' = overlay (connect (vertex s) $ vertices . toList $ preSet s g) g
+  [g''] = dfsForestFrom g' [s]
+  -- find all paths from root (there should be only one)
+  summarize (Node l ts) = if ts /= [] then [l:summary | t <- ts, summary <- summarize t] else [[l]]
+  [circuit] =  summarize g''
+
+part1 tiles = (length (mainloop tiles) - 1) `div` 2 + 1 where
+
+part2 tiles = length enclosed where
+  (g, First (Just s)) = maze tiles
+  circuit = mainloop tiles
+
+  -- even-odd rule
+  -- inside tile = (foldl (/=) False $ [isLeftOf tile pipe | pipe <- circuit]) && (foldl (/=) False $ [isRightOf tile pipe | pipe <- circuit])
+  both = bimap <*> id
+  pairwise = zip <*> tail
+  
+  -- offset the points on the circuit so we dont get subset lines 
+  offgrid = both ((+0.5).fromIntegral) <$> (circuit ++ [s])
+
+  -- is this a counterclockwise turn?
+  ccw (ax,ay) (bx,by) (cx,cy) = (cy-ay) * (bx-ax) > (by-ay) * (cx-ax)
+  -- line-line intersection
+  llintersect (a,b) (c,d) = ccw a c d /= ccw b c d && ccw a b c /= ccw a b d
+  
+  -- a tile is inside the circuit if it intersects an odd amount of edges
+  inside tile@(x,_) = foldl (/=) False $ llintersect (both fromIntegral $ tile,(fromIntegral x,1/0)) <$> pairwise offgrid
+
+  -- all tiles that dont lie on the circuit that are inside it
+  enclosed = filter inside $ (vertexList g) \\ circuit
+
+main = readFile "input.txt" >>= (putStrLn . show . part2 . lines)