-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay07.cs
133 lines (117 loc) · 3.85 KB
/
Day07.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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
using System.Text.RegularExpressions;
namespace AdventOfCode2022;
internal partial class Day07
{
public interface INode
{
string Name { get; }
int Size { get; }
}
public class Directory : INode
{
public string Name { get; init; }
public Directory? Parent { get; init; }
public List<INode> Children { get; } = new List<INode>();
public int Size => Children.Sum(x => x.Size);
}
public class File : INode
{
public string Name { get; init; }
public int Size { get; init; }
}
private readonly Directory _root = new() { Name = "/" };
public Day07(IEnumerable<string> input)
{
var current = _root;
foreach (var line in input)
{
switch (line)
{
case "$ cd /":
current = _root;
break;
case "$ cd ..":
if (current.Parent != null)
{
current = current.Parent;
}
break;
case string cd when cd.StartsWith("$ cd"):
var targetName = cd[5..];
if (current.Children.FirstOrDefault(x => x.Name == targetName) is Directory target)
{
current = target;
}
break;
case string dir when dir.StartsWith("dir "):
var dirName = dir[4..];
if (current.Children.All(x => x.Name != dirName))
{
current.Children.Add(new Directory { Name = dirName, Parent = current });
}
break;
case string file when FilePattern().IsMatch(file):
var fileSize = file.Split(' ')[0];
var fileName = file.Split(' ')[1];
if (current.Children.All(x => x.Name != fileName))
{
current.Children.Add(new File { Name = fileName, Size = int.Parse(fileSize) });
}
break;
}
}
}
public int PartOne()
{
return Traverse(dir => dir.Size <= 100000).Sum(d => d.Size);
}
public int PartTwo()
{
var freeSpace = 70000000 - _root.Size;
var requiredSpace = 30000000 - freeSpace;
return Traverse(dir => dir.Size >= requiredSpace).Select(d => d.Size).Min();
}
private IEnumerable<Directory> Traverse(Func<Directory, bool> predicate)
{
var queue = new Queue<Directory>();
queue.Enqueue(_root);
while (queue.Any())
{
var dir = queue.Dequeue();
if (predicate.Invoke(dir))
{
yield return dir;
}
foreach (var c in dir.Children)
{
if (c is Directory d)
{
queue.Enqueue(d);
}
}
}
}
[GeneratedRegex("\\d+ .*")]
private static partial Regex FilePattern();
}
public class Day07Test
{
private const string InputFile = "Day07.Input.txt";
private const string ExampleFile = "Day07.Example.txt";
[Theory]
[FileData(ExampleFile, FileContents.StringPerLine, 95437)]
[FileData(InputFile, FileContents.StringPerLine, 1477771)]
public void TestPartOne(IEnumerable<string> input, int expected)
{
var solution = new Day07(input);
Assert.Equal(expected, solution.PartOne());
}
[Theory]
[FileData(ExampleFile, FileContents.StringPerLine, 24933642)]
[FileData(InputFile, FileContents.StringPerLine, 3579501)]
public void TestPartTwo(IEnumerable<string> input, int expected)
{
var solution = new Day07(input);
Assert.Equal(expected, solution.PartTwo());
}
}