day7. finally.
This commit is contained in:
parent
f576146891
commit
3a1d612f97
|
@ -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 "<nonexistent>" 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
|
||||
|
||||
|
Loading…
Reference in New Issue