1 -- Some code taken from [AoC 2017 day 5](https://adventofcode.com/2017/day/5),
2 -- and some from [AoC 2018 day 21](https://adventofcode.com/2018/day/21)
4 import Data.Text (Text)
5 import qualified Data.Text.IO as TIO
7 import Data.Void (Void)
9 import Text.Megaparsec hiding (State)
10 import Text.Megaparsec.Char
11 import qualified Text.Megaparsec.Char.Lexer as L
12 import qualified Control.Applicative as CA
14 import Data.List (foldl')
15 import qualified Data.Set as S
17 import Linear (V2(..), (^+^), (^-^), (*^), (*^))
19 data Direction = East | South | West | North deriving (Show, Eq)
21 type Location = V2 Int -- x, y
23 type Visited = S.Set Location
25 data Path = Path { _visited :: Visited
30 data Segment = Segment { _direction :: Direction
37 text <- TIO.readFile "data/advent03.txt"
38 let segmentss = successfulParse text
40 -- print $ travelPath $ head segmentss
41 print $ part1 segmentss
42 -- print $ part2 machine
44 part1 :: [[Segment]] -> Int
45 part1 segmentss = closest $ crossovers $ travelAllPaths segmentss
47 closest :: Visited -> Int
48 closest points = S.findMin $ S.map manhattan points
50 crossovers :: [Path] -> Visited
51 crossovers travelledPaths =
53 (_visited $ head travelledPaths)
54 (map _visited $ drop 1 travelledPaths)
56 travelAllPaths :: [[Segment]] -> [Path]
57 travelAllPaths = map travelPath
59 travelPath :: [Segment] -> Path
60 travelPath segments = foldl' travelSegment path0 segments
61 where path0 = Path { _visited = S.empty, _tip = V2 0 0 }
63 travelSegment :: Path -> Segment -> Path
64 travelSegment path segment = path { _tip = tip', _visited = visited' }
65 where delta = facing $ _direction segment
66 distance = _steps segment
68 visited = _visited path
69 visited' = foldl' (flip S.insert) visited $ take distance $ drop 1 $ iterate (^+^ delta) start
70 tip' = start ^+^ distance *^ delta
72 facing :: Direction -> Location
74 facing South = V2 0 (-1)
75 facing West = V2 (-1) 0
79 manhattan (V2 x y) = (abs x) + (abs y)
81 -- Parse the input file
82 type Parser = Parsec Void Text
85 sc = L.space (skipSome spaceChar) CA.empty CA.empty
86 -- sc = L.space (skipSome (char ' ')) CA.empty CA.empty
89 integer = lexeme L.decimal
90 -- signedInteger = L.signed sc integer
95 pathP = segmentP `sepBy1` comma
97 segmentP = segmentify <$> directionP <*> integer
98 where segmentify direction steps =
99 Segment { _direction = direction, _steps = steps }
102 directionP = eP <|> sP <|> wP <|> nP
103 eP = (symb "R" *> pure East)
104 sP = (symb "D" *> pure South)
105 wP = (symb "L" *> pure West)
106 nP = (symb "U" *> pure North)
109 successfulParse :: Text -> [[Segment]]
110 successfulParse input =
111 case parse wiresP "input" input of
112 Left _err -> [] -- TIO.putStr $ T.pack $ parseErrorPretty err