Day 9 part 1 and partial part 2
parent
3ce503b8ce
commit
23e5f91fef
|
@ -0,0 +1,290 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection.Emit;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
|
||||
namespace Advent24
|
||||
{
|
||||
internal class Day9
|
||||
{
|
||||
public Day9()
|
||||
{
|
||||
String fileData = System.IO.File.ReadAllText(@"..\..\..\inputd9.txt");
|
||||
|
||||
Int128 checksumWholeFile = 0;
|
||||
|
||||
Int64 checksum = 0;
|
||||
|
||||
Int32 leftDigitInt;
|
||||
Int32 rightDigitInt;
|
||||
|
||||
Int64 i = 0; // left-most iterator in expanded sequence
|
||||
|
||||
Int32 leftFileID = 0;
|
||||
|
||||
// 1 will be subtracted on first iteration, to make this (fileData.Length-1)/2
|
||||
Int32 rightFileID = (fileData.Length+1)/2;
|
||||
|
||||
// j = right-most position in compressed sequence; 1 will be subtracted on first iteration, to make this fileData.Length-1
|
||||
Int32 j = fileData.Length;
|
||||
|
||||
Int32 leftBlockLength;
|
||||
Int32 rightBlockLength = 0;
|
||||
|
||||
Boolean leftIsFileBlock = true;
|
||||
|
||||
Boolean rightIsFileBlock = (fileData.Length % 2) == 1;
|
||||
|
||||
|
||||
foreach(Char digitChar in fileData)
|
||||
{
|
||||
// The .toString() is needed to convert '2' to "2" to get 2 from .ToInt32(), otherwise we get the
|
||||
// ASCII value of '2' (when we just wanted the number 2) when converting a Char ('2') to Int32.
|
||||
leftDigitInt = System.Convert.ToInt32(digitChar.ToString());
|
||||
|
||||
if (leftIsFileBlock)
|
||||
{
|
||||
leftBlockLength = leftDigitInt;
|
||||
|
||||
// part of the same file block was handled from the right end,
|
||||
// so only the remaining length of that block is to be handled by
|
||||
// from the left end
|
||||
if (leftFileID == rightFileID)
|
||||
{
|
||||
leftBlockLength = rightBlockLength;
|
||||
}
|
||||
|
||||
// fileID * Sum(A_n from i to i+n-1)
|
||||
checksum += leftFileID * (leftBlockLength * (2*i + leftBlockLength - 1) / 2);
|
||||
|
||||
//for (int l = 0; l < leftBlockLength; l++)
|
||||
// Console.Write("{0:d},", leftFileID);
|
||||
|
||||
i += leftBlockLength;
|
||||
leftFileID += 1;
|
||||
|
||||
// immediately after handling the leftFileID == rightFileID case, we should exit the
|
||||
// loop after having incremented leftFileID above, because it has already been fully
|
||||
// handled from the right end - and thus has already been incorporated in the checksum.
|
||||
if (leftFileID > rightFileID)
|
||||
{
|
||||
// to remove trailing comma
|
||||
//Console.Write("\b ");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// left is free block
|
||||
|
||||
leftBlockLength = leftDigitInt;
|
||||
|
||||
if (rightBlockLength < 0)
|
||||
throw new ApplicationException(nameof(rightBlockLength)+" must be >= 0 but was "+rightBlockLength.ToString());
|
||||
|
||||
if (rightBlockLength == 0)
|
||||
{
|
||||
j -= 1;
|
||||
rightIsFileBlock = !rightIsFileBlock;
|
||||
rightDigitInt = System.Convert.ToInt32(fileData[j].ToString());
|
||||
|
||||
rightFileID -= 1;
|
||||
|
||||
rightBlockLength = rightDigitInt;
|
||||
}
|
||||
|
||||
//Console.Write("\b[");
|
||||
|
||||
while (leftBlockLength >= rightBlockLength)
|
||||
{
|
||||
checksum += rightFileID * (rightBlockLength * (2 * i + rightBlockLength - 1) / 2);
|
||||
i += rightBlockLength;
|
||||
|
||||
//for (int l = 0; l < rightBlockLength; l++)
|
||||
// Console.Write("{0:d},", rightFileID);
|
||||
|
||||
leftBlockLength -= rightBlockLength;
|
||||
|
||||
// right-ended free block
|
||||
j -= 1;
|
||||
rightIsFileBlock = !rightIsFileBlock;
|
||||
rightDigitInt = System.Convert.ToInt32(fileData[j].ToString());
|
||||
|
||||
// moving leftward from the right-ended free block, so handling a file block
|
||||
j -= 1;
|
||||
rightIsFileBlock = !rightIsFileBlock;
|
||||
rightDigitInt = System.Convert.ToInt32(fileData[j].ToString());
|
||||
|
||||
rightFileID -= 1;
|
||||
|
||||
// if there are more empty spaces left (leftBlockLength) in the free block handled
|
||||
// from the left side but no more right handled file blocks to move there (if
|
||||
// rightFileID > leftFileID), we've reached the end of the checksum calculation and
|
||||
// should exit the loop without adding anything further to the checksum
|
||||
if (leftFileID > rightFileID)
|
||||
break;
|
||||
|
||||
rightBlockLength = rightDigitInt;
|
||||
}
|
||||
|
||||
// if we broke from the inner 'for' loop above because leftFileID > rightFileID, we should break
|
||||
// out of the outer 'foreach' loop too, for the same reason
|
||||
if (leftFileID > rightFileID)
|
||||
{
|
||||
//Console.Write("\b]");
|
||||
break;
|
||||
}
|
||||
|
||||
if (leftBlockLength > 0)
|
||||
{
|
||||
// Also, leftBlockLength < rightBlockLength after the above while() loop
|
||||
checksum += rightFileID * (leftBlockLength * (2 * i + leftBlockLength - 1) / 2);
|
||||
i += leftBlockLength;
|
||||
|
||||
//for (int l = 0; l < leftBlockLength; l++)
|
||||
// Console.Write("{0:d},", rightFileID);
|
||||
|
||||
rightBlockLength -= leftBlockLength;
|
||||
}
|
||||
else
|
||||
//Console.Write(","); // to prevent opening [ from being eaten by the \b on the next line
|
||||
//Console.Write("\b]");
|
||||
;
|
||||
}
|
||||
leftIsFileBlock = !leftIsFileBlock;
|
||||
}
|
||||
//Console.WriteLine();
|
||||
Console.WriteLine("checksum = {0:d}", checksum);
|
||||
|
||||
// part 2
|
||||
{
|
||||
// Linked list of tuples of (fileID, fileLength) tuples, with fileID = -1 for free lengths
|
||||
LinkedList<(Int32, Int32)> expandedDisk = new();
|
||||
|
||||
Int32 digitInt;
|
||||
Int32 previousFileID = -2;
|
||||
Int32 fileID = 0;
|
||||
Int32 fileLength = 0;
|
||||
|
||||
Boolean isFileBlock = true;
|
||||
|
||||
// create expanded disk from disk map
|
||||
foreach(Char digitChar in fileData)
|
||||
{
|
||||
digitInt = System.Convert.ToInt32(digitChar.ToString());
|
||||
|
||||
if (isFileBlock)
|
||||
{
|
||||
expandedDisk.AddLast((fileID, digitInt));
|
||||
|
||||
for (Int32 ii = 0; ii < digitInt; ii++)
|
||||
Console.Write("{0:d},", fileID);
|
||||
fileID++;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (Int32 ii = 0; ii < digitInt; ii++)
|
||||
Console.Write('.');
|
||||
|
||||
expandedDisk.AddLast((-1, digitInt));
|
||||
}
|
||||
isFileBlock = !isFileBlock;
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
|
||||
for (LinkedListNode<(Int32, Int32)>? node = expandedDisk.Last; node != null; node = node.Previous)
|
||||
{
|
||||
fileLength = node.Value.Item2;
|
||||
fileID = node.Value.Item1;
|
||||
|
||||
if (fileID == -1) // node is not free space
|
||||
continue;
|
||||
|
||||
// previousFileId is no longer the negative sentinel value
|
||||
// and we've finished progressing down the fileIDs in descending order
|
||||
// and have hit up against a previously moved fileID
|
||||
if (previousFileID >= 0 && previousFileID < fileID)
|
||||
{
|
||||
//Console.WriteLine("previousFileID = {0:d}, fileID = {1:d}", previousFileID, fileID);
|
||||
previousFileID = fileID;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (LinkedListNode<(Int32, Int32)>? innerNode = expandedDisk.First; innerNode != node && innerNode != null; innerNode = innerNode.Next)
|
||||
{
|
||||
Int32 freeID = innerNode.Value.Item1;
|
||||
Int32 freeLength = innerNode.Value.Item2;
|
||||
|
||||
//for (Int32 ii = 0; ii < freeLength; ii++)
|
||||
// if (freeID == -1)
|
||||
// Console.Write('.');
|
||||
// else
|
||||
// Console.Write("{0:d},", freeID);
|
||||
|
||||
if (freeID != -1) // node is not free space
|
||||
continue;
|
||||
|
||||
if (fileLength <= freeLength)
|
||||
{
|
||||
// moving file to formerly free space
|
||||
expandedDisk.AddBefore(innerNode, (fileID, fileLength));
|
||||
// changing original node to free space
|
||||
node.ValueRef = (-1, fileLength);
|
||||
// reducing or deleting free space
|
||||
if (freeLength - fileLength == 0)
|
||||
expandedDisk.Remove(innerNode);
|
||||
else
|
||||
innerNode.ValueRef = (-1, freeLength - fileLength); // fileID of free space is -1
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Console.WriteLine();
|
||||
|
||||
previousFileID = fileID;
|
||||
}
|
||||
|
||||
//Console.WriteLine();
|
||||
|
||||
Int32 blockPosition = 0;
|
||||
|
||||
foreach(var fileBlockTuple in expandedDisk)
|
||||
{
|
||||
fileID = fileBlockTuple.Item1;
|
||||
fileLength = fileBlockTuple.Item2;
|
||||
|
||||
// skip free blocks
|
||||
if (fileID == -1)
|
||||
{
|
||||
for (Int32 ii = 0; ii < fileLength; ii++)
|
||||
Console.Write('.');
|
||||
blockPosition += fileLength;
|
||||
continue;
|
||||
}
|
||||
|
||||
checksumWholeFile += fileID * (fileLength * (2 * blockPosition + fileLength - 1) / 2);
|
||||
//Console.WriteLine("\n(intermediate) fileID = {0:d}, blockPosition = {1:d}, fileLength = {2:d}",
|
||||
// fileID, blockPosition, fileLength);
|
||||
//Console.WriteLine("(intermediate) checksumWholeFile = {0:d}", checksumWholeFile);
|
||||
|
||||
for (Int32 ii = 0; ii < fileLength; ii++)
|
||||
Console.Write("{0:d},", fileID);
|
||||
|
||||
blockPosition += fileLength;
|
||||
}
|
||||
}
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("checksumWholeFile = {0:d}", checksumWholeFile);
|
||||
|
||||
// to keep the console window from closing
|
||||
Console.ReadKey();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,7 +14,8 @@ namespace Advent24
|
|||
//_ = new Day5();
|
||||
//_ = new Day6();
|
||||
//_ = new Day7();
|
||||
_ = new Day8();
|
||||
//_ = new Day8();
|
||||
_ = new Day9();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
|||
2333133121414131402
|
Loading…
Reference in New Issue