-
Notifications
You must be signed in to change notification settings - Fork 0
/
day22.hs
66 lines (57 loc) · 1.97 KB
/
day22.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import Control.Monad
import Data.Set (Set)
import qualified Data.Set as Set
data Pos = Pos { x :: Int, y :: Int } deriving (Eq, Ord)
data Node = Node { pos :: Pos
, size :: Int
, used :: Int
} deriving (Eq, Ord)
type State = (Pos, Pos)
data Grid = Grid { wall :: Pos
, width :: Int
, height :: Int
}
avail :: Node -> Int
avail node = size node - used node
viablePairs :: [Node] -> [(Node, Node)]
viablePairs nodes = do
a <- nodes
b <- nodes
guard $ used a > 0
guard $ pos a /= pos b
guard $ used a <= avail b
return (a, b)
neighbors :: Pos -> [Pos]
neighbors (Pos x y) = do
(x', y') <- [(x-1, y), (x, y-1), (x, y+1), (x+1, y)]
return $ Pos x' y'
next :: Grid -> State -> [State]
next grid (b, goal) = do
a <- neighbors b
guard $ x a >= 0 && x a <= width grid
guard $ y a >= 0 && y a <= height grid
guard $ y a /= y (wall grid) || x a < x (wall grid)
return (a, if goal == a then b else goal)
bfs :: Grid -> Set State -> Set State -> Int
bfs grid visited unvisited =
if any ((== Pos 0 0) . snd) unvisited
then 0
else let unvisited' = Set.filter (`Set.notMember` visited) $ Set.fromList $ concatMap (next grid) unvisited
visited' = Set.union visited unvisited
in 1 + bfs grid visited' unvisited'
parse :: [String] -> Node
parse [x, size, used, _, _] =
let [(x', y)] = reads $ drop (length "/dev/grid/node-x") x
y' = read $ drop (length "-y") y
[(size', _)] = reads size
[(used', _)] = reads used
in Node (Pos x' y') size' used'
part1 :: String -> Int
part1 = length . viablePairs . map (parse . words) . drop 2 . lines
part2 :: String -> Int
part2 input =
let nodes = map (parse . words) . drop 2 . lines $ input
empty = head [pos n | n <- nodes, used n == 0]
Pos width height = pos $ last nodes
wall = head [pos n | n <- nodes, size n > 500]
in bfs (Grid wall width height) Set.empty $ Set.singleton (empty, Pos width 0)