diff --git a/src/09.cs b/src/09.cs new file mode 100644 index 0000000..19d74e1 --- /dev/null +++ b/src/09.cs @@ -0,0 +1,122 @@ +using System.Text; + +namespace aoc2024; + +internal class Day09 : Day +{ + private record struct FileData(int id, int blocks, int pos); + private readonly List files = []; + private string layout = string.Empty; + private readonly List gaps = []; + + internal override void Parse() + { + StringBuilder layoutBuilder = new(); + var text = Util.Parsing.ReadAllText($"{GetDay()}"); + for (int i = 0; i < text.Length; i += 2) + { + var fd = new FileData(i / 2, int.Parse(text[i].ToString()), layoutBuilder.Length); + files.Add(fd); + for (int j = 0; j < fd.blocks; j++) + { + // using % 10 so the length doesn't get screwed up. placeholder for verifying gap lengths. + layoutBuilder.Append(fd.id % 10); + } + + if (i + 1 == text.Length) + { + break; + } + + var gapLen = int.Parse(text[i + 1].ToString()); + gaps.Add(new FileData(layoutBuilder.Length, gapLen, layoutBuilder.Length)); + + for (int j = 0; j < gapLen; j++) + { + layoutBuilder.Append('.'); + } + } + + layout = layoutBuilder.ToString(); + } + + internal override string Part1() + { + long checksum = 0; + + int currFile = 0; + int currBlock = 0; + int repackFileIdx = files.Count - 1; + int repackFileBlock = 0; + int gapIdx = 0; + int gapPos = 0; + var packedLen = files.Sum(f => f.blocks); + for (int i = 0; i < packedLen; i++) + { + if (i >= gaps[gapIdx].id && i < (gaps[gapIdx].id + gaps[gapIdx].blocks) && gapIdx < gaps.Count && gaps[gapIdx].blocks > gapPos) + { + checksum += i * files[repackFileIdx].id; + repackFileBlock++; + if (repackFileBlock == files[repackFileIdx].blocks) + { + repackFileBlock = 0; + repackFileIdx--; + } + + gapPos++; + if (gapPos == gaps[gapIdx].blocks) + { + gapPos = 0; + gapIdx++; + while (gaps[gapIdx].blocks == 0) + { + gapIdx++; + } + } + } + else + { + checksum += i * files[currFile].id; + currBlock++; + if (currBlock == files[currFile].blocks) + { + currBlock = 0; + currFile++; + } + } + } + + return $"<+white>{checksum}"; + } + + internal override string Part2() + { + List packed = [..files]; + List newGaps = [..gaps]; + + int repackFileIdx = files.Count - 1; + for (int i = repackFileIdx; i >= 0; i--) + { + var firstRepackIdx = newGaps.FindIndex(g => g.pos < files[i].pos && g.blocks >= files[i].blocks); + if (firstRepackIdx >= 0) + { + packed[i] = packed[i] with {pos = newGaps[firstRepackIdx].pos}; + newGaps[firstRepackIdx] = new FileData(newGaps[firstRepackIdx].id + files[i].blocks, + newGaps[firstRepackIdx].blocks - files[i].blocks, newGaps[firstRepackIdx].pos + files[i].blocks); + } + } + + packed.Sort((a, b) => a.pos.CompareTo(b.pos)); + + long checksum = 0; + foreach (var file in packed) + { + for (int i = 0; i < file.blocks; i++) + { + checksum += (file.pos + i) * file.id; + } + } + + return $"<+white>{checksum}"; + } +}