-
Notifications
You must be signed in to change notification settings - Fork 0
/
09.hs
65 lines (46 loc) · 1.52 KB
/
09.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import Data.List
import Data.Ord (clamp)
import Lib
import Prelude hiding (Left, Right)
data Direction = Up | Down | Left | Right deriving (Show)
type Position = (Int, Int)
type Rope = [Position]
type State = (Rope, [Position])
type Motion = (Direction, Int)
type Input = [Motion]
main :: IO ()
main = aoc 2022 9 setup solve1 solve2 ["1", "2"]
solve1 :: Input -> Int
solve1 = solve 2
solve2 :: Input -> Int
solve2 = solve 10
solve :: Int -> Input -> Int
solve n = length . nub . snd . foldl step (initialRope n, []) . directions
step :: State -> Direction -> State
step (rope, visited) m = (newRope, head newRope : visited)
where
newRope = stepRope rope m
stepRope :: Rope -> Direction -> Rope
stepRope r m = scanr follow (move m $ last r) $ init r
follow :: Position -> Position -> Position
follow (x, y) (x', y')
| abs (x - x') <= 1 && abs (y - y') <= 1 = (x, y)
| otherwise = (x + clamp (-1, 1) (x' - x), y + clamp (-1, 1) (y' - y))
directions :: [Motion] -> [Direction]
directions = concatMap $ uncurry $ flip replicate
setup :: String -> Input
setup = map parseMotion . lines
parseMotion :: String -> Motion
parseMotion (d : ' ' : n) = (parseDirection d, read n)
parseDirection :: Char -> Direction
parseDirection 'U' = Up
parseDirection 'D' = Down
parseDirection 'L' = Left
parseDirection 'R' = Right
move :: Direction -> Position -> Position
move Up (x, y) = (x, y - 1)
move Down (x, y) = (x, y + 1)
move Left (x, y) = (x - 1, y)
move Right (x, y) = (x + 1, y)
initialRope :: Int -> Rope
initialRope = flip replicate (0, 0)