1
1
module Main where
2
2
3
- import Data.Bits
4
- import Data.List
5
- import Data.List.Split
6
- import Data.List.Unique
7
3
import Data.Map (Map )
8
4
import Data.Map qualified as M
9
- import Data.Matrix (Matrix , (!) )
10
- import Data.Matrix qualified as Mat
11
5
import Data.Set (Set )
12
6
import Data.Set qualified as S
13
7
import Data.Tuple.Extra
14
8
import Debug.Trace
15
9
import System.Environment
16
- import Text.Regex.TDFA ((=~) )
17
-
18
- -- TODO: Cleanup imports after day done
19
10
20
11
type Input = [(Int , Int )]
21
12
@@ -35,62 +26,38 @@ move (y, x) RIGHT = (y, x + 1)
35
26
isOut :: (Int , Int ) -> (Int , Int ) -> Bool
36
27
isOut (width, height) (y, x) = x < 0 || y < 0 || x > width || y > height
37
28
38
- smallestPathFind :: Set (Int , Int ) -> Map (Int , Int ) Int -> (Int , Int ) -> (Int , Int ) -> Int -> (Int , Set (Int , Int ), Map (Int , Int ) Int )
39
- smallestPathFind memory seen pos target nbMoves
40
- -- \| trace ("Pos: " ++ show pos) False = (-1, S.empty, seen)
41
- | isOut target pos = (- 1 , S. empty, seen)
42
- | pos `M.member` seen && seen M. ! pos <= nbMoves = (- 1 , S. empty, seen) -- trace ("At " ++ show nbMoves ++ " but already seen at " ++ show (seen M.! pos))
43
- | pos `S.member` memory = (- 1 , S. empty, currSeen)
44
- | pos == target = (nbMoves, S. singleton target, currSeen)
45
- | length bestSol /= 0 = (bestMoves, S. insert pos bestPath, seenRight)
46
- | otherwise = (- 1 , S. empty, seenRight)
29
+ bfs :: Set (Int , Int ) -> (Int , Int ) -> Set (Int , Int ) -> Set (Int , Int ) -> Map (Int , Int ) (Set (Int , Int )) -> Set (Int , Int )
30
+ bfs memory target seen curr paths
31
+ | S. null curr = S. empty
32
+ | target `S.member` curr = paths M. ! target
33
+ | otherwise = bfs memory target (S. union seen curr) newCurr newPaths
47
34
where
48
- currSeen = M. insert pos nbMoves seen
49
- (movesUp, pathUp, seenUp) = smallestPathFind memory currSeen (move pos UP ) target (nbMoves + 1 )
50
- (movesLeft, pathLeft, seenLeft) = smallestPathFind memory seenUp (move pos LEFT ) target (nbMoves + 1 )
51
- (movesDown, pathDown, seenDown) = smallestPathFind memory seenLeft (move pos DOWN ) target (nbMoves + 1 )
52
- (movesRight, pathRight, seenRight) = smallestPathFind memory seenDown (move pos RIGHT ) target (nbMoves + 1 )
35
+ notSeen = curr S. \\ seen
36
+ notInWall = notSeen S. \\ memory
37
+ notOut = S. filter (not . isOut target) notInWall
53
38
54
- bestSol = sortOn fst . filter ((/= - 1 ) . fst ) $ [(movesUp, pathUp), (movesLeft, pathLeft), (movesDown, pathDown), (movesRight, pathRight)]
55
- (bestMoves, bestPath) = head bestSol
39
+ f2 p (curr', paths') p' = (S. insert p' curr', M. insert p' (S. insert p' (paths M. ! p)) paths')
40
+ f1 cp p = foldl (f2 p) cp $ map (move p) [UP , LEFT , RIGHT , DOWN ]
41
+ (newCurr, newPaths) = S. foldl f1 (S. empty, M. empty) notOut
56
42
57
- part1 :: Int -> Input -> Output
58
- part1 range input = fst3 $ smallestPathFind memory M. empty (0 , 0 ) (range, range) 0
59
- where
60
- memory = foldl (\ r e -> S. insert e r) S. empty $ take 1024 input
61
-
62
- anyPathFind :: Set (Int , Int ) -> Map (Int , Int ) Int -> (Int , Int ) -> (Int , Int ) -> Int -> (Int , Set (Int , Int ), Map (Int , Int ) Int )
63
- anyPathFind memory seen pos target nbMoves
64
- -- \| trace ("Pos: " ++ show pos) False = (-1, S.empty, seen)
65
- | isOut target pos = (- 1 , S. empty, seen)
66
- | pos `M.member` seen && seen M. ! pos <= nbMoves = (- 1 , S. empty, seen) -- trace ("At " ++ show nbMoves ++ " but already seen at " ++ show (seen M.! pos))
67
- | pos `S.member` memory = (- 1 , S. empty, currSeen)
68
- | pos == target = (nbMoves, S. singleton target, currSeen)
69
- | movesUp /= - 1 = (movesUp, S. insert pos pathUp, seenUp)
70
- | movesLeft /= - 1 = (movesLeft, S. insert pos pathLeft, seenLeft)
71
- | movesDown /= - 1 = (movesDown, S. insert pos pathDown, seenDown)
72
- | movesRight /= - 1 = (movesRight, S. insert pos pathRight, seenRight)
73
- | otherwise = (- 1 , S. empty, seenRight)
43
+ part1 :: Int -> Int -> Input -> Output
44
+ part1 range firstBatch input = S. size $ bfs memory (range, range) S. empty (S. singleton (0 , 0 )) (M. singleton (0 , 0 ) S. empty)
74
45
where
75
- currSeen = M. insert pos nbMoves seen
76
- (movesUp, pathUp, seenUp) = anyPathFind memory currSeen (move pos UP ) target (nbMoves + 1 )
77
- (movesLeft, pathLeft, seenLeft) = anyPathFind memory seenUp (move pos LEFT ) target (nbMoves + 1 )
78
- (movesDown, pathDown, seenDown) = anyPathFind memory seenLeft (move pos DOWN ) target (nbMoves + 1 )
79
- (movesRight, pathRight, seenRight) = anyPathFind memory seenDown (move pos RIGHT ) target (nbMoves + 1 )
80
-
81
- part2 :: Int -> Input -> (Int , Int )
82
- part2 range input = sub 1024 memory (drop 1024 input) (snd3 $ smallestPathFind memory M. empty (0 , 0 ) (range, range) 0 )
46
+ memory = S. fromList $ take firstBatch input
47
+
48
+ part2 :: Int -> Int -> Input -> (Int , Int )
49
+ part2 range firstBatch input = sub (firstBatch, length input + 1 )
83
50
where
84
- memory = foldl (\ r e -> S. insert e r) S. empty $ take 1024 input
85
- sub n mem [] lastPath = (- 1 , - 1 )
86
- sub n mem (e : l) lastPath
87
- -- \| trace (show lastPath) False = (0, 0)
88
- | e `S.notMember` lastPath = sub (n + 1 ) newMem l lastPath
89
- | currRes == - 1 = swap e
90
- | otherwise = sub (n + 1 ) newMem l currPath
51
+ findPath m = bfs m (range, range) S. empty (S. singleton (0 , 0 )) (M. singleton (0 , 0 ) S. empty)
52
+ sub :: (Int , Int ) -> (Int , Int )
53
+ sub (imin, imax)
54
+ | imin >= imax = swap $ input !! (imin - 1 )
55
+ | S. null currPath = sub (imin, midi)
56
+ | otherwise = sub (midi + 1 , imax)
91
57
where
92
- newMem = S. insert e mem
93
- (currRes, currPath, _) = smallestPathFind newMem M. empty (0 , 0 ) (range, range) 0
58
+ midi = imin + (imax - imin) `div` 2
59
+ mem = S. fromList $ take midi input
60
+ currPath = findPath mem
94
61
95
62
showMemory :: Int -> Set (Int , Int ) -> [String ]
96
63
showMemory range memory = [[if S. member (y, x) memory then ' #' else ' .' | x <- [0 .. range]] | y <- [0 .. range]]
@@ -101,12 +68,13 @@ main = do
101
68
content <- readFile (last args)
102
69
let input = parseInput content
103
70
let range = 70
104
-
71
+ let firstStep = 1024
105
72
-- print input
106
73
107
- -- let memory = foldl (\r e -> S.insert e r) S.empty $ take 1024 input
74
+ print $ part1 range firstStep input
75
+ print $ part2 range firstStep input
108
76
109
- -- putStrLn . unlines $ showMemory range memory
77
+ -- print $ part2dicho range firstStep input
110
78
111
- print $ part1 range input
112
- print $ part2 range input
79
+ -- let memory = foldl (\r e -> S.insert e r) S.empty $ take 1024 input
80
+ -- putStrLn . unlines $ showMemory range memory
0 commit comments