Day 7 Part 1

This commit is contained in:
Jens Kadenbach
2022-12-07 16:11:04 +01:00
parent 001ffc6789
commit 7d1a8b8f5c
7 changed files with 1294 additions and 0 deletions

97
src/Day7.hs Normal file
View File

@@ -0,0 +1,97 @@
module Day7 (
buildTree,
buildTree',
mkdir,
Directory (..),
calculateSize,
filterDirectories,
sumUp,
day7
) where
import Day7.Parser
import Data.Map (Map)
import qualified Data.Map as Map
data Directory = Directory
{ sub :: Map String Directory
, files :: Map String Int
, isRoot :: Bool
} deriving (Eq)
instance Show Directory where
show d = show (files d) ++ " - " ++ show (sub d) ++ "\n"
mkdir :: Directory
mkdir = Directory { sub = Map.empty, files = Map.empty, isRoot = False }
rootDirectory :: Directory
rootDirectory = Directory { sub = Map.empty, files = Map.empty, isRoot = True }
buildTree :: [TerminalCommand] -> Directory
buildTree commands = fst (buildTree' rootDirectory commands)
buildTree' :: Directory -> [TerminalCommand] -> (Directory, [TerminalCommand])
buildTree' dir [] = (dir, [])
buildTree' dir (command:cs) = case command of
Listing entries ->
let asFiles = Map.fromList $ toFiles entries
newDir = dir { files = asFiles }
in buildTree' newDir cs
In dirName ->
let subFolders = sub dir
selectedDir = Map.findWithDefault mkdir dirName subFolders
(replacement, rest) = buildTree' selectedDir cs
updatedSub = Map.insert dirName replacement subFolders
in buildTree' dir { sub = updatedSub} rest
Out -> (dir, cs)
Root -> if isRoot dir
then buildTree' dir cs
else (dir, command:cs)
toFiles :: [ListingEntry] -> [(String, Int)]
toFiles ((FileListing name size):rest) = (name, size): toFiles rest
toFiles (_:rest) = toFiles rest
toFiles [] = []
sizeThreshold :: Int
sizeThreshold = 100000
calculateSize :: Directory -> Int
calculateSize dir = sum (Map.elems (files dir)) + sum sizes
where
subFolders = Map.elems (sub dir)
sizes = map calculateSize subFolders
flatten :: Directory -> [(String, Directory)]
flatten dir = flatten' ("/", dir)
where
flatten' (name, d) = (name, d) : concatMap flatten' (Map.toList (sub d))
sizeOfDirectories :: Directory -> [(String, Int)]
sizeOfDirectories dir = map withSize allDirectories
where
allDirectories = flatten dir
withSize (name, directory) = (name, calculateSize directory)
filterDirectories :: (Int -> Bool) -> Directory -> [(String, Int)]
filterDirectories predicate dir = filter (\(_, size) -> predicate size) $ sizeOfDirectories dir
sumUp :: [(String, Int)] -> Int
sumUp = sum . map snd
forceRight :: Either a b -> b
forceRight (Left _) = error "forced Right but got Left"
forceRight (Right b) = b
day7 :: IO ()
day7 = do
input <- readFile "ressources/day07-input"
putStrLn "Day7"
let parsed = forceRight $ parseTerminalLines input
let tree = buildTree parsed
let filtered = filterDirectories (<= 100000) tree
let summed = sumUp filtered
putStrLn ("Sum of those directories is " ++ show summed)

68
src/Day7/Parser.hs Normal file
View File

@@ -0,0 +1,68 @@
module Day7.Parser (
parseTerminalLines,
TerminalCommand (..),
ListingEntry (..),
DirName,
FileName,
Size
) where
import Text.ParserCombinators.Parsec
type DirName = String
type FileName = String
type Size = Int
data ListingEntry = DirListing DirName | FileListing FileName Size
deriving (Show, Eq)
data TerminalCommand = In DirName | Out | Root | Listing [ListingEntry]
deriving (Show, Eq)
parseTerminalLines :: String -> Either ParseError [TerminalCommand]
parseTerminalLines = parse terminal "(error)"
terminal :: GenParser Char st [TerminalCommand]
terminal = many command
command :: GenParser Char st TerminalCommand
command = do
_ <- string "$ "
cd <|> ls
ls :: GenParser Char st TerminalCommand
ls = do
_ <- string "ls\n"
entries <- many listingEntry
return $ Listing entries
listingEntry :: GenParser Char st ListingEntry
listingEntry = dirListing <|> fileListing
dirListing :: GenParser Char st ListingEntry
dirListing = do
_ <- string "dir "
dirName <- many $ noneOf "\n"
_ <- char '\n'
return $ DirListing dirName
fileListing :: GenParser Char st ListingEntry
fileListing = do
fileSize <- many1 digit
_ <- char ' '
fileName <- many $ noneOf "\n"
_ <- char '\n'
return $ FileListing fileName (read fileSize)
cd :: GenParser Char st TerminalCommand
cd = do
_ <- string "cd "
name <- many $ noneOf "\n"
_ <- char '\n'
return (nameToDir name)
nameToDir :: DirName -> TerminalCommand
nameToDir "/" = Root
nameToDir ".." = Out
nameToDir ds = In ds

View File

@@ -8,6 +8,7 @@ import Day3
import Day4
import Day5
import Day6
import Day7
someFunc :: IO ()
someFunc = do
@@ -22,5 +23,7 @@ someFunc = do
day5
putStrLn "-----------"
day6
putStrLn "-----------"
day7