--- Some code taken from [AoC 2017 day 5](https://adventofcode.com/2017/day/5),
--- and some from [AoC 2018 day 21](https://adventofcode.com/2018/day/21)
-
import Data.Text (Text)
import qualified Data.Text.IO as TIO
import Data.List (foldl')
import qualified Data.Set as S
+import qualified Data.Map as M
+import Data.Map ((!))
import Linear (V2(..), (^+^), (^-^), (*^), (*^))
type Visited = S.Set Location
-data Path = Path { _visited :: Visited
+type TrackedVisited = M.Map Location Int
+
+data Path = Path { _visited :: TrackedVisited
, _tip :: Location
+ , _currentLength :: Int
}
deriving (Show, Eq)
main = do
text <- TIO.readFile "data/advent03.txt"
let segmentss = successfulParse text
- print segmentss
+ let paths = travelAllPaths segmentss
-- print $ travelPath $ head segmentss
- print $ part1 segmentss
- -- print $ part2 machine
+ print $ part1 paths
+ print $ part2 paths
+
+part1 :: [Path] -> Int
+part1 paths = closest $ crossovers paths
+
+part2 :: [Path] -> Int
+part2 paths = shortestPaths paths $ crossovers paths
-part1 :: [[Segment]] -> Int
-part1 segmentss = closest $ crossovers $ travelAllPaths segmentss
closest :: Visited -> Int
closest points = S.findMin $ S.map manhattan points
+
+shortestPaths :: [Path] -> Visited -> Int
+shortestPaths paths crossings = minimum $ S.map crossingPathLengths crossings
+ where crossingPathLengths crossing = sum $ map (\p -> (_visited p)!crossing) paths
+
+
crossovers :: [Path] -> Visited
crossovers travelledPaths =
foldl' S.intersection
- (_visited $ head travelledPaths)
- (map _visited $ drop 1 travelledPaths)
+ (M.keysSet $ _visited $ head travelledPaths)
+ (map (M.keysSet . _visited) $ drop 1 travelledPaths)
travelAllPaths :: [[Segment]] -> [Path]
travelAllPaths = map travelPath
travelPath :: [Segment] -> Path
travelPath segments = foldl' travelSegment path0 segments
- where path0 = Path { _visited = S.empty, _tip = V2 0 0 }
+ where path0 = Path { _visited = M.empty, _tip = V2 0 0, _currentLength = 0 }
travelSegment :: Path -> Segment -> Path
-travelSegment path segment = path { _tip = tip', _visited = visited' }
+travelSegment path segment = path { _tip = tip', _visited = visited', _currentLength = len'}
where delta = facing $ _direction segment
distance = _steps segment
start = _tip path
+ len = _currentLength path
+ len' = len + distance
visited = _visited path
- visited' = foldl' (flip S.insert) visited $ take distance $ drop 1 $ iterate (^+^ delta) start
+ visited' = foldl' insertStep visited $ take distance $ drop 1 $ zip [len, (len + 1) ..] $ iterate (^+^ delta) start
tip' = start ^+^ distance *^ delta
+ insertStep visits (dist, loc) = if loc `M.member` visits
+ then visits
+ else M.insert loc dist visits
facing :: Direction -> Location
facing East = V2 1 0