-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathProgram.cs
80 lines (66 loc) · 2.5 KB
/
Program.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
using AdventOfCode.Common;
var lines = Resources.GetInputFileLines();
static Directory ParseFileTree(string[] input)
{
var root = new Directory("/", null, []);
Directory currentDir = root;
var commandLine = new Queue<string>(input);
while (commandLine.TryDequeue(out string? line))
{
if (line.StartsWith("$ cd "))
{
currentDir = line.Substring(5) switch
{
"/" => root,
".." => currentDir.Parent!,
string name => (Directory)(currentDir.Items.FirstOrDefault(i => i is Directory && i.Name == name)
?? new Directory(name, currentDir, []))
};
continue;
}
if (line == "$ ls")
{
while (commandLine.TryPeek(out var child) && !child.StartsWith('$'))
{
child = commandLine.Dequeue();
if (child is ['d', 'i', 'r', ' ', .. string name])
{
currentDir.Items.Add(new Directory(name, currentDir, []));
}
else
{
var parts = child.Split(' ', 2);
currentDir.Items.Add(new File(parts[1], currentDir, long.Parse(parts[0])));
}
}
}
}
return root;
}
static Dictionary<string, long> GetDirectorySizes(Directory root, string path = "/", Dictionary<string, long>? sizes = null)
{
sizes ??= [];
long size = root.Items
.Select(item =>
{
if (item is File file) return file.Size;
var directory = (Directory)item;
var itemPath = path + "/" + item.Name;
GetDirectorySizes(directory, itemPath, sizes);
return sizes[itemPath];
})
.Sum();
sizes.Add(path, size);
return sizes;
}
Directory root = ParseFileTree(lines);
var orderedSizes = GetDirectorySizes(root).Select(kv => kv.Value).Order().ToList();
const long diskSize = 70000000L;
const long requiredFreeSpace = 30000000L;
var freeSpace = diskSize - orderedSizes.Last();
var needsToDelete = requiredFreeSpace - freeSpace;
Console.WriteLine($"Part 1: {orderedSizes.TakeWhile(size => size <= 100000).Sum()}");
Console.WriteLine($"Part 2: {orderedSizes.First(size => size >= needsToDelete)}");
abstract record Item(string Name, Directory? Parent);
record Directory(string Name, Directory? Parent, HashSet<Item> Items) : Item(Name, Parent);
record File(string Name, Directory? Parent, long Size) : Item(Name, Parent);