-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrun.hs
56 lines (44 loc) · 1.74 KB
/
run.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
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE FlexibleContexts #-}
import Control.Applicative ((<|>))
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import Data.Hashable (Hashable)
import Data.List (minimumBy, permutations, nub)
import Data.Maybe
import Data.Set (Set)
import qualified Data.Set as Set
import Data.String (IsString, fromString)
import Text.Parsec hiding ((<|>))
newtype City = City String
deriving (Show, Read, Eq, IsString, Ord, Hashable)
type Distance = Integer
data Path = Path { start :: City
, stop :: City
, dist :: Distance
}
deriving Show
city = fromString <$> many1 (oneOf az)
where az = ['A'..'Z'] ++ ['a'..'z']
number = fromInteger . read <$> many1 digit
path = Path <$> city <*> (string " to " *> city) <*> (string " = " *> number)
readPath s = case parse path "" s of
Right x -> Just x
Left _ -> Nothing
parseAll = mapMaybe readPath . lines
type Result = ([City], Distance)
shortestPath :: [Path] -> Result
shortestPath paths = minimumBy (\a b -> snd a `compare` snd b)
. map (\cs -> (cs, sum $ zipWith lookup cs (drop 1 cs)))
. permutations $ cities
where cities = nub $ map start paths ++ map stop paths
distances = HashMap.fromList . map (\p -> ((start p, stop p), dist p)) $ paths
lookup s e = fromJust $ HashMap.lookup (s, e) distances <|> HashMap.lookup (e, s) distances
remove :: Eq a => a -> [a] -> [a]
remove x = filter (/= x)
part1 = snd . shortestPath
part2 = negate . snd . shortestPath . map (\p -> p { dist = negate (dist p) })
main = do
input <- parseAll <$> readFile "input.txt"
print $ part1 input
print $ part2 input