3 Commits

Autor SHA1 Mensagem Data
  Jens Kadenbach 08306ed57d Day 9 - Part 2 2 anos atrás
  Jens Kadenbach dc5a757eb6 Day 9 - Part 1 refactor with state 2 anos atrás
  Jens Kadenbach 9bd3d62eec Day 9 - Part 1 2 anos atrás
6 arquivos alterados com 2235 adições e 10 exclusões
  1. 5
    0
      aoc2022.cabal
  2. 1
    0
      package.yaml
  3. 2000
    0
      ressources/day09-input
  4. 116
    0
      src/Day9.hs
  5. 11
    10
      src/Lib.hs
  6. 102
    0
      test/Day9Spec.hs

+ 5
- 0
aoc2022.cabal Ver arquivo

@@ -48,6 +48,7 @@ library
48 48
       Day7.Interpreter
49 49
       Day7.Parser
50 50
       Day8
51
+      Day9
51 52
       Lib
52 53
       Shared
53 54
   other-modules:
@@ -67,6 +68,7 @@ library
67 68
     , parsec
68 69
     , split
69 70
     , text
71
+    , transformers
70 72
     , vector
71 73
   default-language: Haskell2010
72 74
 
@@ -90,6 +92,7 @@ executable aoc2022-exe
90 92
     , parsec
91 93
     , split
92 94
     , text
95
+    , transformers
93 96
     , vector
94 97
   default-language: Haskell2010
95 98
 
@@ -105,6 +108,7 @@ test-suite aoc2022-test
105 108
       Day6Spec
106 109
       Day7Spec
107 110
       Day8Spec
111
+      Day9Spec
108 112
       Paths_aoc2022
109 113
   hs-source-dirs:
110 114
       test
@@ -122,5 +126,6 @@ test-suite aoc2022-test
122 126
     , parsec
123 127
     , split
124 128
     , text
129
+    , transformers
125 130
     , vector
126 131
   default-language: Haskell2010

+ 1
- 0
package.yaml Ver arquivo

@@ -33,6 +33,7 @@ dependencies:
33 33
 - matrix
34 34
 - vector
35 35
 - megaparsec
36
+- transformers
36 37
 
37 38
 ghc-options:
38 39
 - -Wall

+ 2000
- 0
ressources/day09-input
Diferenças do arquivo suprimidas por serem muito extensas
Ver arquivo


+ 116
- 0
src/Day9.hs Ver arquivo

@@ -0,0 +1,116 @@
1
+module Day9
2
+  ( parseMovements,
3
+    Move (..),
4
+    Grid (..),
5
+    up,
6
+    down,
7
+    left,
8
+    right,
9
+    diag,
10
+    still,
11
+    step,
12
+    recordPositions,
13
+    normalizeMovement,
14
+    Step (..),
15
+    follow,
16
+    buildTails,
17
+    day9,
18
+  )
19
+where
20
+
21
+import Control.Arrow ((>>>))
22
+import Control.Monad.Trans.State.Strict (State, modify, runState)
23
+import qualified Data.Set as S
24
+
25
+newtype Move = Move (Int, Int)
26
+  deriving (Show, Eq)
27
+
28
+newtype Step = Step (Int, Int)
29
+  deriving (Show, Eq)
30
+
31
+up :: Int -> Move
32
+up y = Move (0, y)
33
+
34
+down :: Int -> Move
35
+down y = Move (0, y * (-1))
36
+
37
+left :: Int -> Move
38
+left x = Move (x * (-1), 0)
39
+
40
+right :: Int -> Move
41
+right x = Move (x, 0)
42
+
43
+diag :: Int -> Move
44
+diag x = Move (x, x)
45
+
46
+still :: Move
47
+still = Move (0, 0)
48
+
49
+type Pos = (Int, Int)
50
+
51
+data Grid = Grid {h :: Pos, t :: Pos} deriving (Show, Eq)
52
+
53
+data MovementLog = MovementLog {visited :: S.Set Pos, recordedSteps :: [Step]}
54
+  deriving (Show, Eq)
55
+
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)
62
+
63
+recordPositions :: [Step] -> ([Pos], [Step])
64
+recordPositions steps = (allPositions, allSteps)
65
+  where
66
+    -- insert last tail position
67
+    allPositions = S.toList $ S.insert lastTailPos (visited state)
68
+    allSteps = reverse (recordedSteps state)
69
+    
70
+    ((_, Grid {t = lastTailPos}), state) =
71
+      runState (recordPositions' steps Grid {h = (0,0), t = (0,0)}) (MovementLog S.empty [])
72
+
73
+    recordPositions' :: [Step] -> Grid -> State MovementLog ([Step], Grid)
74
+    recordPositions' [] grid = return ([], grid)
75
+    recordPositions' (m : ms) Grid {h = headPos, t = tailPos} =
76
+      let newHead = headPos `step` m
77
+          followStep = follow newHead tailPos
78
+          newTail = tailPos `step` followStep
79
+       in modify (logOne (newTail, followStep))
80
+            >> recordPositions' ms Grid {h = newHead, t = newTail}
81
+
82
+parseMovements :: String -> [Move]
83
+parseMovements = lines >>> map toMove
84
+  where
85
+    toMove ('U' : ' ' : xs) = up $ read xs
86
+    toMove ('D' : ' ' : xs) = down $ read xs
87
+    toMove ('L' : ' ' : xs) = left $ read xs
88
+    toMove ('R' : ' ' : xs) = right $ read xs
89
+    toMove _ = error "cannot parse movement"
90
+
91
+normalizeMovement :: Move -> [Step]
92
+normalizeMovement (Move (dx, 0)) = replicate (abs dx) (Step (signum dx, 0))
93
+normalizeMovement (Move (0, dy)) = replicate (abs dy) (Step (0, signum dy))
94
+normalizeMovement m = error $ "cannot normalize movement: " ++ show m
95
+
96
+step :: Pos -> Step -> Pos
97
+step (x, y) (Step (dx, dy)) = (x + dx, y + dy)
98
+
99
+follow :: Pos -> Pos -> Step
100
+follow (x1, y1) (x2, y2)
101
+  | abs dx > 1 || abs dy > 1 = Step (signum dx, signum dy)
102
+  | otherwise = Step (0, 0)
103
+  where
104
+    dx = x1 - x2
105
+    dy = y1 - y2
106
+
107
+day9 :: IO ()
108
+day9 = do
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)

