|
| 1 | +module Day15 where |
| 2 | + |
| 3 | +import qualified Data.Map as M |
| 4 | +import Data.List |
| 5 | +import qualified Data.Set as S |
| 6 | + |
| 7 | +data Dir = U|L|D|R |
| 8 | + deriving (Show,Eq) |
| 9 | + |
| 10 | +data Thing = Wall | Box |
| 11 | + deriving (Show,Eq) |
| 12 | + |
| 13 | +type Pos = (Int,Int) |
| 14 | +type Chart = M.Map Pos Thing |
| 15 | + |
| 16 | +data State = State {chart :: Chart, robot :: Pos, moves :: [Dir]} |
| 17 | + deriving Show |
| 18 | + |
| 19 | +parse :: String -> State |
| 20 | +parse s = State chart robot moves |
| 21 | + where ls = lines s |
| 22 | + (chartLines,"":moveLines) = break (=="") ls |
| 23 | + coords = [((x,y),c) | (y,line) <- zip [0..] chartLines |
| 24 | + , (x,c) <- zip [0..] line] |
| 25 | + robot = head [pos | (pos,'@') <- coords] |
| 26 | + chart = M.fromList [(pos,case c of '#' -> Wall; 'O' -> Box) | (pos,c) <- coords, c /= '@', c /= '.'] |
| 27 | + parseMove 'v' = D |
| 28 | + parseMove '^' = U |
| 29 | + parseMove '<' = L |
| 30 | + parseMove '>' = R |
| 31 | + moves = map parseMove $ concat moveLines |
| 32 | + |
| 33 | +example1 = parse <$> readFile "example1-15" |
| 34 | +example2 = parse <$> readFile "example2-15" |
| 35 | +slurp = parse <$> readFile "input-15" |
| 36 | + |
| 37 | +visualize :: State -> String |
| 38 | +visualize (State chart robot _) = unlines [ [r (x,y) | x <- [0..maxX]] | y <- [0..maxY] ] |
| 39 | + where ((maxX,maxY),_) = M.findMax chart |
| 40 | + r p |
| 41 | + | p == robot = '@' |
| 42 | + | otherwise = case M.lookup p chart |
| 43 | + of Just Box -> 'O' |
| 44 | + Just Wall -> '#' |
| 45 | + Nothing -> '.' |
| 46 | + |
| 47 | +(>>>) :: Pos -> Dir -> Pos |
| 48 | +(x,y) >>> U = (x,y-1) |
| 49 | +(x,y) >>> D = (x,y+1) |
| 50 | +(x,y) >>> L = (x-1,y) |
| 51 | +(x,y) >>> R = (x+1,y) |
| 52 | + |
| 53 | +swapIn :: Pos -> Thing -> Chart -> (Chart,Maybe Thing) |
| 54 | +swapIn p t c = (M.insert p t c, M.lookup p c) |
| 55 | + |
| 56 | +push :: Pos -> Dir -> Chart -> Maybe Chart |
| 57 | +push p d original = go remaining (p >>> d) (M.lookup p original) |
| 58 | + where remaining = M.delete p original |
| 59 | + go c _ Nothing = Just c |
| 60 | + go c _ (Just Wall) = Nothing |
| 61 | + go c p (Just Box) = let (c',thing) = swapIn p Box c |
| 62 | + in go c' (p >>> d) thing |
| 63 | + |
| 64 | +tick :: State -> State |
| 65 | +tick (State chart robot (dir:moves)) = |
| 66 | + case push robot' dir chart |
| 67 | + of Just chart' -> State chart' robot' moves |
| 68 | + Nothing -> State chart robot moves |
| 69 | + where robot' = robot >>> dir |
| 70 | + |
| 71 | +finish :: State -> State |
| 72 | +finish s@(State _ _ []) = s |
| 73 | +finish s = finish $ tick s |
| 74 | + |
| 75 | +gps :: State -> Int |
| 76 | +gps (State chart _ _) = sum [y*100+x | ((x,y),Box) <- M.toList chart] |
| 77 | + |
| 78 | +part1 = gps . finish |
| 79 | + |
| 80 | +main = do |
| 81 | + print . part1 =<< slurp |
0 commit comments