1
1
module Main where
2
2
3
+ import Control.Parallel.Strategies
3
4
import Data.List
4
5
import System.Environment
6
+ import Data.Matrix (Matrix , (!) )
7
+ import Data.Matrix qualified as Mat
5
8
import Data.Set (Set )
6
9
import Data.Set qualified as S
7
10
-- TODO: Cleanup imports after day done
8
11
9
12
10
13
data Heading = UP | RIGHT | DOWN | LEFT deriving (Show , Eq , Ord )
11
- type Input = ([ String ] , (Int , Int ), (Int , Int ), Heading )
14
+ type Input = (Matrix Char , (Int , Int ), (Int , Int ), Heading )
12
15
type Output = Int
13
16
14
17
parseInput :: String -> Input
15
- parseInput s = (lines s , (width, height), pos, UP )
18
+ parseInput s = (mat , (width, height), pos, UP )
16
19
where
17
- height = length $ lines s
18
- width = length . head $ lines s
19
- pos = head . filter (\ (x, y) -> (== ' ^' ) . (!! x) . (!! y) $ lines s) $ [(x, y) | x<- [0 .. width- 1 ], y<- [0 .. height- 1 ]]
20
+ mat = Mat. fromLists $ lines s
21
+ height = Mat. nrows mat
22
+ width = Mat. ncols mat
23
+
24
+ pos = head . filter ((== ' ^' ) . (mat ! )) $ [(y, x) | x<- [1 .. width], y<- [1 .. height]]
20
25
21
26
22
27
turn :: Heading -> Heading
@@ -26,53 +31,47 @@ turn DOWN = LEFT
26
31
turn LEFT = UP
27
32
28
33
move :: Heading -> (Int , Int ) -> (Int , Int )
29
- move UP (x, y ) = (x, y- 1 )
30
- move RIGHT (x, y ) = (x+ 1 , y )
31
- move DOWN (x, y ) = (x, y+ 1 )
32
- move LEFT (x, y ) = (x- 1 , y )
34
+ move UP (y, x ) = (y- 1 , x )
35
+ move RIGHT (y, x ) = (y, x+ 1 )
36
+ move DOWN (y, x ) = (y+ 1 , x )
37
+ move LEFT (y, x ) = (y, x- 1 )
33
38
34
39
isOut :: (Int , Int ) -> (Int , Int ) -> Bool
35
- isOut (width, height) (x, y) = x < 0 || y < 0 || x >= width || y >= height
36
-
37
- cellAt :: [String ] -> (Int , Int ) -> Char
38
- cellAt grid (x, y) = (grid !! y) !! x
40
+ isOut (width, height) (y, x) = x <= 0 || y <= 0 || x > width || y > height
39
41
40
42
visitedCells :: Input -> Set (Int , Int )
41
43
visitedCells (grid, dim, pos, dir) = moveOut pos dir S. empty
42
44
where
43
- moveOut xy dir positions
44
- | isOut dim (move dir xy ) = newPoss
45
- | cellAt grid (move dir xy ) == ' #' = moveOut (move newDir xy) newDir newPoss
46
- | otherwise = moveOut (move dir xy ) dir newPoss
45
+ moveOut yx dir positions
46
+ | isOut dim (move dir yx ) = newPoss
47
+ | grid ! (move dir yx ) == ' #' = moveOut yx newDir newPoss
48
+ | otherwise = moveOut (move dir yx ) dir newPoss
47
49
where
48
- newPoss = (S. insert xy positions)
50
+ newPoss = (S. insert yx positions)
49
51
newDir = turn dir
50
52
51
53
52
54
part1 :: Input -> Output
53
55
part1 = S. size . visitedCells
54
56
55
57
part2 :: Input -> Output
56
- part2 (grid, (dim@ (width, height)), pos, dir) = length . filter (isLoop pos dir S. empty) . map insertObstacle $ wallsPos
58
+ part2 (grid, (dim@ (width, height)), pos, dir) = length . filter id . parMap rseq (isLoop pos dir S. empty) . map insertObstacle $ wallsPos
57
59
where
58
60
visited = visitedCells (grid, dim, pos, dir)
59
- wallsPos = [(x, y) | x<- [0 .. width- 1 ], y<- [0 .. height- 1 ], ((x, y) `S.member` visited) && cellAt grid (x, y) /= ' #' ]
60
-
61
- insertObstacle :: (Int , Int ) -> [String ]
62
- insertObstacle (x, y) = linesBefore ++ [elemsBefore ++ " #" ++ elemsAfter] ++ linesAfter
63
- where
64
- (linesBefore, lineAt: linesAfter) = splitAt y grid
65
- (elemsBefore, elemAt: elemsAfter) = splitAt x lineAt
66
-
67
- isLoop :: (Int , Int ) -> Heading -> Set ((Int , Int ), Heading ) -> [String ] -> Bool
68
- isLoop xy dir positions grid
69
- | (xy, dir) `S.member` positions = True
70
- | isOut dim xy = False
71
- | isOut dim (move dir xy) = False
72
- | cellAt grid (move dir xy) == ' #' = isLoop xy newDir newPos grid
73
- | otherwise = isLoop (move dir xy) dir newPos grid
61
+ wallsPos = [(y, x) | y<- [1 .. height], x<- [1 .. width], ((y, x) `S.member` visited) && grid ! (y, x) == ' .' ]
62
+
63
+ insertObstacle :: (Int , Int ) -> Matrix Char
64
+ insertObstacle yx = Mat. setElem ' #' yx grid
65
+
66
+ isLoop :: (Int , Int ) -> Heading -> Set ((Int , Int ), Heading ) -> Matrix Char -> Bool
67
+ isLoop yx dir positions grid
68
+ | (yx, dir) `S.member` positions = True
69
+ | isOut dim yx = False
70
+ | isOut dim (move dir yx) = False
71
+ | grid ! (move dir yx) == ' #' = isLoop yx newDir newPos grid
72
+ | otherwise = isLoop (move dir yx) dir newPos grid
74
73
where
75
- newPos = (S. insert (xy , dir) positions)
74
+ newPos = (S. insert (yx , dir) positions)
76
75
newDir = turn dir
77
76
78
77
0 commit comments