summaryrefslogtreecommitdiff
path: root/2019/3.hs
blob: b0f8e714c2dee24f5f13a2951e26422d71479909 (plain)
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
66
67
68
69
70
module Main where

import Data.Char
import Data.List
import qualified Data.Map.Strict as Map
import qualified Data.Set as Set

import Input


data Pt = Pt Int Int deriving (Show, Eq, Ord)
data Dir = U | L | D | R deriving (Show)
data Seg = Seg Pt Dir Int deriving (Show)

direction :: Dir -> Pt
direction U = Pt 0 1
direction R = Pt 1 0
direction D = Pt 0 (-1)
direction L = Pt (-1) 0

add :: Pt -> Pt -> Pt
add (Pt x y) (Pt a b) = Pt (x + a) (y + b)

scale :: Int -> Pt -> Pt
scale n (Pt x y) = Pt (n * x) (n * y)

parse :: String -> [(Dir, Int)]
parse "" = []
parse (c:s) =
    let dir = case c of
                  'U' -> U
                  'R' -> R
                  'D' -> D
                  'L' -> L
                  _ -> undefined
        (ns, r) = span isDigit s
    in (dir, read ns) : parse (dropWhile (== ',') r)

process :: Pt -> [(Dir, Int)] -> [Seg]
process _ [] = []
process pt ((dir, n) : rest) =
    Seg pt dir n : process (add pt (scale n (direction dir))) rest

points :: Seg -> [Pt]
points (Seg pt dir n) =
    let delta = direction dir
    in [add pt (scale k delta) | k <- [1..n]]

manhattan :: Pt -> Int
manhattan (Pt x y) = abs x + abs y

data Hit = Hit {hitPt :: Pt, hitIdx :: Int} deriving (Show)
instance Eq Hit where Hit p _ == Hit q _ = p == q
instance Ord Hit where compare (Hit p _) (Hit q _) = compare p q

points2 :: Int -> [Seg] -> [Hit]
points2 _ [] = []
points2 start (Seg pt dir n : segs) =
    let delta = direction dir
    in [Hit (add pt (scale k delta)) (start + k) | k <- [1..n]] ++ points2 (start + n) segs

main :: IO ()
main = do
    ls <- map (process (Pt 0 0) . parse) <$> getInput 3
    let pts = Set.toList (foldl1 Set.intersection (map (Set.fromList . concatMap points) ls))
    print (manhattan (head (sortOn manhattan pts)))

    let idxMap1 = Map.fromList . reverse $ [(hitPt h, hitIdx h) | h <- points2 0 (ls !! 0)]
        idxMap2 = Map.fromList . reverse $ [(hitPt h, hitIdx h) | h <- points2 0 (ls !! 1)]
    print $ minimum (zipWith (+) (map (idxMap1 Map.!) pts) (map (idxMap2 Map.!) pts))