Day 15: Warehouse Woes
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
- 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
Haskell
I’m late today, anyway here is my blazingly fast solution using haskell
Large codeblock
{-# LANGUAGE MultiWayIf #-} import Control.Arrow import Data.Bifunctor hiding (first, second) import Data.Array.Unboxed (UArray) import Data.Array.ST (STUArray) import Control.Monad.ST (ST, runST) import Control.Monad (join) import qualified Data.Char as Char import qualified Data.List as List import qualified Data.Set as Set import qualified Data.Array.Unboxed as UArray import qualified Data.Array.ST as MArray parse :: String -> (UArray (Int, Int) Char, String) parse s = (grid, orders) where l = lines s orderLines = drop 1 . dropWhile (/= "") $ l orders = foldl (++) "" $ orderLines gridLines = takeWhile (/= "") $ l gridHeight = length gridLines gridWidth = length . head $ gridLines grid = UArray.listArray ((1, 1), (gridHeight, gridWidth)) . foldl (++) "" $ gridLines moveRobot :: UArray (Int, Int) Char -> String -> ST s (UArray (Int, Int) Char) moveRobot g s = do let robotPosition = maybe (error "Robot not in grid") fst . List.find ((== '@') . snd) . UArray.assocs $ g mg <- MArray.thaw g moveRobot' mg robotPosition s type RobotPosition = (Int, Int) walkDirection :: (Int, Int) -> (Int, Int) -> [(Int, Int)] walkDirection p d = iterate (.+. d) p orderDirection :: Char -> (Int, Int) orderDirection '>' = ( 0, 1) orderDirection '<' = ( 0, -1) orderDirection '^' = (-1, 0) orderDirection 'v' = ( 1, 0) (y1, x1) .+. (y2, x2) = (y1 + y2, x1 + x2) (y1, x1) .*. (y2, x2) = (y1 * y2, x1 * x2) countBarrels :: STUArray s (Int, Int) Char -> RobotPosition -> (Int, Int) -> ST s Int countBarrels g p d = do currentTile <- MArray.readArray g p if currentTile == 'O' then do n <- countBarrels g (p .+. d) d return $! n + 1 else return 0 moveRobot' :: STUArray s (Int, Int) Char -> RobotPosition -> String -> ST s (UArray (Int, Int) Char) moveRobot' g _ [] = MArray.freeze g moveRobot' g p (o:os) = do let direction = orderDirection o let nextCoordinate = p .+. direction nextTile <- MArray.readArray g nextCoordinate case nextTile of '#' -> moveRobot' g p os '.' -> MArray.writeArray g p '.' *> MArray.writeArray g nextCoordinate '@' *> moveRobot' g nextCoordinate os 'O' -> do barrelCount <- countBarrels g nextCoordinate direction let postBarrelPosition = p .+. (direction .*. (1 + barrelCount, 1 + barrelCount)) postBarrelTile <- MArray.readArray g postBarrelPosition case postBarrelTile of '#' -> moveRobot' g p os '.' -> MArray.writeArray g p '.' *> MArray.writeArray g nextCoordinate '@' *> MArray.writeArray g postBarrelPosition 'O' *> moveRobot' g nextCoordinate os part1 (g, o) = UArray.assocs >>> filter (snd >>> (== 'O')) >>> map (uncurry (+) . ((*100) *** id) . (join bimap pred) . fst) >>> sum $ g' where g' = runST $ (moveRobot g o) translate :: Char -> String translate '#' = "##" translate '.' = ".." translate '@' = "@." translate 'O' = "[]" translate '\n' = "\n" translate c = [c] moveWideRobot :: UArray (Int, Int) Char -> String -> ST s (UArray (Int, Int) Char) moveWideRobot g s = do let robotPosition = maybe (error "Robot not in grid") fst . List.find ((== '@') . snd) . UArray.assocs $ g mg <- MArray.thaw g moveWideRobot' mg robotPosition s moveChestHorizontally g p d = do tile <- MArray.readArray g p case tile of '.' -> return True '#' -> return False _ -> do let p' = p .+. d canMove <- moveChestHorizontally g p' d if canMove then MArray.writeArray g p' tile else return () return canMove boxCounterpart ('[', (y, x)) = (']', (y, x+1)) boxCounterpart (']', (y, x)) = ('[', (y, x-1)) moveChestVertically :: STUArray s (Int, Int) Char -> [(Int, Int)] -> (Int, Int) -> ST s Bool moveChestVertically g [] d = return True moveChestVertically g ps d = do tiles <- flip zip ps <$> mapM (MArray.readArray g) ps let counterParts = List.map boxCounterpart . List.filter (fst >>> flip List.elem "[]") $ tiles let tiles' = List.nub $ tiles ++ counterParts if | any ((== '#') . fst) tiles' -> return False | otherwise -> do let boxTiles = List.filter (fst >>> flip List.elem "[]") $ tiles' let boxPositions = List.map snd $ boxTiles let positionsAhead = List.map (.+. d) $ boxPositions success <- moveChestVertically g positionsAhead d if success then do mapM_ (second (.+. d) >>> uncurry (flip (MArray.writeArray g))) boxTiles mapM_ (flip (MArray.writeArray g) '.') boxPositions else return () return $ success moveWideRobot' :: STUArray s (Int, Int) Char -> RobotPosition -> String -> ST s (UArray (Int, Int) Char) moveWideRobot' g p [] = MArray.freeze g moveWideRobot' g p (o:os) = do let direction = orderDirection o let nextCoordinate = p .+. direction nextTile <- MArray.readArray g nextCoordinate case nextTile of '#' -> moveWideRobot' g p os '.' -> MArray.writeArray g p '.' *> MArray.writeArray g nextCoordinate '@' *> moveWideRobot' g nextCoordinate os '[' -> do success <- if o == '>' then moveChestHorizontally g nextCoordinate direction else moveChestVertically g [nextCoordinate, second succ nextCoordinate] direction if success then do MArray.writeArray g p '.' MArray.writeArray g nextCoordinate '@' moveWideRobot' g nextCoordinate os else moveWideRobot' g p os ']' -> do success <- if o == '<' then moveChestHorizontally g nextCoordinate direction else moveChestVertically g [nextCoordinate, second pred nextCoordinate] direction if success then do MArray.writeArray g p '.' MArray.writeArray g nextCoordinate '@' moveWideRobot' g nextCoordinate os else moveWideRobot' g p os part2 (g, o) = UArray.assocs >>> List.filter (snd >>> (== '[')) >>> map (uncurry (+) . ((*100) *** id) . (join bimap pred) . fst) >>> sum $ g' where g' = runST $ (moveWideRobot g o) main = getContents >>= print . (part1 *** part2) . join bimap parse . second (List.concatMap translate) . join (,)