Day 10: Hoof It

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)
  • You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL

FAQ

  • LeixB@lemmy.world
    link
    fedilink
    arrow-up
    2
    ·
    14 days ago

    Haskell

    import Control.Arrow
    import Control.Monad.Reader
    import Data.Array.Unboxed
    import Data.List
    
    type Pos = (Int, Int)
    type Board = UArray Pos Char
    type Prob = Reader Board
    
    parse :: String -> Board
    parse s = listArray ((1, 1), (n, m)) $ concat l
      where
        l = lines s
        n = length l
        m = length $ head l
    
    origins :: Prob [Pos]
    origins =
        ask >>= \board ->
            return $ fmap fst . filter ((== '0') . snd) $ assocs board
    
    moves :: Pos -> Prob [Pos]
    moves pos =
        ask >>= \board ->
            let curr = board ! pos
             in return . filter ((== succ curr) . (board !)) . filter (inRange (bounds board)) $ fmap (.+. pos) deltas
      where
        deltas = [(1, 0), (0, 1), (-1, 0), (0, -1)]
        (ax, ay) .+. (bx, by) = (ax + bx, ay + by)
    
    solve :: [Pos] -> Prob [Pos]
    solve p = do
        board <- ask
        nxt <- concat <$> mapM moves p
    
        let (nines, rest) = partition ((== '9') . (board !)) nxt
    
        fmap (++ nines) $ if null rest then return [] else solve rest
    
    scoreTrail = fmap (length . nub) . solve . pure
    scoreTrail' = fmap length . solve . pure
    
    part1 = sum . runReader (origins >>= mapM scoreTrail)
    part2 = sum . runReader (origins >>= mapM scoreTrail')
    
    main = getContents >>= print . (part1 &&& part2) . parse