Browse Source

Day 9 - Part 2

main
Jens Kadenbach 2 years ago
parent
commit
08306ed57d
2 changed files with 53 additions and 34 deletions
  1. 27
    31
      src/Day9.hs
  2. 26
    3
      test/Day9Spec.hs

+ 27
- 31
src/Day9.hs View File

2
   ( parseMovements,
2
   ( parseMovements,
3
     Move (..),
3
     Move (..),
4
     Grid (..),
4
     Grid (..),
5
-    startGrid,
6
     up,
5
     up,
7
     down,
6
     down,
8
     left,
7
     left,
14
     normalizeMovement,
13
     normalizeMovement,
15
     Step (..),
14
     Step (..),
16
     follow,
15
     follow,
17
-    day9
16
+    buildTails,
17
+    day9,
18
   )
18
   )
19
 where
19
 where
20
 
20
 
21
 import Control.Arrow ((>>>))
21
 import Control.Arrow ((>>>))
22
-import Control.Monad.Trans.State.Strict (State, runState, modify)
22
+import Control.Monad.Trans.State.Strict (State, modify, runState)
23
 import qualified Data.Set as S
23
 import qualified Data.Set as S
24
 
24
 
25
 newtype Move = Move (Int, Int)
25
 newtype Move = Move (Int, Int)
50
 
50
 
51
 data Grid = Grid {h :: Pos, t :: Pos} deriving (Show, Eq)
51
 data Grid = Grid {h :: Pos, t :: Pos} deriving (Show, Eq)
52
 
52
 
53
-data MovementLog = MovementLog { visited :: S.Set Pos, recordedSteps :: [Step] }
53
+data MovementLog = MovementLog {visited :: S.Set Pos, recordedSteps :: [Step]}
54
   deriving (Show, Eq)
54
   deriving (Show, Eq)
55
 
55
 
56
-appendOne :: (Pos, Step) -> MovementLog -> MovementLog
57
-appendOne (p, s) (MovementLog v steps) =
58
-   MovementLog (S.insert p v) (s:steps)
56
+logOne :: (Pos, Step) -> MovementLog -> MovementLog
57
+logOne (p, s) (MovementLog v steps) =
58
+  MovementLog (S.insert p v) (s : steps)
59
+
60
+buildTails :: [Step] -> [([Pos], [Step])]
61
+buildTails steps = iterate (snd >>> recordPositions) ([], steps)
59
 
62
 
60
 recordPositions :: [Step] -> ([Pos], [Step])
63
 recordPositions :: [Step] -> ([Pos], [Step])
61
 recordPositions steps = (allPositions, allSteps)
64
 recordPositions steps = (allPositions, allSteps)
62
   where
65
   where
66
+    -- insert last tail position
63
     allPositions = S.toList $ S.insert lastTailPos (visited state)
67
     allPositions = S.toList $ S.insert lastTailPos (visited state)
64
     allSteps = reverse (recordedSteps state)
68
     allSteps = reverse (recordedSteps state)
