From: Neil Smith Date: Mon, 12 Dec 2016 12:29:47 +0000 (+0000) Subject: Day 11 X-Git-Url: https://git.njae.me.uk/?a=commitdiff_plain;h=35f60bc907c0bf8b5037a537671bba9307ab6f6b;p=advent-of-code-16.git Day 11 --- diff --git a/advent11.hs b/advent11.hs new file mode 100644 index 0000000..af048de --- /dev/null +++ b/advent11.hs @@ -0,0 +1,125 @@ +import Data.List (subsequences, (\\), sort, sortBy) +import Data.Ord (comparing) + +data Item = Generator String | Microchip String deriving (Show, Eq) +type Floor = [Item] +data Building = Building Int [Floor] deriving (Show, Eq) + +instance Ord Item where + compare (Generator a) (Generator b) = compare a b + compare (Microchip a) (Microchip b) = compare a b + compare (Generator _) (Microchip _) = LT + compare (Microchip _) (Generator _) = GT + +instance Ord Building where + compare b1 b2 = comparing estimateCost b1 b2 + +building1 = Building 0 [ + (sort [Generator "polonium", Generator "thulium", + Microchip "thulium", Generator "promethium", Generator "ruthenium", + Microchip "ruthenium", Generator "cobalt", Microchip "cobalt"]), + (sort [Microchip "polonium", Microchip "promethium"]), + [], + [] + ] + +building2 = Building 0 [ + (sort [Generator "polonium", Generator "thulium", + Microchip "thulium", Generator "promethium", Generator "ruthenium", + Microchip "ruthenium", Generator "cobalt", Microchip "cobalt", + Generator "elerium", Microchip "elerium", + Generator "dilithium", Microchip "dilithium"]), + (sort [Microchip "polonium", Microchip "promethium"]), + [], + [] + ] + + +buildingTest = Building 0 [ + sort([Microchip "hydrogen", Microchip "lithium"]), + [Generator "hydrogen"], + [Generator "lithium"], + []] + +main :: IO () +main = do + part1 + part2 + + +part1 :: IO () +-- part1 = print $ length $ init $ extractJust $ aStar [[buildingTest]] [] +part1 = print $ length $ init $ extractJust $ aStar [[building1]] [] + +part2 :: IO () +part2 = print $ length $ init $ extractJust $ aStar [[building2]] [] + + +extractJust :: Maybe [a] -> [a] +extractJust Nothing = [] +extractJust (Just x) = x + +aStar :: [[Building]] -> [Building] -> Maybe [Building] +aStar [] _ = Nothing +aStar (currentTrail:trails) closed = + if isGoal (head currentTrail) then Just currentTrail + else aStar newAgenda ((head currentTrail): closed) + where newAgenda = + sortBy (\t1 t2 -> (head t1) `compare` (head t2)) $ + trails ++ (candidates currentTrail closed) + +candidates :: [Building] -> [Building] -> [[Building]] +candidates currentTrail closed = newCandidates + where + (candidate:trail) = currentTrail + succs = legalSuccessors $ successors candidate + nonloops = (succs \\ trail) \\ closed + newCandidates = map (\n -> n:candidate:trail) nonloops + +isGoal :: Building -> Bool +isGoal (Building f floors) = + f+1 == height && (all (null) $ take f floors) + where height = length floors + +isLegal :: Building -> Bool +isLegal (Building f floors) = + null floor + || + not (any (isGenerator) floor) + || + any (safePair) pairs + where floor = floors!!f + pairs = [(i, j) | i <- floor, j <- floor, isGenerator i] + safePair (Generator e, Microchip f) = e == f + safePair (Generator _, Generator _) = False + +isGenerator :: Item -> Bool +isGenerator (Generator _) = True +isGenerator (Microchip _) = False + +successors :: Building -> [Building] +successors (Building f floors) = [updateBuilding f floors nf is | nf <- nextFloors, is <- items] + where + floor = floors!!f + items = filter (\is -> length is == 1 || length is == 2) $ subsequences floor + nextFloors = if f == 0 then [1] + else if f+1 == length floors then [f-1] + else [f+1, f-1] + +legalSuccessors :: [Building] -> [Building] +legalSuccessors = filter (isLegal) + +updateBuilding :: Int -> [Floor] -> Int -> [Item] -> Building +-- updateBuilding f floors _ _ = Building f floors +updateBuilding oldF oldFloors newF items = Building newF newFloors + where numberedFloors = zip [0..] oldFloors + newFloors = map (updateFloor) numberedFloors + updateFloor (f, fl) + | f == oldF = sort $ fl \\ items + | f == newF = sort $ items ++ fl + | otherwise = fl + +estimateCost :: Building -> Int +estimateCost (Building _ floors) = + sum $ map (\(c, f) -> c * length f) $ zip [0..] $ reverse floors +