summaryrefslogtreecommitdiff
path: root/day06/day06.hs
blob: 3f11fed7e2d13a2265bdb71d03b2bbe114cd3752 (plain)
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import Data.List
import Data.Maybe

data Cell = Clr | Obs deriving (Show, Eq)
type Grid = [[Cell]]
type Coo = (Int, Int)
data Dir = U | R | D | L deriving (Show, Eq)
type Guard = (Coo, Dir)

(!?) :: Grid -> Coo -> Maybe Cell
grid !? (row, col)
  | row < 0                     = Nothing
  | row >= length grid          = Nothing
  | col < 0                     = Nothing
  | col >= (length $ head grid) = Nothing
  | otherwise                   = Just (grid !! row !! col)

findGuard :: Int -> [[Char]] -> Guard
findGuard r (h:t)
  | c == Nothing = findGuard (r + 1) t
  | otherwise    = ((r, (fromJust c)), U)
  where c = elemIndex '^' h

consume :: [Char] -> (Grid, Guard)
consume file =
  let toCell = \ln -> case ln of
                        '#' -> Obs
                        otherwise -> Clr
      grid = map (map toCell) (lines file)
      guard = findGuard 0 (lines file) in
        (grid, guard)

step :: Grid -> Guard -> Maybe Guard
step grid (coo@(r,c), U)
  | cell == Nothing = Nothing
  | cell == Just Obs = Just (coo, R)
  | cell == Just Clr = Just (ncoo, U)
  where
    ncoo = (r - 1, c)
    cell = grid !? ncoo
step grid (coo@(r,c), R)
  | cell == Nothing = Nothing
  | cell == Just Obs = Just (coo, D)
  | cell == Just Clr = Just (ncoo, R)
  where
    ncoo = (r, c + 1)
    cell = grid !? ncoo
step grid (coo@(r,c), D)
  | cell == Nothing = Nothing
  | cell == Just Obs = Just (coo, L)
  | cell == Just Clr = Just (ncoo, D)
  where
    ncoo = (r + 1, c)
    cell = grid !? ncoo
step grid (coo@(r,c), L)
  | cell == Nothing = Nothing
  | cell == Just Obs = Just (coo, U)
  | cell == Just Clr = Just (ncoo, L)
  where
    ncoo = (r, c - 1)
    cell = grid !? ncoo

(?:) :: Eq a => a -> [a] -> [a]
el ?: arr
  | el `elem` arr = arr
  | otherwise = el:arr

route :: Grid -> [Coo] -> Guard -> [Coo]
route grid seen guard@(coo, dir)
  | nguard == Nothing = coo ?: seen
  | otherwise         = route grid (coo ?: seen) (fromJust nguard)
  where
    nguard = step grid guard

route2 :: Grid -> [Guard] -> Bool
route2 grid seen@(guard:_)
  | nguard == Nothing             = False
  | (fromJust nguard) `elem` seen = True
  | otherwise                     = route2 grid ((fromJust nguard):seen)
  where
    nguard = step grid guard

putObs :: Grid -> Coo -> Grid
putObs grid (r, c) =
  let (br,tr:ar) = splitAt r grid
      (bc,_:ac)  = splitAt c tr in
        br ++
        [bc ++ [Obs] ++ ac] ++
        ar

part1 :: Grid -> Guard -> Int
part1 grid guard =
  length $ route grid [] guard

part2 :: Grid -> Guard -> Int
part2 grid guard =
  length $
    filter (route2A . putObsA) $
    route grid [] guard
  where
    route2A = (flip route2) [guard]
    putObsA = putObs grid

main = do
  file <- readFile "day06.input"
  let (grid, guard) = consume file
  putStrLn ("Part 1: " ++ (show $ part1 grid guard))
  putStrLn ("Part 2: " ++ (show $ part2 grid guard))