Day 10: Pipe Maze
Megathread guidelines
- Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
- Code block support is not fully rolled out yet but likely will be in the middle of the event. Try to share solutions as both code blocks and using something such as https://topaz.github.io/paste/ , pastebin, or github (code blocks to future proof it for when 0.19 comes out and since code blocks currently function in some apps and some instances as well if they are running a 0.19 beta)
FAQ
- What is this?: Here is a post with a large amount of details: https://programming.dev/post/6637268
- Where do I participate?: https://adventofcode.com/
- Is there a leaderboard for the community?: We have a programming.dev leaderboard with the info on how to join in this post: https://programming.dev/post/6631465
🔒 Thread is locked until there’s at least 100 2 star entries on the global leaderboard
🔓 Unlocked after 40 mins
Haskell
This was a fun one, and quite tricky! I used winding numbers to determine whether a point is inside or outside the path, but it looks like Hades’ solution is a more efficient approach.
Solution
import Control.Monad import Data.Array.Unboxed (Array) import qualified Data.Array.Unboxed as Array import Data.List import qualified Data.Set as Set type Pos = (Int, Int) readInput :: String -> (Array Pos Char, Pos) readInput s = let rows = lines s h = length rows w = length $ head rows grid = Array.listArray ((1, 1), (h, w)) $ concat rows Just (start, _) = find ((== 'S') . snd) $ Array.assocs grid in (grid, start) inBounds = Array.inRange . Array.bounds walk :: Array Pos Char -> Pos -> [Pos] walk grid start@(sy, sx) = go start initDir where initDir = head $ do ((dy, dx), valid) <- [ ((-1, 0), "|7F"), ((0, -1), "-LF"), ((0, 1), "-J7"), ((1, 0), "|LJ") ] let p = (sy + dy, sx + dx) guard $ inBounds grid p && grid Array.! p `elem` valid return (dy, dx) go p@(y, x) (dy, dx) = let p' = (y + dy, x + dx) d' = case grid Array.! p' of c | c `elem` "|-" -> (dy, dx) | c `elem` "L7" -> (dx, dy) | c `elem` "JF" -> (-dx, -dy) in if p' == start then [p] else p : go p' d' inside :: Array Pos Char -> [Pos] -> [Pos] inside grid path = filter (\p -> not (onPath p) && wind p /= 0) $ Array.range $ Array.bounds grid where onPath = (`elem` Set.fromList path) (sy, _) = head path wind p@(y, x) = let test = if sy > y then (< y) else (> y) in sum $ (map step . tails) $ (map head . group) $ filter (\x -> abs x <= 1) $ map (\(_, x') -> x' - x) $ filter (test . fst) path step :: [Int] -> Int step xs = case xs of (-1 : 0 : 1 : _) -> 1 (1 : 0 : -1 : _) -> -1 _ -> 0 main = do (grid, start) <- readInput <$> readFile "input10" let path = walk grid start print $ length path `quot` 2 print $ length $ grid `inside` path