+ 11
- 10
src/Lib.hs Ver arquivo

@@ -2,21 +2,22 @@ module Lib
2 2
     ( someFunc
3 3
     ) where
4 4
 
5
-import Day1
6
-import Day2
7
-import Day3
8
-import Day4
9
-import Day5
10
-import Day6
11
-import Day7
12
-import Day8
5
+import Day1 (day1)
6
+import Day2 (day2)
7
+import Day3 (day3)
8
+import Day4 (day4)
9
+import Day5 (day5)
10
+import Day6 (day6)
11
+import Day7 (day7)
12
+import Day8 (day8)
13
+import Day9 (day9)
13 14
 
14 15
 days :: [IO ()]
15
-days = [day1, day2, day3, day4, day5, day6, day7, day8]
16
+days = [day1, day2, day3, day4, day5, day6, day7, day8, day9]
16 17
 
17 18
 sep :: IO ()
18 19
 sep = putStrLn "---------"
19 20
 
20 21
 someFunc :: IO ()
21 22
 someFunc = mapM_ (>> sep) days
22
-  
23
+

+ 102
- 0
test/Day9Spec.hs Ver arquivo

@@ -0,0 +1,102 @@
1
+{-# LANGUAGE QuasiQuotes #-}
2
+
3
+module Day9Spec (spec) where
4
+
5
+import Control.Arrow ((>>>))
6
+import Day9
7
+import Test.Hspec
8
+import Text.Heredoc
9
+import Data.List (sort)
10
+
11
+testInput :: String
12
+testInput =
13
+  [str|R 4
14
+                |U 4
15
+                |L 3
16
+                |D 1
17
+                |R 4
18
+                |D 1
19
+                |L 5
20
+                |R 2
21
+                |]
22
+
23
+expectedPositions :: [(Int, Int)]
24
+expectedPositions = sort [
25
+              (2,4),(3,4),
26
+                    (3,3),(4,3),
27
+        (1,2),(2,2),(3,2),(4,2),
28
+                          (4,1),
29
+  (0,0),(1,0),(2,0),(3,0)
30
+  ]
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
+
43
+spec :: Spec
44
+spec =
45
+  describe "Day9" $ do
46
+    describe "Part1" $ do
47
+      it "parses the instructions" $ do
48
+        parseMovements testInput
49
+          `shouldBe` [ right 4,
50
+                       up 4,
51
+                       left 3,
52
+                       down 1,
53
+                       right 4,
54
+                       down 1,
55
+                       left 5,
56
+                       right 2
57
+                     ]
58
+      it "moves a step" $ do
59
+        step (0, 0) (Step (1, 1)) `shouldBe` (1, 1)
60
+        step (0, 0) (Step (1, 0)) `shouldBe` (1, 0)
61
+        step (1, 0) (Step (-1, 0)) `shouldBe` (0, 0)
62
+        step (0, 1) (Step (0, -1)) `shouldBe` (0, 0)
63
+      it "normalizes movement" $ do
64
+        normalizeMovement still `shouldBe` []
65
+        normalizeMovement (left 2) `shouldBe` [Step (-1, 0),Step (-1, 0)]
66
+        normalizeMovement (right 1) `shouldBe` [Step (1, 0)]
67
+        normalizeMovement (up 1) `shouldBe` [Step (0, 1)]
68
+        normalizeMovement (down 2) `shouldBe` [Step (0, -1), Step (0, -1)]
69
+      it "follows the head" $ do
70
+        follow (1, 0) (0, 0) `shouldBe` Step (0, 0)
71
+        follow (0, 1) (0, 0) `shouldBe` Step (0, 0)
72
+        follow (1, 1) (0, 0) `shouldBe` Step (0, 0)
73
+        follow (2, 1) (0, 0) `shouldBe` Step (1, 1)
74
+        follow (1, 2) (0, 0) `shouldBe` Step (1, 1)
75
+        follow (2, 2) (0, 0) `shouldBe` Step (1, 1)
76
+        follow (4, 2) (3, 0) `shouldBe` Step (1, 1)
77
+      it "moves around and records tail position" $ do
78
+        let positions = parseMovements
79
+                >>> concatMap normalizeMovement
80
+                >>> recordPositions
81
+                >>> fst
82
+                >>> sort
83
+                $ testInput
84
+        length positions `shouldBe` 13
85
+        positions `shouldBe` expectedPositions
86
+      it "solves the riddle" $ do
87
+        input <- readFile "ressources/day09-input"
88
+        let headSteps = parseMovements >>> concatMap normalizeMovement $ input
89
+        let allTails = buildTails headSteps
90
+        let positions = (!! 1)  >>> fst >>> length $ allTails
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

Carregando…
Cancelar
Salvar