feat: solved day 9 part 2
This commit is contained in:
@@ -4,6 +4,11 @@ public class DiskMapTests
|
||||
{
|
||||
private const string TestInput = "12345";
|
||||
private const string ExampleInput = "2333133121414131402";
|
||||
|
||||
private async Task<string> GetPuzzleInput()
|
||||
{
|
||||
return await File.ReadAllTextAsync(Path.Combine(AppContext.BaseDirectory, "INPUT.txt"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task FromDenseFormat_WhenCalled_ItShouldReturnDiskMap()
|
||||
@@ -59,4 +64,48 @@ public class DiskMapTests
|
||||
|
||||
await Assert.That(result).IsEqualTo(1928);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task CalculateCheckSum_WhenCalledWithPuzzleInput_ItShouldReturnExpectedValue()
|
||||
{
|
||||
var input = await GetPuzzleInput();
|
||||
|
||||
var result = DiskMap.FromDenseFormat(input)
|
||||
.CompactDisk()
|
||||
.CalculateCheckSum();
|
||||
|
||||
await Assert.That(result).IsEqualTo(6200294120911);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task CalculateCheckSum_WhenCalledWhenCalledWithTestInputAndNoFragmentation_ItShouldReturnExpectedValue()
|
||||
{
|
||||
var result = DiskMap.FromDenseFormat(TestInput)
|
||||
.CompactDiskWithoutFragmentation()
|
||||
.CalculateCheckSum();
|
||||
|
||||
await Assert.That(result).IsEqualTo(132);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task CalculateCheckSum_WhenCalledWithExampleInputAndNoFragmentation_ItShouldReturnExpectedValue()
|
||||
{
|
||||
var result = DiskMap.FromDenseFormat(ExampleInput)
|
||||
.CompactDiskWithoutFragmentation()
|
||||
.CalculateCheckSum();
|
||||
|
||||
await Assert.That(result).IsEqualTo(2858);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task CalculateCheckSum_WhenCalledWithPuzzleInputAndNoFragmentation_ItShouldReturnExpectedValue()
|
||||
{
|
||||
var input = await GetPuzzleInput();
|
||||
|
||||
var result = DiskMap.FromDenseFormat(input)
|
||||
.CompactDiskWithoutFragmentation()
|
||||
.CalculateCheckSum();
|
||||
|
||||
await Assert.That(result).IsEqualTo(6227018762750);
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,12 @@ var input = await File.ReadAllTextAsync(args[0]);
|
||||
var stopwatch = new Stopwatch();
|
||||
stopwatch.Start();
|
||||
|
||||
var result = DiskMap.FromDenseFormat(input).CompactDisk().CalculateCheckSum();
|
||||
var map = DiskMap.FromDenseFormat(input);
|
||||
var compactedMap = isPart2
|
||||
? map.CompactDiskWithoutFragmentation()
|
||||
: map.CompactDisk();
|
||||
|
||||
var result = compactedMap.CalculateCheckSum();
|
||||
|
||||
stopwatch.Stop();
|
||||
Console.WriteLine($"The checksum of the compacted disk is {result}. ({stopwatch.ElapsedMilliseconds}ms)");
|
||||
@@ -54,12 +59,19 @@ class DiskMap
|
||||
return total;
|
||||
}
|
||||
|
||||
// TODO: Can this be solved without less index manipulation?
|
||||
// Can I create a data structure that suits both ways
|
||||
// of doing disk compaction and allows for easily calculating
|
||||
// the checksum
|
||||
// maybe something like [block]
|
||||
// block needs to represent a block of free space
|
||||
// and a block of file ids
|
||||
// each will consist indexes, value
|
||||
public DiskMap CompactDisk()
|
||||
{
|
||||
var compactedFormat = _expandedFormat.ToList();
|
||||
var blockToBeMovedIndex = compactedFormat.Count - 1;
|
||||
|
||||
// TODO: I think this might be easier to deal with in a while loop.
|
||||
for (var possiblePlacementIndex = 0; possiblePlacementIndex < compactedFormat.Count; possiblePlacementIndex++)
|
||||
{
|
||||
if (blockToBeMovedIndex < possiblePlacementIndex)
|
||||
@@ -93,15 +105,19 @@ class DiskMap
|
||||
public DiskMap CompactDiskWithoutFragmentation()
|
||||
{
|
||||
var compactedFormat = _expandedFormat.ToList();
|
||||
|
||||
|
||||
// initialize file block pointers
|
||||
var fileBlockStartIndex = compactedFormat.FindLastIndex(i => i is not -1);
|
||||
var fileBlockEndIndex = fileBlockStartIndex;
|
||||
|
||||
// initialize free block points
|
||||
var freeBlockStartIndex = compactedFormat.IndexOf(-1);
|
||||
var freeBlockEndIndex = freeBlockStartIndex;
|
||||
|
||||
|
||||
// loop over all possible file blocks
|
||||
while (fileBlockEndIndex > -1)
|
||||
{
|
||||
// loop to end of current file block
|
||||
while (compactedFormat[fileBlockEndIndex] == compactedFormat[fileBlockStartIndex])
|
||||
{
|
||||
fileBlockEndIndex--;
|
||||
@@ -112,42 +128,71 @@ class DiskMap
|
||||
}
|
||||
}
|
||||
|
||||
while (freeBlockEndIndex < compactedFormat.Count - 1 && freeBlockEndIndex is not -1)
|
||||
// loop over all free blocks that are to the left of the
|
||||
// current file block
|
||||
while (
|
||||
freeBlockEndIndex < compactedFormat.Count - 1 &&
|
||||
freeBlockEndIndex is not -1 &&
|
||||
freeBlockEndIndex < fileBlockEndIndex
|
||||
)
|
||||
{
|
||||
// find end of current free block
|
||||
while (compactedFormat[freeBlockStartIndex] == compactedFormat[freeBlockEndIndex])
|
||||
{
|
||||
freeBlockEndIndex++;
|
||||
}
|
||||
|
||||
// determine if free block can hold file block
|
||||
var fileBlockLength = fileBlockStartIndex - fileBlockEndIndex;
|
||||
var freeBlockLength = freeBlockEndIndex - freeBlockStartIndex;
|
||||
|
||||
if (freeBlockLength < fileBlockLength || freeBlockStartIndex > file)
|
||||
if (freeBlockLength < fileBlockLength)
|
||||
{
|
||||
// if current free block cannot hold file block
|
||||
// advance to next free block
|
||||
freeBlockStartIndex = compactedFormat.IndexOf(-1, freeBlockEndIndex);
|
||||
freeBlockEndIndex = freeBlockStartIndex;
|
||||
continue;
|
||||
}
|
||||
|
||||
// if current free block can hold file block
|
||||
// loop over the free block positions and place
|
||||
// the file block's id in them, but only replace
|
||||
// as many free blocks as there are file blocks
|
||||
var blockLengthDelta = freeBlockLength - fileBlockLength;
|
||||
|
||||
for (int i = freeBlockStartIndex; i < freeBlockEndIndex; i++)
|
||||
for (var i = freeBlockStartIndex; i < freeBlockEndIndex - blockLengthDelta; i++)
|
||||
{
|
||||
for (int j = fileBlockStartIndex; j < fileBlockEndIndex; j++)
|
||||
{
|
||||
var fileIdToMove = compactedFormat[j];
|
||||
compactedFormat[i] = fileIdToMove;
|
||||
compactedFormat[j] = -1;
|
||||
}
|
||||
compactedFormat[i] = compactedFormat[fileBlockStartIndex];
|
||||
}
|
||||
|
||||
// loop over original file block positions
|
||||
// and free them up.
|
||||
for (var j = fileBlockStartIndex; j > fileBlockEndIndex; j--)
|
||||
{
|
||||
compactedFormat[j] = -1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// if we have reached the end of all
|
||||
// possible file blocks then no
|
||||
// need to go to next file block
|
||||
if (fileBlockEndIndex is -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// move to next file block
|
||||
fileBlockStartIndex = compactedFormat.FindLastIndex(fileBlockEndIndex, i => i is not -1);
|
||||
fileBlockEndIndex = fileBlockStartIndex;
|
||||
|
||||
// reset free block to beginning free block
|
||||
freeBlockStartIndex = compactedFormat.IndexOf(-1);
|
||||
freeBlockEndIndex = freeBlockStartIndex;
|
||||
}
|
||||
|
||||
|
||||
return new(compactedFormat);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,3 +52,4 @@ dotnet build
|
||||
| 06 | [Problem](./06/PROBLEM.md) | [Solution](./06/GuardGallivant/) | I kind of brute forced part two... |
|
||||
| 07 | [Problem](./07/PROBLEM.md) | [Solution](./07/BridgeRepair/) | Not perfect or pretty, but good enough |
|
||||
| 08 | [Problem](./08/PROBLEM.md) | [Solution](./08/ResonantCollinearity/) | Without some help from chat I don't know where I'd be...to be fair the description kind of mislead me. |
|
||||
| 09 | [Problem](./09/PROBLEM.md) | [Solution](./09/DiskFragmenter/) | Doing things with indexes is error prone. |
|
||||
|
||||
Reference in New Issue
Block a user