day7. finally.
This commit is contained in:
		
							
								
								
									
										122
									
								
								day7/main.hs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								day7/main.hs
									
									
									
									
									
										Normal file
									
								
							@ -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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user