Day 18: Ram Run

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

  • lwhjp
    link
    16 hours ago

    Haskell

    I did an easy optimization for part 2, but it’s not too slow without.

    Solution
    import Control.Monad
    import Data.Ix
    import Data.List
    import Data.Map qualified as Map
    import Data.Maybe
    import Data.Set (Set)
    import Data.Set qualified as Set
    
    readInput :: String -> [(Int, Int)]
    readInput = map readCoords . lines
      where
        readCoords l = let (a, _ : b) = break (== ',') l in (read a, read b)
    
    findRoute :: (Int, Int) -> Set (Int, Int) -> Maybe [(Int, Int)]
    findRoute goal blocked = go Set.empty (Map.singleton (0, 0) [])
      where
        go seen paths
          | Map.null paths = Nothing
          | otherwise =
              (paths Map.!? goal)
                `mplus` let seen' = Set.union seen (Map.keysSet paths)
                            paths' =
                              (`Map.withoutKeys` seen')
                                . foldl' (flip $ uncurry Map.insert) Map.empty
                                . concatMap (\(p, path) -> (,p : path) <$> step p)
                                $ Map.assocs paths
                         in go seen' paths'
        step (x, y) = do
          (dx, dy) <- [(0, -1), (0, 1), (-1, 0), (1, 0)]
          let p' = (x + dx, y + dy)
          guard $ inRange ((0, 0), goal) p'
          guard $ p' `Set.notMember` blocked
          return p'
    
    dropAndFindRoutes goal skip bytes =
      let drops = drop skip $ zip bytes $ drop 1 $ scanl' (flip Set.insert) Set.empty bytes
       in zip (map fst drops) $ scanl' go (findRoute goal (snd $ head drops)) $ tail drops
      where
        go route (p, blocked) = do
          r <- route
          if p `elem` r then findRoute goal blocked else route
    
    main = do
      input <- readInput <$> readFile "input18"
      let routes = dropAndFindRoutes (70, 70) 1024 input
      print $ length <$> (snd . head) routes
      print $ fst <$> find (isNothing . snd) routes