day7: clean up a bit and add comments

Signed-off-by: Amneesh Singh <natto@weirdnatto.in>
This commit is contained in:
2022-12-07 16:43:56 +05:30
parent a4c25f5d1f
commit 205c5deed3
2 changed files with 39 additions and 34 deletions

View File

@@ -2,7 +2,7 @@ import Data.Tree
main :: IO () main :: IO ()
main = do main = do
tree <- flip parse (emptyFs "/") . map words . lines <$> readFile "day7.in" tree <- snd . flip parse (emptyFs "/") . map words . lines <$> readFile "day7.in"
putStr "Q1: " putStr "Q1: "
print $ print $
foldTree foldTree
@@ -22,36 +22,35 @@ main = do
) )
tree tree
type Filesystem = Tree (String, Int)
tail' :: [a] -> [a] tail' :: [a] -> [a]
tail' = drop 1 tail' = drop 1
emptyFs :: String -> Tree (String, Int) emptyFs :: String -> Filesystem
emptyFs n = Node (n, 0) [] emptyFs n = Node (n, 0) []
insertFs :: Tree (String, Int) -> String -> Tree (String, Int) -> Tree (String, Int) insertFs :: Filesystem -> String -> Filesystem -> Filesystem
insertFs (Node n xs) name dir = Node (fst n, snd n + snd (rootLabel dir)) (dir : xs) insertFs (Node n xs) name fs = Node (fst n, snd n + snd (rootLabel fs)) (fs : xs)
totalSize :: [Tree (String, Int)] -> Int totalSize :: [Filesystem] -> Int
totalSize = sum . map (snd . rootLabel) totalSize = sum . map (snd . rootLabel)
ls :: [[String]] -> [Tree (String, Int)] ls :: [[String]] -> [Filesystem]
ls = map (\[a, b] -> Node (b, read a) []) . filter ((/= "dir") . head) ls = map (\[a, b] -> Node (b, read a) []) . filter ((/= "dir") . head)
parse :: [[String]] -> Tree (String, Int) -> Tree (String, Int) parse :: [[String]] -> Filesystem -> ([[String]], Filesystem)
parse input fs = snd $ parse' input fs parse input fs
| null input || cur == ["$", "cd", ".."] = (tail' input, fs)
parse' :: [[String]] -> Tree (String, Int) -> ([[String]], Tree (String, Int)) | cur == ["$", "ls"] =
parse' input fs
| null input || cur !! 1 == "cd" && cur !! 2 == ".." = (tail' input, fs)
| cur !! 1 == "ls" =
let (children, rest) = span ((/= "$") . head) (tail' input) let (children, rest) = span ((/= "$") . head) (tail' input)
childFs = ls children leaves = ls children
name = fst $ rootLabel fs name = fst $ rootLabel fs
in parse' rest (Node (name, totalSize childFs) childFs) in parse rest (Node (name, totalSize leaves) leaves)
| otherwise = | otherwise =
let name = cur !! 2 let name = cur !! 2
(nextInput, newFs) = parse' (tail' input) (emptyFs name) (nextInput, newFs) = parse (tail' input) (emptyFs name)
replaced = insertFs fs name newFs -- replace empty directory replaced = insertFs fs name newFs -- replace empty directory
in parse' nextInput replaced in parse nextInput replaced
where where
cur = head input cur = head input

40
day7.hs
View File

@@ -1,12 +1,12 @@
import Data.Tree import Data.Tree
-- this solution assumes that empty directories can exist, -- this solution assumes that empty directories can exist,
-- if you want to ignore that, there is a slightly more compact code as day7'.hs -- if you want to ignore that, there is a slightly different code in day7'.hs
-- needs cleaning and improvement -- needs cleaning and improvement
main :: IO () main :: IO ()
main = do main = do
tree <- flip parse (emptyFs "/") . map words . lines <$> readFile "day7.in" tree <- snd . flip parse (emptyFs "/") . map words . lines <$> readFile "day7.in"
putStr "Q1: " putStr "Q1: "
print $ print $
foldTree foldTree
@@ -26,40 +26,46 @@ main = do
) )
tree tree
type Filesystem = Tree (String, Int)
tail' :: [a] -> [a] tail' :: [a] -> [a]
tail' = drop 1 tail' = drop 1
emptyFs :: String -> Tree (String, Int) -- wrapper to create an empty tree
emptyFs :: String -> Filesystem
emptyFs n = Node (n, 0) [] emptyFs n = Node (n, 0) []
replaceFs :: Tree (String, Int) -> String -> Tree (String, Int) -> Tree (String, Int) -- This function is to replace a filesystem by name
-- Used to replace empty directories with parsed directories in code
replaceFs :: Filesystem -> String -> Filesystem -> Filesystem
replaceFs (Node n xs) name fs = replaceFs (Node n xs) name fs =
let (h, t) = span ((/= name) . fst . rootLabel) xs let (h, t) = span ((/= name) . fst . rootLabel) xs
in Node in Node
(fst n, snd n + snd (rootLabel fs)) (fst n, snd n + snd (rootLabel fs))
(h ++ [fs] ++ tail' t) (h ++ [fs] ++ tail' t)
totalSize :: [Tree (String, Int)] -> Int -- Sum of all filesystems in the list
-- Used to calculate sum of leaves in code
totalSize :: [Filesystem] -> Int
totalSize = sum . map (snd . rootLabel) totalSize = sum . map (snd . rootLabel)
ls :: [[String]] -> [Tree (String, Int)] -- All directories/files are parsed here into leaves
ls :: [[String]] -> [Filesystem]
ls = map (\[a, b] -> if a == "dir" then Node (b, 0) [] else Node (b, read a) []) ls = map (\[a, b] -> if a == "dir" then Node (b, 0) [] else Node (b, read a) [])
parse :: [[String]] -> Tree (String, Int) -> Tree (String, Int) -- main function where stuff happens
parse input fs = snd $ parse' input fs parse :: [[String]] -> Filesystem -> ([[String]], Filesystem)
parse input fs
parse' :: [[String]] -> Tree (String, Int) -> ([[String]], Tree (String, Int)) | null input || cur == ["$", "cd", ".."] = (tail' input, fs)
parse' input fs | cur == ["$", "ls"] =
| null input || cur !! 1 == "cd" && cur !! 2 == ".." = (tail' input, fs)
| cur !! 1 == "ls" =
let (children, rest) = span ((/= "$") . head) (tail' input) let (children, rest) = span ((/= "$") . head) (tail' input)
childFs = ls children leaves = ls children
name = fst $ rootLabel fs name = fst $ rootLabel fs
in parse' rest (Node (name, totalSize childFs) childFs) in parse rest (Node (name, totalSize leaves) leaves)
| otherwise = | otherwise =
let name = cur !! 2 let name = cur !! 2
(nextInput, newFs) = parse' (tail' input) (emptyFs name) (nextInput, newFs) = parse (tail' input) (emptyFs name)
replaced = replaceFs fs name newFs -- replace empty directory replaced = replaceFs fs name newFs -- replace empty directory
in parse' nextInput replaced in parse nextInput replaced
where where
cur = head input cur = head input