Guest User

Untitled

a guest
Dec 15th, 2024
67
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. module DayFifteen (parseGridV2, executeMove, partOne, sampleInput, parseGrid, parseActions, sampleActions, neighborsInDirection, Action(..), buildGraph, Item(..), Feature(..), allReachable, isBlocked) where
  2.  
  3. import qualified Data.Graph as G
  4. import Data.List (group, sort)
  5. import Data.Foldable (find)
  6. import Data.Ix
  7. import Data.Maybe (mapMaybe, catMaybes, fromMaybe)
  8. import qualified Data.Set as S
  9.  
  10. data Item = Wall | Box | DoubleBox | Robot  deriving (Ord, Eq, Show)
  11. type Location = (Int, Int)
  12. data Feature = Feature Location Item deriving (Ord, Eq, Show)
  13. type World = (Location, S.Set Feature)
  14. type WorldGraph = (G.Graph, G.Vertex -> Feature, Feature -> Maybe G.Vertex)
  15. data Action = PushUp | PushDown | PushLeft | PushRight deriving (Ord, Eq, Show)
  16.  
  17. parseActions = map parseAction
  18.   where parseAction '<' = PushLeft
  19.         parseAction '>' = PushRight
  20.         parseAction 'v' = PushDown
  21.         parseAction _ = PushUp
  22.  
  23. parseGrid :: [String] -> World
  24. parseGrid inputLines = (robotLocation, S.fromList features)
  25.         where parseLine :: (String, Int) -> [Feature]
  26.               parseLine (contents, lineNumber) = mapMaybe parseChar $ zip contents [0..]
  27.                 where parseChar ('O', col) = Just $ Feature (lineNumber, col) Box
  28.                       parseChar ('#', col) = Just $ Feature (lineNumber, col) Wall
  29.                       parseChar ('@', col) = Just $ Feature (lineNumber, col) Robot -- Keep???
  30.                       parseChar _ = Nothing    
  31.               features = concatMap parseLine $ zip inputLines [0..]
  32.               robotLocation = head $ [location | Feature location item <- features, item == Robot]
  33.  
  34. parseGridV2 :: [String] -> World
  35. parseGridV2 inputLines = (robotLocation, S.fromList features)
  36.         where parseLine :: (String, Int) -> [Feature]
  37.               parseLine (contents, lineNumber) = concatMap parseChar $ zip contents [0..]
  38.                 where parseChar ('O', col) = [Feature (lineNumber, col * 2) DoubleBox]
  39.                       parseChar ('#', col) = [Feature (lineNumber, col * 2) Wall, Feature (lineNumber, col * 2 + 1) Wall]
  40.                       parseChar ('@', col) = [Feature (lineNumber, col * 2) Robot]
  41.                       parseChar _ = []
  42.               features = concatMap parseLine $ zip inputLines [0..]
  43.               robotLocation = head $ [location | Feature location item <- features, item == Robot]
  44.  
  45.  
  46. moveTowards (r,c) PushRight = (r, c+1)
  47. moveTowards (r,c) PushLeft = (r, c-1)
  48. moveTowards (r,c) PushUp = (r - 1, c)
  49. moveTowards (r,c) PushDown = (r+1, c)
  50.  
  51. pushFeature f@(Feature _ Wall) _ = f
  52. pushFeature (Feature loc item) action = Feature (moveTowards loc action) item
  53.  
  54.  
  55. neighborsInDirection :: World -> Action -> Feature -> [Feature]
  56. neighborsInDirection (_, features) action from = S.toList $ S.filter isHit features
  57.         where isHit f = (footprint f) `intersects` (footprint (pushFeature from action))
  58.               intersects a b = not $ a `S.disjoint` b
  59.  
  60. footprint (Feature loc DoubleBox) = S.fromList [loc, moveTowards loc PushRight]
  61. footprint (Feature loc _) = S.singleton loc
  62.  
  63.        
  64.  
  65. buildGraph :: World -> Action -> WorldGraph
  66. buildGraph world action = (thegraph, lookup,  vertexFromKey)
  67.   where (thegraph, nodeFromVertex, vertexFromKey) = G.graphFromEdges edges
  68.         edges = [(feature, feature, neighborsInDirection world action feature) | feature <- featuresList]
  69.         featuresList = S.toList $ snd world
  70.         lookup = snd3 . nodeFromVertex
  71.         snd3 (a,b,c) = b
  72.  
  73. getLoc (Feature loc _) = loc
  74.  
  75. allReachable :: WorldGraph -> Feature -> Action -> [Feature]
  76. allReachable (g, getFeature, getVertex) from direction = fromMaybe [] result
  77.   where result = do
  78.                    vertex <- getVertex from
  79.                    let reachableVertices = G.reachable g vertex
  80.                    return $ map getFeature reachableVertices
  81.                    
  82. isBlocked :: WorldGraph -> Location -> Action -> Bool
  83. isBlocked g startLocation direction = any isWall impacted
  84.   where isWall (Feature _ Wall) = True
  85.         isWall _ = False
  86.         impacted = allReachable g (Feature startLocation Robot) direction
  87.  
  88.  
  89. executeMove :: World -> Action -> World
  90. executeMove world@(startLocation, features) action
  91.   | stuck = world
  92.   | otherwise = (getLoc (pushFeature robot action), S.map updateIndividual features)
  93.   where stuck = isBlocked g startLocation action
  94.         g = buildGraph world action
  95.         affected = S.fromList $ allReachable g (Feature startLocation Robot) action
  96.         robot = Feature startLocation Robot
  97.         updateIndividual feature
  98.           | feature `S.member` affected = pushFeature feature action
  99.           | otherwise = feature
  100.  
  101.  
  102.  
  103. fullSimulate :: World -> [Action] -> World
  104. fullSimulate world actions = foldl executeMove world actions
  105.  
  106. partOne :: World -> [Action] -> Int
  107. partOne world actions = scoreWorld $ fullSimulate world actions
  108.   where scoreWorld world@(_, features) = sum $ map scoreFeature $ S.toList features
  109.         scoreFeature (Feature (r,c) Box) = 100 * r + c
  110.         scoreFeature (Feature (r,c) DoubleBox) = 100 * r + c
  111.         scoreFeature _ = 0
  112.  
  113.  
  114. sampleActions = "<vv>^<v^>v>^vv^v>v<>v^v<v<^vv<<<^><<><>>v<vvv<>^v^>^<<<><<v<<<v^vv^v>^vvv<<^>^v^^><<>>><>^<<><^vv^^<>vvv<>><^^v>^>vv<>v<<<<v<^v>^<^^>>>^<v<v><>vv>v^v^<>><>>>><^^>vv>v<^^^>>v^v^<^^>v^^>v^<^v>v<>>v^v^<v>v^^<^^vv<<<v<^>>^^^^>>>v^<>vvv^><v<<<>^^^vv^<vvv>^>v<^^^^v<>^>vvvv><>>v^<<^^^^^^><^><>>><>^^<<^^v>>><^<v>^<vv>>v>>>^v><>^v><<<<v>>v<v<v>vvv>^<><<>^><^>><>^v<><^vvv<^^<><v<<<<<><^v<<<><<<^^<v<^^^><^>>^<v^><<<^>>^v<v^v<v^>^>>^v>vv>^<<^v<>><<><<v<<v><>v<^vv<<<>^^v^>^^>>><<^v>>v^v><^^>>^<>vv^<><^^>^^^<><vvvvv^v<v<<>^v<v>v<<^><<><<><<<^^<<<^<<>><<><^^^>^^<>^>v<>^^>vv<^v^v<vv>^<><v<^v>^^^>>>^^vvv^>vvv<>>>^<^>>>>>^<<^v>^vvv<>^<><<v>v^^>>><<^^<>>^v^<v^vv<>v^<<>^<^v^v><^<<<><<^<v><v<>vv>>v><v^<vv<>v^<<^"
  115.  
  116. sampleInput = ["##########",
  117.         "#..O..O.O#",
  118.         "#......O.#",
  119.         "#.OO..O.O#",
  120.         "#[email protected].#",
  121.         "#O#..O...#",
  122.         "#O..O..O.#",
  123.         "#.OO.O.OO#",
  124.         "#....O...#",
  125.         "##########"]
  126.  
Advertisement
Add Comment
Please, Sign In to add comment