65
-    ((_, Grid { t = lastTailPos}), state) = runState (recordPositions' steps startGrid) (MovementLog S.empty [])
69
+    
70
+    ((_, Grid {t = lastTailPos}), state) =
71
+      runState (recordPositions' steps Grid {h = (0,0), t = (0,0)}) (MovementLog S.empty [])
72
+
66
     recordPositions' :: [Step] -> Grid -> State MovementLog ([Step], Grid)
73
     recordPositions' :: [Step] -> Grid -> State MovementLog ([Step], Grid)
67
     recordPositions' [] grid = return ([], grid)
74
     recordPositions' [] grid = return ([], grid)
68
     recordPositions' (m : ms) Grid {h = headPos, t = tailPos} =
75
     recordPositions' (m : ms) Grid {h = headPos, t = tailPos} =
69
       let newHead = headPos `step` m
76
       let newHead = headPos `step` m
70
           followStep = follow newHead tailPos
77
           followStep = follow newHead tailPos
71
           newTail = tailPos `step` followStep
78
           newTail = tailPos `step` followStep
72
-       in modify (appendOne (newTail, followStep)) >> recordPositions' ms Grid {h = newHead, t = newTail}
73
-
74
-startGrid :: Grid
75
-startGrid = Grid {h = p, t = p}
76
-  where
77
-    p = (0, 0)
79
+       in modify (logOne (newTail, followStep))
80
+            >> recordPositions' ms Grid {h = newHead, t = newTail}
78
 
81
 
79
 parseMovements :: String -> [Move]
82
 parseMovements :: String -> [Move]
80
 parseMovements = lines >>> map toMove
83
 parseMovements = lines >>> map toMove
93
 step :: Pos -> Step -> Pos
96
 step :: Pos -> Step -> Pos
94
 step (x, y) (Step (dx, dy)) = (x + dx, y + dy)
97
 step (x, y) (Step (dx, dy)) = (x + dx, y + dy)
95
 
98
 
96
-distance :: Pos -> Pos -> Int
97
-distance (x, y) (x2, y2) = floor (dx ** 2 + dy ** 2)
98
-  where
99
-    dx :: Double
100
-    dx = fromIntegral $ x - x2
101
-    dy :: Double
102
-    dy = fromIntegral $ y - y2
103
-
104
 follow :: Pos -> Pos -> Step
99
 follow :: Pos -> Pos -> Step
105
-follow p1@(x1, y1) p2@(x2, y2)
106
-  | distance p1 p2 > 2 = Step (signum dx, signum dy)
107
-  | abs dx == 2 = Step (signum dx, 0)
108
-  | abs dy == 2 = Step (0, signum dy)
100
+follow (x1, y1) (x2, y2)
101
+  | abs dx > 1 || abs dy > 1 = Step (signum dx, signum dy)
109
   | otherwise = Step (0, 0)
102
   | otherwise = Step (0, 0)
110
   where
103
   where
111
     dx = x1 - x2
104
     dx = x1 - x2
113
 
106
 
114
 day9 :: IO ()
107
 day9 :: IO ()
115
 day9 = do
108
 day9 = do
116
-   input <- readFile "ressources/day09-input"
117
-   putStrLn "Day9"
118
-   let movements = parseMovements input
119
-   let positions = concatMap normalizeMovement >>> recordPositions >>> fst >>> length $ movements
120
-   putStrLn ("Number of distinct positions " ++ show positions)
109
+  input <- readFile "ressources/day09-input"
110
+  putStrLn "Day9"
111
+  let headSteps = parseMovements >>> concatMap normalizeMovement $ input
112
+  let allTails = buildTails headSteps
113
+  let positions = (!! 1) >>> fst >>> length $ allTails
114
+  putStrLn ("Number of distinct positions " ++ show positions)
115
+  let tail9 = (!! 9) >>> fst >>> length $ allTails
116
+  putStrLn ("Number of distinct positions of tail 9" ++ show tail9)

+ 26
- 3
test/Day9Spec.hs View File

29
   (0,0),(1,0),(2,0),(3,0)
29
   (0,0),(1,0),(2,0),(3,0)
30
   ]
30
   ]
31
 
31
 
32
+testInput2 :: String
33
+testInput2 = [str|R 5
34
+                 |U 8
35
+                 |L 8
36
+                 |D 3
37
+                 |R 17
38
+                 |D 10
39
+                 |L 25
40
+                 |U 20
41
+                 |]
42
+
32
 spec :: Spec
43
 spec :: Spec
33
 spec =
44
 spec =
34
   describe "Day9" $ do
45
   describe "Day9" $ do
51
         step (0, 1) (Step (0, -1)) `shouldBe` (0, 0)
62
         step (0, 1) (Step (0, -1)) `shouldBe` (0, 0)
52
       it "normalizes movement" $ do
63
       it "normalizes movement" $ do
53
         normalizeMovement still `shouldBe` []
64
         normalizeMovement still `shouldBe` []
54
-        normalizeMovement (left 1) `shouldBe` [Step (-1, 0)]
65
+        normalizeMovement (left 2) `shouldBe` [Step (-1, 0),Step (-1, 0)]
55
         normalizeMovement (right 1) `shouldBe` [Step (1, 0)]
66
         normalizeMovement (right 1) `shouldBe` [Step (1, 0)]
56
         normalizeMovement (up 1) `shouldBe` [Step (0, 1)]
67
         normalizeMovement (up 1) `shouldBe` [Step (0, 1)]
57
         normalizeMovement (down 2) `shouldBe` [Step (0, -1), Step (0, -1)]
68
         normalizeMovement (down 2) `shouldBe` [Step (0, -1), Step (0, -1)]
74
         positions `shouldBe` expectedPositions
85
         positions `shouldBe` expectedPositions
75
       it "solves the riddle" $ do
86
       it "solves the riddle" $ do
76
         input <- readFile "ressources/day09-input"
87
         input <- readFile "ressources/day09-input"
77
-        let movements = parseMovements input
78
-        let positions = concatMap normalizeMovement >>> recordPositions >>> fst >>> length $ movements
88
+        let headSteps = parseMovements >>> concatMap normalizeMovement $ input
89
+        let allTails = buildTails headSteps
90
+        let positions = (!! 1)  >>> fst >>> length $ allTails
79
         positions `shouldBe` 5878
91
         positions `shouldBe` 5878
92
+      it "solves example of part 2" $ do
93
+        let headSteps = parseMovements >>> concatMap normalizeMovement $ testInput2
94
+        let allTails = buildTails headSteps
95
+        let tail9Positions = fst $ allTails !! 9
96
+        length tail9Positions `shouldBe` 36
97
+      it "solves the riddle part 2" $ do
98
+        input <- readFile "ressources/day09-input"
99
+        let headSteps = parseMovements >>> concatMap normalizeMovement $ input
100
+        let allTails = buildTails headSteps
101
+        let positions = (!! 9)  >>> fst >>> length $ allTails
102
+        positions `shouldBe` 2405

Loading…
Cancel
Save