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