-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay9.cs
124 lines (98 loc) · 3.84 KB
/
Day9.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
namespace Aoc2024Net.Days
{
internal sealed class Day9 : Day
{
private abstract record Block(int Size);
private record FileBlock(int Size, int Id) : Block(Size);
private record FreeSpaceBlock(int Size) : Block(Size);
public override object? SolvePart1() =>
Solve(false);
public override object? SolvePart2() =>
Solve(true);
private long Solve(bool moveWhole)
{
var blocks = GetBlocks();
var filesCount = blocks.Count(b => b is FileBlock);
for (var fileId = filesCount - 1; fileId >= 0; fileId--)
{
var fileNode = FindNode(blocks, node => node.Value is FileBlock fileBlock && fileBlock.Id == fileId);
var file = (FileBlock)fileNode.Value;
var fileSize = file.Size;
while (fileSize > 0)
{
var freeSpaceNode = FindNode(
blocks,
node => node.Value is FreeSpaceBlock && (!moveWhole || node.Value.Size >= file.Size),
node => node == fileNode);
if (freeSpaceNode == null)
break;
if (blocks.Contains(fileNode.Value))
{
var filePreviousNode = fileNode.Previous;
blocks.Remove(fileNode);
blocks.AddAfter(filePreviousNode, new FreeSpaceBlock(file.Size));
}
var freeSpaceSize = freeSpaceNode.Value.Size;
var cutSize = Math.Min(fileSize, freeSpaceSize);
var freeSpacePreviousNode = freeSpaceNode.Previous;
blocks.Remove(freeSpaceNode);
var newFileNode = blocks.AddAfter(freeSpacePreviousNode, new FileBlock(cutSize, file.Id));
if (freeSpaceSize - cutSize > 0)
blocks.AddAfter(newFileNode, new FreeSpaceBlock(freeSpaceSize - cutSize));
fileSize -= cutSize;
}
}
return CalculateChecksum(blocks);
}
private long CalculateChecksum(LinkedList<Block> blocks)
{
var result = 0L;
var position = 0;
foreach (var block in blocks)
{
if (block is FreeSpaceBlock)
{
position += block.Size;
continue;
}
for (var i = 0; i < block.Size; i++)
{
result += position * ((FileBlock)block).Id;
position++;
}
}
return result;
}
private LinkedListNode<Block>? FindNode(
LinkedList<Block> blocks,
Predicate<LinkedListNode<Block>> predicate,
Predicate<LinkedListNode<Block>>? stopPredicate = null)
{
for (var node = blocks.First; node != null; node = node.Next)
{
if (stopPredicate?.Invoke(node) == true)
return null;
if (predicate(node))
return node;
}
return null;
}
private LinkedList<Block> GetBlocks()
{
var text = InputData.GetInputText();
var blocks = new LinkedList<Block>();
var isFile = true;
var fileId = 0;
for (var i = 0; i < text.Length; i++)
{
var size = int.Parse(text[i].ToString());
if (isFile)
blocks.AddLast(new FileBlock(size, fileId++));
else
blocks.AddLast(new FreeSpaceBlock(size));
isFile = !isFile;
}
return blocks;
}
}
}