diff --git a/Makefile b/Makefile index 3f9abc8..f9256d5 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -DAY = 10 +DAY = 7 DIR = day$(DAY) diff --git a/day7/main.hs b/day7/main.hs new file mode 100644 index 0000000..d399fde --- /dev/null +++ b/day7/main.hs @@ -0,0 +1,122 @@ +import System.IO + +import Data.List +import Data.List.Split + +import Debug.Trace + + + +data Node = File String Int | Dir String Int [Node] deriving (Show) + +instance Eq Node where + Dir n1 _ _ == Dir n2 _ _ = n1 == n2 + File n1 _ == File n2 _ = n1 == n2 + +instance Ord Node where + Dir _ s1 _ `compare` Dir _ s2 _ = s1 `compare` s2 + File _ s1 `compare` File _ s2 = s1 `compare` s2 + +nodeSize :: Node -> Int +nodeSize (File _ s) = s +nodeSize (Dir _ s _) = s + + +nodeInfo :: Node -> String +nodeInfo (File n s) = n ++ "(file, size=" ++ show s ++ ")" +nodeInfo (Dir n s _) = n ++ "(dir, size=" ++ show s ++ ")" + +printNode :: Int -> Node -> String +printNode lvl n = case n of + File n s -> sp ++ "- " ++ n ++ " (file, size=" ++ show s ++ ")\n" + Dir n s c -> sp ++ "- " ++ n ++ " (dir, size=" ++ show s ++ ")\n" ++ printNodes (lvl+1) c + where + sp = replicate (2*lvl) ' ' + +printNodes :: Int -> [Node] -> String +printNodes a = concat . map (printNode a) + + + + + +--parseDir' :: [String] -> [Node] +--parseDir' (x:xs) = + +dirInNodes :: String -> [Node] -> (Bool,Node,[Node]) +dirInNodes name onodes = (exists, instanc, removed) + where + matches = filter (\node@(Dir n _ _) -> n == name) onodes + exists = (length matches) > 0 + instanc = if exists then head matches else File "" 0 + removed = delete instanc onodes + + + + +parseDir :: [Node] -> [Node] -> [String] -> ([Node],[String]) +parseDir onodes nodes (x:xs) + | "$ cd " `isPrefixOf` x = ((Dir (drop 5 x) (sum $ map nodeSize nodes) nodes:onodes), xs) + | "dir " `isPrefixOf` x = case dirInNodes (drop 4 x) onodes of + (True,node,restnodes) -> parseDir restnodes (node:nodes) xs + (False,_,_) -> parseDir onodes nodes xs + | otherwise = parseDir onodes (File fname fsize:nodes) xs + where + [fsize',fname] = splitOn " " x + fsize = read fsize' :: Int + + + +parseCli :: [Node] -> [String] -> [String] -> [Node] +parseCli nodes [] [] = [] +parseCli nodes stack [] = onodes ++ parseCli onodes reststack [] + where (onodes,reststack) = parseDir nodes [] $ stack +parseCli nodes stack (x:xs) + | x == "$ cd .." = onodes ++ parseCli onodes reststack xs + | otherwise = parseCli nodes (x:stack) xs + where (onodes,reststack) = parseDir nodes [] $ stack + + +prepCli :: [String] -> [String] +prepCli = filter (/= "$ ls") + + + + + +findNodes :: (Node -> Bool) -> Node -> [Node] +findNodes f file@(File _ _) = if (f file) then [file] else [] +findNodes f dir@(Dir _ _ c) = (if (f dir) then [dir] else []) ++ (concat $ map (findNodes f) c) + + +dirSize :: (Int -> Bool) -> Node -> Bool +dirSize _ (File _ _) = False +dirSize f (Dir _ s _) = f s + + + + +findDeletable :: Int -> Int -> Node -> Node +findDeletable fss req root@(Dir _ used _) = smallest + where + tbf = req - (fss-used) + candidates = findNodes (dirSize (>= tbf)) root + smallest = head $ sort candidates + + + + +handler :: String -> String +handler s = (show sumUnder) ++ "\n" ++ + (show savsize) ++ "\n" + where + rootNode = last $ parseCli [] [] $ prepCli $ lines s + under100k = findNodes (dirSize (<= 100000)) rootNode + sumUnder = sum $ map (\(Dir _ s _) -> s) under100k + (Dir _ savsize _) = findDeletable 70000000 30000000 rootNode + +main :: IO () +main = do + interact handler + +