feat: part 9 solve part 1
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
namespace DiskFragmenter.Tests;
|
||||
|
||||
public class DiskMapTests
|
||||
{
|
||||
private const string TestInput = "12345";
|
||||
private const string ExampleInput = "2333133121414131402";
|
||||
|
||||
[Test]
|
||||
public async Task FromDenseFormat_WhenCalled_ItShouldReturnDiskMap()
|
||||
{
|
||||
var map = DiskMap.FromDenseFormat(TestInput);
|
||||
|
||||
await Assert.That(map).IsTypeOf<DiskMap>();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task CompactDisk_WhenCalled_ItShouldReturnNewDiskCompacted()
|
||||
{
|
||||
var map = DiskMap.FromDenseFormat(TestInput);
|
||||
var compactedMap = map.CompactDisk();
|
||||
|
||||
await Assert.That(compactedMap).IsNotEqualTo(map);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task CompactDiskWithoutFragmentation_WhenCalledWithTestInput_ItShouldReturnNewDiskCompacted()
|
||||
{
|
||||
var map = DiskMap.FromDenseFormat(TestInput);
|
||||
var compactedMap = map.CompactDiskWithoutFragmentation();
|
||||
|
||||
await Assert.That(compactedMap).IsNotEqualTo(map);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task CompactDiskWithoutFragmentation_WhenCalledWithExampleInput_ItShouldReturnNewDiskCompacted()
|
||||
{
|
||||
var map = DiskMap.FromDenseFormat(ExampleInput);
|
||||
var compactedMap = map.CompactDiskWithoutFragmentation();
|
||||
|
||||
await Assert.That(compactedMap).IsNotEqualTo(map);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task CalculateCheckSum_WhenCalledWhenCalledWithTestInput_ItShouldReturnExpectedValue()
|
||||
{
|
||||
var result = DiskMap.FromDenseFormat(TestInput)
|
||||
.CompactDisk()
|
||||
.CalculateCheckSum();
|
||||
|
||||
await Assert.That(result).IsEqualTo(60);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task CalculateCheckSum_WhenCalledWithExampleInput_ItShouldReturnExpectedValue()
|
||||
{
|
||||
var result = DiskMap.FromDenseFormat(ExampleInput)
|
||||
.CompactDisk()
|
||||
.CalculateCheckSum();
|
||||
|
||||
await Assert.That(result).IsEqualTo(1928);
|
||||
}
|
||||
}
|
||||
@@ -13,12 +13,167 @@ if (File.Exists(args[0]) is false)
|
||||
}
|
||||
|
||||
var isPart2 = args.Length is 2 && args[1] is "part2";
|
||||
var input = await File.ReadAllLinesAsync(args[0]);
|
||||
var input = await File.ReadAllTextAsync(args[0]);
|
||||
|
||||
var stopwatch = new Stopwatch();
|
||||
stopwatch.Start();
|
||||
|
||||
// TODO: Implement solution
|
||||
var result = DiskMap.FromDenseFormat(input).CompactDisk().CalculateCheckSum();
|
||||
|
||||
stopwatch.Stop();
|
||||
Console.WriteLine($". ({stopwatch.ElapsedMilliseconds}ms)");
|
||||
Console.WriteLine($"The checksum of the compacted disk is {result}. ({stopwatch.ElapsedMilliseconds}ms)");
|
||||
|
||||
class DiskMap
|
||||
{
|
||||
private readonly IReadOnlyList<int> _expandedFormat;
|
||||
|
||||
private DiskMap(string denseFormat)
|
||||
{
|
||||
_expandedFormat = GetExpandedFormat(denseFormat);
|
||||
}
|
||||
|
||||
private DiskMap(List<int> expandedFormat)
|
||||
{
|
||||
_expandedFormat = expandedFormat;
|
||||
}
|
||||
|
||||
public long CalculateCheckSum()
|
||||
{
|
||||
long total = 0;
|
||||
|
||||
foreach (var (fileId, index) in _expandedFormat.Select((block, index) => (block, index)))
|
||||
{
|
||||
if (fileId is -1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
total += fileId * index;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
var possiblePlacement = compactedFormat[possiblePlacementIndex];
|
||||
var blockToBePlaced = compactedFormat[blockToBeMovedIndex];
|
||||
|
||||
if (possiblePlacement is not -1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (blockToBePlaced is -1)
|
||||
{
|
||||
possiblePlacementIndex--;
|
||||
blockToBeMovedIndex--;
|
||||
continue;
|
||||
}
|
||||
|
||||
compactedFormat[possiblePlacementIndex] = blockToBePlaced;
|
||||
compactedFormat[blockToBeMovedIndex] = -1;
|
||||
blockToBeMovedIndex--;
|
||||
}
|
||||
|
||||
return new(compactedFormat);
|
||||
}
|
||||
|
||||
public DiskMap CompactDiskWithoutFragmentation()
|
||||
{
|
||||
var compactedFormat = _expandedFormat.ToList();
|
||||
|
||||
var fileBlockStartIndex = compactedFormat.FindLastIndex(i => i is not -1);
|
||||
var fileBlockEndIndex = fileBlockStartIndex;
|
||||
|
||||
var freeBlockStartIndex = compactedFormat.IndexOf(-1);
|
||||
var freeBlockEndIndex = freeBlockStartIndex;
|
||||
|
||||
while (fileBlockEndIndex > -1)
|
||||
{
|
||||
while (compactedFormat[fileBlockEndIndex] == compactedFormat[fileBlockStartIndex])
|
||||
{
|
||||
fileBlockEndIndex--;
|
||||
|
||||
if (fileBlockEndIndex is -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (freeBlockEndIndex < compactedFormat.Count - 1 && freeBlockEndIndex is not -1)
|
||||
{
|
||||
while (compactedFormat[freeBlockStartIndex] == compactedFormat[freeBlockEndIndex])
|
||||
{
|
||||
freeBlockEndIndex++;
|
||||
}
|
||||
|
||||
var fileBlockLength = fileBlockStartIndex - fileBlockEndIndex;
|
||||
var freeBlockLength = freeBlockEndIndex - freeBlockStartIndex;
|
||||
|
||||
if (freeBlockLength < fileBlockLength || freeBlockStartIndex > file)
|
||||
{
|
||||
freeBlockStartIndex = compactedFormat.IndexOf(-1, freeBlockEndIndex);
|
||||
freeBlockEndIndex = freeBlockStartIndex;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = freeBlockStartIndex; i < freeBlockEndIndex; i++)
|
||||
{
|
||||
for (int j = fileBlockStartIndex; j < fileBlockEndIndex; j++)
|
||||
{
|
||||
var fileIdToMove = compactedFormat[j];
|
||||
compactedFormat[i] = fileIdToMove;
|
||||
compactedFormat[j] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fileBlockStartIndex = compactedFormat.FindLastIndex(fileBlockEndIndex, i => i is not -1);
|
||||
fileBlockEndIndex = fileBlockStartIndex;
|
||||
|
||||
freeBlockStartIndex = compactedFormat.IndexOf(-1);
|
||||
freeBlockEndIndex = freeBlockStartIndex;
|
||||
}
|
||||
|
||||
|
||||
return new(compactedFormat);
|
||||
}
|
||||
|
||||
public static DiskMap FromDenseFormat(string denseFormat) => new(denseFormat);
|
||||
|
||||
private static List<int> GetExpandedFormat(string denseFormat)
|
||||
{
|
||||
var expandedFormat = new List<int>();
|
||||
var fileId = 0;
|
||||
|
||||
for (var characterIndex = 0; characterIndex < denseFormat.Length; characterIndex += 2)
|
||||
{
|
||||
var fileLength = int.Parse(denseFormat[characterIndex].ToString());
|
||||
expandedFormat.AddRange(Enumerable.Repeat(fileId, fileLength));
|
||||
|
||||
var freeSpaceIndex = characterIndex + 1;
|
||||
|
||||
if (freeSpaceIndex < denseFormat.Length)
|
||||
{
|
||||
var freeSpaceLength = int.Parse(denseFormat[characterIndex + 1].ToString());
|
||||
expandedFormat.AddRange(Enumerable.Repeat(-1, freeSpaceLength));
|
||||
}
|
||||
|
||||
fileId++;
|
||||
}
|
||||
|
||||
return expandedFormat;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user