2022-12-08 22:50:11 +01:00
import Data.List
type Name = String
2022-12-11 12:03:12 +01:00
2022-12-08 22:50:11 +01:00
type Size = Int
2022-12-11 12:03:12 +01:00
data Inode
= File Name Size
| Folder Name [ Inode ]
deriving ( Show )
data ICrumb =
ICrumb Name [ Inode ]
deriving ( Show )
2022-12-08 22:50:11 +01:00
type IZipper = ( Inode , [ ICrumb ] )
main :: IO ()
main = do
2022-12-11 12:03:12 +01:00
input <- map words . lines <$> readFile " input "
let fullFS = walk ( tail input ) ( Folder " / " [] , [] )
2022-12-08 22:50:11 +01:00
let sizeList = getDirSizeList $ upTop fullFS
2022-12-11 12:03:12 +01:00
print $ sum $ filter ( < 100000 ) sizeList
let toDelete = subtract 40000000 $ getDirSize $ upTop fullFS
2022-12-08 22:50:11 +01:00
print $ head $ dropWhile ( < toDelete ) $ sort sizeList
up :: IZipper -> IZipper
2022-12-11 12:03:12 +01:00
up ( node , ICrumb name nodes : crumbs ) = ( Folder name ( node : nodes ) , crumbs )
2022-12-08 22:50:11 +01:00
upTop :: IZipper -> IZipper
upTop ( inode , [] ) = ( inode , [] )
upTop z = upTop ( up z )
newFile :: Inode -> IZipper -> IZipper
2022-12-11 12:03:12 +01:00
newFile node ( Folder name nodes , crumbs ) = ( Folder name ( node : nodes ) , crumbs )
2022-12-08 22:50:11 +01:00
goTo :: Name -> IZipper -> IZipper
goTo name ( Folder fname nodes , crumbs ) =
2022-12-11 12:03:12 +01:00
let ( ls , node : rs ) = break ( nameIs name ) nodes
in ( node , ICrumb fname ( ls ++ rs ) : crumbs )
2022-12-08 22:50:11 +01:00
nameIs :: Name -> Inode -> Bool
nameIs name ( Folder folderName _ ) = name == folderName
nameIs name ( File fileName _ ) = name == fileName
walk :: [ [ String ] ] -> IZipper -> IZipper
2022-12-11 12:03:12 +01:00
walk ( [ " $ " , " cd " , name ] : xs ) z =
walk xs $
if name == " .. "
then up z
else goTo name z
walk ( [ " $ " , " ls " ] : xs ) z = walk xs z
walk ( [ " dir " , name ] : xs ) z = walk xs $ newFile ( Folder name [] ) z
walk ( [ size , name ] : xs ) z = walk xs $ newFile ( File name ( read size ) ) z
2022-12-08 22:50:11 +01:00
walk _ z = z
getDirSize :: IZipper -> Int
2022-12-11 12:03:12 +01:00
getDirSize ( Folder _ nodes , _ ) = sum $ map getSize nodes
where
getSize ( File _ size ) = size
getSize folder = getDirSize ( folder , [] )
2022-12-08 22:50:11 +01:00
getDirSize _ = 0
getDirSizeList :: IZipper -> [ Int ]
2022-12-11 12:03:12 +01:00
getDirSizeList ( Folder _ nodes , _ ) =
getDirSize ( Folder " " nodes , [] ) :
concat [ getDirSizeList ( node , [] ) | node <- nodes ]
2022-12-08 22:50:11 +01:00
getDirSizeList _ = []