Day 9 - Part 2
This commit is contained in:
58
src/Day9.hs
58
src/Day9.hs
@@ -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
|
||||||
@@ -113,8 +106,11 @@ follow p1@(x1, y1) p2@(x2, y2)
|
|||||||
|
|
||||||
day9 :: IO ()
|
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
|
||||||
putStrLn ("Number of distinct positions " ++ show positions)
|
let positions = (!! 1) >>> fst >>> length $ allTails
|
||||||
|
putStrLn ("Number of distinct positions " ++ show positions)
|
||||||
|
let tail9 = (!! 9) >>> fst >>> length $ allTails
|
||||||
|
putStrLn ("Number of distinct positions of tail 9" ++ show tail9)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user