-
Notifications
You must be signed in to change notification settings - Fork 0
/
Day15.hs
69 lines (54 loc) · 2.07 KB
/
Day15.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
module Day15
( part1
, part2
) where
import Helpers.Parsers
import Data.Char (ord)
import Data.IntMap as M (IntMap, assocs, empty, insert, lookup)
import Data.List.Split (splitOn)
import Data.Maybe (Maybe (Just), isNothing)
import Data.Sequence as Sq (Seq ((:<|), (:|>)), filter, null,
singleton, spanl, tails, (><))
import Text.Regex.TDFA ((=~))
type Label = String
type Focal = Int
type Procedure = String
type Boxes = IntMap Box
type Box = Seq (Label, Focal)
hash :: String -> Int
hash = foldl (\a b -> mod ((a + ord b) * 17) 256) 0
step :: Boxes -> Procedure -> Boxes
step boxes procedure
| isNothing potBox && op == "=" = insert box (singleton (label, focal)) boxes
| isNothing potBox && op == "-" = boxes
| op == "=" = insert box (insertInBox label focal content) boxes
| op == "-" = insert box (removeFromBox label content) boxes
where
label = procedure =~ "[[:alpha:]]+"
op = procedure =~ "[=-]"
focal = read (procedure =~ "[[:digit:]]+")
box = hash label
potBox = M.lookup box boxes
(Just content) = potBox
insertInBox :: Label -> Focal -> Box -> Box
insertInBox label focal box
| Sq.null box = singleton (label, focal)
| Sq.null . Sq.filter (\(a, b) -> a == label) $ box = box :|> (label, focal)
| otherwise = (before :|> (label, focal)) >< after
where
(before, _ :<| after) = spanl (\(a, b) -> a /= label) box
removeFromBox :: Label -> Box -> Box
removeFromBox label box
| Sq.null box = box
| Sq.null . Sq.filter (\(a, b) -> a == label) $ box = box
| otherwise = before >< after
where
(before, _ :<| after) = spanl (\(a, b) -> a /= label) box
scoreBox :: Box -> Int
scoreBox = foldl (flip $ (+) . sum) 0 . tails . fmap snd
scoreBoxes :: Boxes -> Int
scoreBoxes = sum . map (\(a, b) -> (a + 1) * scoreBox b) . assocs
part1 :: Bool -> String -> String
part1 _ = show . sum . map hash . splitOn "," . init
part2 :: Bool -> String -> String
part2 _ = show . scoreBoxes . foldl step empty . splitOn "," . init