class Program { public static void Main() { var file = File.ReadAllLines("../../../Input.txt"); Console.WriteLine(PartOne(file)); Console.WriteLine(PartTwo(file)); } public static string PartOne(string[] input) { var storage = Storage.ParseTerminalOutput(in input); return storage.AllDirectories.Where(x => x.Size < 100_000) .Sum(x => x.Size) .ToString(); } public static string PartTwo(string[] input) { var storage = Storage.ParseTerminalOutput(input); var needSpace = 30_000_000 - (70_000_000 - storage.Size); return storage.AllDirectories.Where(x => x.Size >= needSpace) .Min(x => x.Size) .ToString(); } class Storage { private readonly Dictionary<string, Directory> _allDirectories; public readonly Directory Root; public Storage() { _allDirectories = new(); Root = new("root"); _allDirectories.Add(Root.Fullname, Root); } public IEnumerable<Directory> AllDirectories => _allDirectories.Values; public int Size => Root.Size; public void AddDirectory(Directory parent, string name) { var directory = parent.AddDirectory(name); if (directory != null) { _allDirectories.Add(directory.Fullname, directory); } } public void AddFile(Directory directory, string name, int size) { directory.AddFile(name, size); } internal static Storage ParseTerminalOutput(in string[] inputLines) => Parser.Parse(in inputLines); internal class Directory { public readonly Directory Parent; public readonly string Name; private readonly Dictionary<string, Directory> _directories; private readonly Dictionary<string, File> _files; public Directory(string name) : this(null, name) { } public Directory(Directory parent, string name) { _directories = new Dictionary<string, Directory>(); _files = new Dictionary<string, File>(); Parent = parent; Name = name; Size = 0; } public int Size { get; private set; } public string Fullname => Parent != null ? $"{Parent.Fullname}\\{Name}" : Name; private void IncreaseSize(int size) { Size += size; Parent?.IncreaseSize(size); } internal Directory? AddDirectory(string name) { if (_directories.ContainsKey(name)) return null; var directory = new Directory(this, name); _directories.Add(name, directory); return directory; } internal File? AddFile(string name, int size) { if (_files.ContainsKey(name)) return null; var file = new File(this, name, size); _files.Add(name, file); IncreaseSize(size); return file; } internal Directory GetDirectory(string name) => _directories[name]; public override string ToString() => $"{Name} {Size}"; } internal class File { public File(Directory directory, string name, int size) { Directory = directory; Name = name; Size = size; } public Directory Directory { get; private set; } public string Name { get; private set; } public int Size { get; private set; } public override string ToString() => $"{Name} {Size}"; public string Fullname => $"{Directory.Fullname}\\{Name}"; } internal static class Parser { private static readonly string ListAll = "$ ls"; private static readonly string GoToRoot = "$ cd /"; private static readonly string GoBack = "$ cd .."; private static readonly string GoTo = "$ cd"; private static readonly string DirPrefix = "dir"; private static readonly int GoToJumpCount = GoTo.Length + 1; private static readonly int DirPrefixJumpCount = DirPrefix.Length + 1; public static Storage Parse(in string[] inputLines) { var storage = new Storage(); var currecntDirectory = storage.Root; foreach (var inputLineRaw in inputLines) { var inputLine = inputLineRaw.AsSpan(); if (inputLine.StartsWith(ListAll)) { continue; } if (inputLine.StartsWith(GoToRoot)) { currecntDirectory = storage.Root; continue; } if (inputLine.StartsWith(GoBack)) { currecntDirectory = currecntDirectory?.Parent ?? storage.Root; continue; } if (inputLine.StartsWith(GoTo)) { var directoryName = inputLine[GoToJumpCount..].ToString(); currecntDirectory = currecntDirectory.GetDirectory(directoryName) ?? currecntDirectory; continue; } if (inputLine.StartsWith(DirPrefix)) { var directoryName = inputLine[DirPrefixJumpCount..].ToString(); storage.AddDirectory(currecntDirectory, directoryName); continue; } var spaceIndex = inputLine.IndexOf(' '); var size = int.Parse(inputLine[..spaceIndex]); var fileName = inputLine[spaceIndex..].ToString(); storage.AddFile(currecntDirectory, fileName, size); continue; } return storage; } } } }