-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay23.hs
78 lines (70 loc) · 2.5 KB
/
Day23.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
67
68
69
70
71
72
73
74
75
76
77
78
{-# LANGUAGE LambdaCase #-}
module Day23 (solve) where
import Data.Function ( (&) )
import Data.List
import qualified Data.Map as Map
import qualified Data.Set as Set
type Crator = Set.Set (Int, Int)
type Dir = [(Int, Int)]
solve input lines = do
let crator = readCrator lines
let crators = iterate doRound (crator, dirs) & map fst
let crator' = crators !! 10
print $ freeSpace crator'
print $
zip crators (tail crators)
& takeWhile (uncurry (/=))
& length & (+ 1)
freeSpace crator = do
let locs = crator & Set.toList
let left = locs & map fst & minimum
let right = locs & map fst & maximum
let top = locs & map snd & minimum
let bottom = locs & map snd & maximum
(1 + right - left) * (1 + bottom - top) - length crator
doRound (crator, dirs) = do
let crator' =
nextLocs
& filter (uncurry (/=))
& foldl addPlan Map.empty
& Map.toList
& filter ((== 1) . length . snd)
& foldl execMove crator
(crator', tail dirs ++ [head dirs])
where
execMove crator (dest, [orig]) =
crator & Set.delete orig & Set.insert dest
addPlan plan (elf, elf') =
case Map.lookup elf' plan of
Nothing -> Map.insert elf' [elf] plan
(Just elves) -> Map.insert elf' (elf : elves) plan
nextLocs =
crator
& Set.toList
& map (\ elf -> (elf, nextLoc elf))
nextLoc elf =
if nhoodClear elf then elf else
dirs
& map (moveDir elf)
& filter (/= Nothing)
& \ case [] -> elf; (Just loc) : _ -> loc
moveDir elf@(x, y) dir@[_, (dx, dy), _] =
if allClear elf dir then Just (x + dx, y + dy) else Nothing
allClear elf@(x, y) deltas =
deltas
& map (\ (dx, dy) -> (x + dx, y + dy))
& filter (`Set.member` crator)
& (== [])
nhoodClear elf = allClear elf neighbourhood
north = [(-1, -1), (0, -1), (1, -1)]
south = [(-1, 1), (0, 1), (1, 1)]
west = [(-1, -1), (-1, 0), (-1, 1)]
east = [(1, -1), (1, 0), (1, 1)]
dirs = [north, south, west, east]
neighbourhood = concat dirs & nub
readCrator lines =
zip [0 ..] lines & concatMap
(\ (y, line) -> zip [0 ..] line & map (\ (x, c) -> ((x, y), c)))
& filter ((== '#') . snd)
& map fst
& Set.fromList