From 15db8402ed2cbe448864565405817ebe4ed83272 Mon Sep 17 00:00:00 2001 From: Laura Orvokki Kursula Date: Sun, 15 Dec 2024 18:19:15 +0100 Subject: 15-1 --- 15-1.hs | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 15-1.hs diff --git a/15-1.hs b/15-1.hs new file mode 100644 index 0000000..69f5b14 --- /dev/null +++ b/15-1.hs @@ -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 -- cgit v1.2.3