Day 9 - Part 2

This commit is contained in:
Jens Kadenbach
2022-12-09 18:53:29 +01:00
parent dc5a757eb6
commit 08306ed57d
2 changed files with 53 additions and 34 deletions

View File

@@ -2,7 +2,6 @@ module Day9
( parseMovements, ( parseMovements,
Move (..), Move (..),
Grid (..), Grid (..),
startGrid,
up, up,
down, down,
left, left,
@@ -14,12 +13,13 @@ module Day9
normalizeMovement, normalizeMovement,
Step (..), Step (..),
follow, follow,
day9 buildTails,
day9,
) )
where where
import Control.Arrow ((>>>)) import Control.Arrow ((>>>))
import Control.Monad.Trans.State.Strict (State, runState, modify) import Control.Monad.Trans.State.Strict (State, modify, runState)
import qualified Data.Set as S import qualified Data.Set as S
newtype Move = Move (Int, Int) newtype Move = Move (Int, Int)
@@ -50,31 +50,34 @@ type Pos = (Int, Int)
data Grid = Grid {h :: Pos, t :: Pos} deriving (Show, Eq) data Grid = Grid {h :: Pos, t :: Pos} deriving (Show, Eq)
data MovementLog = MovementLog { visited :: S.Set Pos, recordedSteps :: [Step] } data MovementLog = MovementLog {visited :: S.Set Pos, recordedSteps :: [Step]}
deriving (Show, Eq) deriving (Show, Eq)
appendOne :: (Pos, Step) -> MovementLog -> MovementLog logOne :: (Pos, Step) -> MovementLog -> MovementLog
appendOne (p, s) (MovementLog v steps) = logOne (p, s) (MovementLog v steps) =
MovementLog (S.insert p v) (s:steps) MovementLog (S.insert p v) (s : steps)
buildTails :: [Step] -> [([Pos], [Step])]
buildTails steps = iterate (snd >>> recordPositions) ([], steps)
recordPositions :: [Step] -> ([Pos], [Step]) recordPositions :: [Step] -> ([Pos], [Step])
recordPositions steps = (allPositions, allSteps) recordPositions steps = (allPositions, allSteps)
where where
-- insert last tail position
allPositions = S.toList $ S.insert lastTailPos (visited state) allPositions = S.toList $ S.insert lastTailPos (visited state)
allSteps = reverse (recordedSteps state) allSteps = reverse (recordedSteps state)
((_, Grid { t = lastTailPos}), state) = runState (recordPositions' steps startGrid) (MovementLog S.empty [])
((_, Grid {t = lastTailPos}), state) =
runState (recordPositions' steps Grid {h = (0,0), t = (0,0)}) (MovementLog S.empty [])
recordPositions' :: [Step] -> Grid -> State MovementLog ([Step], Grid) recordPositions' :: [Step] -> Grid -> State MovementLog ([Step], Grid)
recordPositions' [] grid = return ([], grid) recordPositions' [] grid = return ([], grid)
recordPositions' (m : ms) Grid {h = headPos, t = tailPos} = recordPositions' (m : ms) Grid {h = headPos, t = tailPos} =
let newHead = headPos `step` m let newHead = headPos `step` m
followStep = follow newHead tailPos followStep = follow newHead tailPos
newTail = tailPos `step` followStep newTail = tailPos `step` followStep
in modify (appendOne (newTail, followStep)) >> recordPositions' ms Grid {h = newHead, t = newTail} in modify (logOne (newTail, followStep))
>> recordPositions' ms Grid {h = newHead, t = newTail}
startGrid :: Grid
startGrid = Grid {h = p, t = p}
where
p = (0, 0)
parseMovements :: String -> [Move] parseMovements :: String -> [Move]
parseMovements = lines >>> map toMove parseMovements = lines >>> map toMove
@@ -93,19 +96,9 @@ normalizeMovement m = error $ "cannot normalize movement: " ++ show m
step :: Pos -> Step -> Pos step :: Pos -> Step -> Pos
step (x, y) (Step (dx, dy)) = (x + dx, y + dy) step (x, y) (Step (dx, dy)) = (x + dx, y + dy)
distance :: Pos -> Pos -> Int
distance (x, y) (x2, y2) = floor (dx ** 2 + dy ** 2)
where
dx :: Double
dx = fromIntegral $ x - x2
dy :: Double
dy = fromIntegral $ y - y2
follow :: Pos -> Pos -> Step follow :: Pos -> Pos -> Step
follow p1@(x1, y1) p2@(x2, y2) follow (x1, y1) (x2, y2)
| distance p1 p2 > 2 = Step (signum dx, signum dy) | abs dx > 1 || abs dy > 1 = Step (signum dx, signum dy)
| abs dx == 2 = Step (signum dx, 0)
| abs dy == 2 = Step (0, signum dy)
| otherwise = Step (0, 0) | otherwise = Step (0, 0)
where where
dx = x1 - x2 dx = x1 - x2
@@ -115,6 +108,9 @@ day9 :: IO ()
day9 = do day9 = do
input <- readFile "ressources/day09-input" input <- readFile "ressources/day09-input"
putStrLn "Day9" putStrLn "Day9"
let movements = parseMovements input let headSteps = parseMovements >>> concatMap normalizeMovement $ input
let positions = concatMap normalizeMovement >>> recordPositions >>> fst >>> length $ movements let allTails = buildTails headSteps
let positions = (!! 1) >>> fst >>> length $ allTails
putStrLn ("Number of distinct positions " ++ show positions) putStrLn ("Number of distinct positions " ++ show positions)
let tail9 = (!! 9) >>> fst >>> length $ allTails
putStrLn ("Number of distinct positions of tail 9" ++ show tail9)

View File

@@ -29,6 +29,17 @@ expectedPositions = sort [
(0,0),(1,0),(2,0),(3,0) (0,0),(1,0),(2,0),(3,0)
] ]
testInput2 :: String
testInput2 = [str|R 5
|U 8
|L 8
|D 3
|R 17
|D 10
|L 25
|U 20
|]
spec :: Spec spec :: Spec
spec = spec =
describe "Day9" $ do describe "Day9" $ do
@@ -51,7 +62,7 @@ spec =
step (0, 1) (Step (0, -1)) `shouldBe` (0, 0) step (0, 1) (Step (0, -1)) `shouldBe` (0, 0)
it "normalizes movement" $ do it "normalizes movement" $ do
normalizeMovement still `shouldBe` [] normalizeMovement still `shouldBe` []
normalizeMovement (left 1) `shouldBe` [Step (-1, 0)] normalizeMovement (left 2) `shouldBe` [Step (-1, 0),Step (-1, 0)]
normalizeMovement (right 1) `shouldBe` [Step (1, 0)] normalizeMovement (right 1) `shouldBe` [Step (1, 0)]
normalizeMovement (up 1) `shouldBe` [Step (0, 1)] normalizeMovement (up 1) `shouldBe` [Step (0, 1)]
normalizeMovement (down 2) `shouldBe` [Step (0, -1), Step (0, -1)] normalizeMovement (down 2) `shouldBe` [Step (0, -1), Step (0, -1)]
@@ -74,6 +85,18 @@ spec =
positions `shouldBe` expectedPositions positions `shouldBe` expectedPositions
it "solves the riddle" $ do it "solves the riddle" $ do
input <- readFile "ressources/day09-input" input <- readFile "ressources/day09-input"
let movements = parseMovements input let headSteps = parseMovements >>> concatMap normalizeMovement $ input
let positions = concatMap normalizeMovement >>> recordPositions >>> fst >>> length $ movements let allTails = buildTails headSteps
let positions = (!! 1) >>> fst >>> length $ allTails
positions `shouldBe` 5878 positions `shouldBe` 5878
it "solves example of part 2" $ do
let headSteps = parseMovements >>> concatMap normalizeMovement $ testInput2
let allTails = buildTails headSteps
let tail9Positions = fst $ allTails !! 9
length tail9Positions `shouldBe` 36
it "solves the riddle part 2" $ do
input <- readFile "ressources/day09-input"
let headSteps = parseMovements >>> concatMap normalizeMovement $ input
let allTails = buildTails headSteps
let positions = (!! 9) >>> fst >>> length $ allTails
positions `shouldBe` 2405