Skip to content

Commit

Permalink
2024 Day09 refactored
Browse files Browse the repository at this point in the history
  • Loading branch information
smabuk committed Dec 9, 2024
1 parent eb4059f commit 7e152bf
Showing 1 changed file with 94 additions and 74 deletions.
168 changes: 94 additions & 74 deletions Solutions/2024/Day09.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,131 +5,151 @@
/// https://adventofcode.com/2024/day/09
/// </summary>
[Description("Disk Fragmenter")]
public partial class Day09 {
public static partial class Day09 {

public static long Part1(string[] input)
{
string denseDiskMap = input[0];
List<int> diskMapAsInts = [.. denseDiskMap.AsDigits<int>()];
int blockCount = diskMapAsInts.Sum();
return input[0]
.AsDigits<int>()
.CreateDiskMap()
.CompactDisk()
.FileChecksum();
}

List<int> diskMap = new (blockCount);
for (int i = 0; i < blockCount; i++) {
diskMap.Add(EMPTY);
}
public static long Part2(string[] input)
{
return
input[0]
.AsDigits<int>()
.CreateDiskMapAsBlocks()
.Defragment()
.FileChecksum();
}


private static List<int> CreateDiskMap(this IEnumerable<int> diskMapAsInts)
{
List<int> diskMap = [.. Enumerable.Repeat(EMPTY, diskMapAsInts.Sum())];

bool fileOrFreeSpace = FILE;
int diskMapPtr = 0;
int blockNo = 0;
foreach (int item in diskMapAsInts) {
bool fileOrFreeSpace = FILE;

foreach (int blockSize in diskMapAsInts) {
if (fileOrFreeSpace is FILE) {
for (int i = 0; i < item; i++) {
for (int i = 0; i < blockSize; i++) {
diskMap[diskMapPtr++] = blockNo;
}

blockNo++;
fileOrFreeSpace = FREE_SPACE;
} else {
for (int i = 0; i < item; i++) {
for (int i = 0; i < blockSize; i++) {
diskMap[diskMapPtr++] = EMPTY;
}
fileOrFreeSpace = FILE;
}
}

// Defragment
for (int i = 0; i < blockCount; i++) {
if (diskMap[^(i+1)] is not EMPTY) {
int ptr = diskMap.IndexOf(EMPTY);
if (ptr >= blockCount - i) {
break;
}
diskMap[ptr] = diskMap[^(i+1)];
diskMap[^(i+1)] = EMPTY;
}
}

long checkSum = 0;
for (int i = 0; i < blockCount; i++) {
if (diskMap[i] is EMPTY) {
break;
fileOrFreeSpace = FILE;
}
checkSum += diskMap[i] * i;
}


return checkSum;
return diskMap;
}

public static long Part2(string[] input)
private static List<Block> CreateDiskMapAsBlocks(this IEnumerable<int> diskMapAsInts)
{
string denseDiskMap = input[0];
List<int> diskMapAsInts = [.. denseDiskMap.AsDigits<int>()];
int blockCount = diskMapAsInts.Sum();
return [.. diskMapAsInts
.Chunk(2)
.SelectMany((sizes, index) =>
sizes.Length == 2
? (List<Block>)[new FileBlock(index, sizes[0]), new EmptyBlock(sizes[1])]
: (List<Block>)[new FileBlock(index, sizes[0])])
];
}

List<Block> diskMap = [];
private static List<int> CompactDisk(this List<int> map)
{
List<int> diskMap = [.. map];

bool fileOrFreeSpace = FILE;
int blockNo = 0;
int maxBlockNo = 0;
foreach (int item in diskMapAsInts) {
if (fileOrFreeSpace is FILE) {
maxBlockNo = blockNo;
diskMap.Add(new Block(blockNo++, item));
fileOrFreeSpace = FREE_SPACE;
} else {
diskMap.Add(new Block(EMPTY, item));
fileOrFreeSpace = FILE;
for (int ptr = diskMap.Count - 1; ptr > 0; ptr--) {
if (diskMap[ptr] is not EMPTY) {
int emptyPtr = diskMap.IndexOf(EMPTY);
if (emptyPtr >= ptr) {
break;
}
diskMap[emptyPtr] = diskMap[ptr];
diskMap[ptr] = EMPTY;
}
}

return diskMap;
}

// I don't like this code
private static List<Block> Defragment(this List<Block> map)
{
List<Block> diskMap = [.. map];

// Defragment
for (blockNo = maxBlockNo; blockNo > 0; blockNo--) {
int blockPtr = diskMap.FindIndex(b => b.Id == blockNo);
int maxBlockNo = diskMap[^1].Id;
for (int blockNo = maxBlockNo; blockNo > 0; blockNo--) {

int blockPtr = diskMap.FindIndex(block => block.Id == blockNo);
Block fileBlock = diskMap[blockPtr];
int firstFreeSpace = diskMap.FindIndex(b => b.Id == EMPTY && b.BlockSize >= fileBlock.BlockSize);
int firstFreeSpace = diskMap.FindIndex(block => block is EmptyBlock && block.BlockSize >= fileBlock.BlockSize);

if (blockPtr > firstFreeSpace && firstFreeSpace > 0) {
if (diskMap[blockPtr - 1].Id is EMPTY) {
diskMap[blockPtr - 1] = diskMap[blockPtr - 1] with { BlockSize = diskMap[blockPtr - 1].BlockSize + fileBlock.BlockSize };
int ptrToPreceding = blockPtr - 1;
if (diskMap[ptrToPreceding] is EmptyBlock) {
diskMap.RemoveAt(blockPtr);
diskMap[ptrToPreceding] = diskMap[ptrToPreceding] with { BlockSize = diskMap[ptrToPreceding].BlockSize + fileBlock.BlockSize };
// Combine contiguous empty spaces into 1 block
ptrToPreceding--;
if (diskMap[ptrToPreceding] is EmptyBlock) {
for (int i = ptrToPreceding; diskMap[i] is EmptyBlock; i--) {
diskMap[i] = diskMap[i] with { BlockSize = diskMap[i].BlockSize + diskMap[i + 1].BlockSize };
diskMap.RemoveAt(i + 1);
}
}
} else {
diskMap[blockPtr] = fileBlock with { Id = EMPTY };
diskMap[blockPtr] = new EmptyBlock(fileBlock.BlockSize);
}

Block freeSpaceBlock = diskMap[firstFreeSpace];
diskMap[firstFreeSpace] = freeSpaceBlock with { BlockSize = freeSpaceBlock.BlockSize - fileBlock.BlockSize };
diskMap.Insert(firstFreeSpace, fileBlock);
}
for (int i = diskMap.Count - 1; i > 0; i--) {
if (diskMap[i].Id is EMPTY && diskMap[i - 1].Id is EMPTY) {
diskMap[i - 1] = diskMap[i - 1] with { BlockSize = diskMap[i - 1].BlockSize + diskMap[i].BlockSize };
diskMap.RemoveAt(i);
}

}
}

_ = diskMap.RemoveAll(b => b.BlockSize is 0);
return diskMap;
}

private static long FileChecksum(this List<int> diskMap)
{
return diskMap
.TakeWhile(id => id is not EMPTY)
.Index()
.Sum(block => (long)block.Index * (long)block.Item);
}

private static long FileChecksum(this List<Block> diskMap)
{
long checkSum = 0;
int idx = 0;
for (int i = 0; i < diskMap.Count; i++) {
if (diskMap[i].Id is not EMPTY) {
for (int j = 0; j < diskMap[i].BlockSize; j++) {
checkSum += diskMap[i].Id * idx++;
}
if (diskMap[i] is FileBlock fileBlock) {
checkSum += Enumerable.Range(0, fileBlock.BlockSize).Sum(i => (long)fileBlock.Id * (long)idx++);
} else {
idx += diskMap[i].BlockSize;
}
}


return checkSum;
}

private sealed record Block(int Id, int BlockSize);
private abstract record Block(int Id, int BlockSize);
private record FileBlock(int Id, int BlockSize) : Block(Id, BlockSize);
private record EmptyBlock(int BlockSize) : Block(EMPTY, BlockSize);

private const bool FILE = true;
private const bool FILE = true;
private const bool FREE_SPACE = false;
private const int EMPTY = int.MinValue;
private const int NOT_FOUND = -1;
private const int EMPTY = int.MinValue;
}

0 comments on commit 7e152bf

Please sign in to comment.