diff options
author | Laura Orvokki Kursula <lav@vampires.gay> | 2024-12-15 18:19:15 +0100 |
---|---|---|
committer | Laura Orvokki Kursula <lav@vampires.gay> | 2024-12-15 18:19:58 +0100 |
commit | 15db8402ed2cbe448864565405817ebe4ed83272 (patch) | |
tree | 0734d7f4cd4e471f02c40990e249b1f185ecd5fe | |
parent | 04ffb7098bb5e3434880f9438a2c12adbc479a24 (diff) | |
download | aoc2024-15db8402ed2cbe448864565405817ebe4ed83272.tar.gz aoc2024-15db8402ed2cbe448864565405817ebe4ed83272.zip |
15-1
-rw-r--r-- | 15-1.hs | 89 |
1 files changed, 89 insertions, 0 deletions
@@ -0,0 +1,89 @@ +import Data.Array + +data Tile = Empty | Box | Wall deriving Eq + +type Map = Array (Int,Int) Tile + +data Direction = North | South | East | West + +type State = ((Int,Int), Map) + +neighbour :: Direction -> (Int,Int) -> (Int,Int) +neighbour North (x,y) = (x,y-1) +neighbour South (x,y) = (x,y+1) +neighbour West (x,y) = (x-1,y) +neighbour East (x,y) = (x+1,y) + +doMove :: Map -> (Int,Int) -> (Int,Int) -> Map +doMove m p0 p1 = m // [ (p0,Empty), (p1,Box) ] + +moveBox :: Map -> Direction -> (Int,Int) -> Maybe Map +moveBox m dir p = let n = neighbour dir p + in case m ! n of + Empty -> Just $ doMove m p n + Wall -> Nothing + Box -> do m' <- moveBox m dir n ; return (doMove m' p n) + +moveRobot :: State -> Direction -> State +moveRobot (pos, m) dir = let n = neighbour dir pos + in case m ! n of + Empty -> (n, m) + Wall -> (pos, m) + Box -> case moveBox m dir n of + Nothing -> (pos, m) + Just m' -> (n, m') + +parseMap :: [String] -> Map +parseMap s = let w = length $ head s + h = length s + in array ((0,0), (w-1, h-1)) + [ ((x,y), f (s!!y!!x)) | x <- [0..w-1], y <- [0..h-1] ] + where + f :: Char -> Tile + f '.' = Empty + f '@' = Empty + f '#' = Wall + f 'O' = Box + f _ = undefined + +findRobot :: [String] -> (Int,Int) +findRobot s = let w = length $ head s + h = length s + in head [ (x,y) + | x <- [0..w-1] + , y <- [0..h-1] + , s!!y!!x == '@' + ] + +parseState :: [String] -> State +parseState s = let pos = findRobot s + m = parseMap s + in (pos,m) + +parseDirections :: String -> [Direction] +parseDirections = let f '^' = North + f 'v' = South + f '>' = East + f '<' = West + f _ = undefined + in map f + +parseInput :: String -> (State,[Direction]) +parseInput s = let (xs, ys) = break null $ lines s + in (parseState xs, parseDirections $ concat ys) + +run :: State -> [Direction] -> State +run = foldl moveRobot + +gps :: (Int,Int) -> Int +gps (x,y) = 100 * y + x + +score :: Map -> Int +score = sum . map (gps . fst) . filter ((== Box) . snd) . assocs + +main :: IO () +main = do + input <- getContents + let (start, directions) = parseInput input + let (_,end) = run start directions + print $ score end |