From 411898e9f45faa7d634169392a5375f78967083c Mon Sep 17 00:00:00 2001 From: Parnic Date: Sun, 3 Dec 2023 14:28:45 -0600 Subject: [PATCH] Much better day 3 solution This moves all the actual handling to the parse function (so that part 2 can run on its own instead of requiring part 1 to fill its data structure for it). Now each part is just operating on the segment of the parsed data that is appropriate to it, and we can much more efficiently handle gears as we come across numbers instead of trying to search for numbers after finding a gear. --- src/03.cs | 91 +++++++++++++------------------------------------------ 1 file changed, 21 insertions(+), 70 deletions(-) diff --git a/src/03.cs b/src/03.cs index a280a07..d9d13ec 100644 --- a/src/03.cs +++ b/src/03.cs @@ -5,6 +5,8 @@ namespace aoc2023; internal class Day03 : Day { private char[,]? grid; + private readonly List partNums = new(); + private readonly Dictionary> gears = new(); internal override void Parse() { @@ -17,11 +19,6 @@ internal class Day03 : Day grid[row, col] = lines[row][col]; } } - } - - internal override string Part1() - { - long sum = 0; string currNumStr = ""; for (int row = 0; row < grid!.GetLength(0); row++) @@ -55,87 +52,41 @@ internal class Day03 : Day continue; } + if (grid[n.y, n.x] == '*') + { + if (!gears.ContainsKey(n)) + { + gears.Add(n, new List()); + } + + gears[n].Add(currNum); + } + valid = true; - break; } } if (valid) { - sum += currNum; + partNums.Add(currNum); } currNumStr = string.Empty; } } + } - return $"Sum of part numbers: <+white>{sum}"; + internal override string Part1() + { + long total = partNums.Sum(); + + return $"Sum of part numbers: <+white>{total}"; } internal override string Part2() { - // a much better way to do this would be to use the number-parsing in part 1 to store which star a given number is touching, - // then find all numbers that touch the same star more than once. - // this solution is...not great. - long total = 0; - for (int row = 0; row < grid!.GetLength(0); row++) - { - for (int col = 0; col < grid!.GetLength(1); col++) - { - if (grid[row, col] != '*') - { - continue; - } - - long lastRow = -1; - long lastCol = -1; - ivec2 pt = new(col, row); - List nums = new(); - foreach (var n in pt.GetNeighbors()) - { - if (!grid[n.y, n.x].IsDigit()) - { - continue; - } - - if (lastRow == -1 || lastCol == -1 || lastRow != n.y || System.Math.Abs(lastCol - n.x) > 1) - { - var x = n.x; - while (x >= 0 && grid[n.y, x].IsDigit()) - { - x--; - } - - if (x < 0 || !grid[n.y, x].IsDigit()) - { - x++; - } - - var numStr = string.Empty; - while (x < grid.GetLength(1) && grid[n.y, x].IsDigit()) - { - numStr += grid[n.y, x]; - x++; - } - - var num = int.Parse(numStr); - // this isn't quite right...it's possible the same number exists 2+ times around a star, but this works with my input, so... - nums.AddUnique(num); - } - - lastRow = n.y; - lastCol = n.x; - } - - if (nums.Count < 2) - { - continue; - } - - long mult = nums.Aggregate(1L, (current, num) => current * num); - total += mult; - } - } + long total = gears.Where(gear => gear.Value.Count == 2) + .Sum(gear => gear.Value.Aggregate(1L, (current, num) => current * num)); return $"Sum of gear ratios: <+white>{total}"; }