feat(2023-03): Finish day 3

This commit is contained in:
Josh Creek
2023-12-04 17:39:37 +00:00
parent c5b096dbea
commit f068ba8b7b
+159 -68
View File
@@ -1,23 +1,23 @@
using System.Reflection; namespace AOC.Tests.Y2023;
namespace AOC.Tests.Y2023 [TestFixture]
[Parallelizable(ParallelScope.All)]
public class Day03
{ {
[TestFixture, Parallelizable(ParallelScope.All)]
public class Day03
{
protected string GetThisClassName() { return this.GetType().Name; }
private string[] realData;
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
realData = File.ReadAllLines(Path.Combine(TestContext.CurrentContext.TestDirectory, "Y2023", "Data", $"{GetThisClassName()}.dat")); realData = File.ReadAllLines(Path.Combine(TestContext.CurrentContext.TestDirectory, "Y2023", "Data",
$"{GetThisClassName()}.dat"));
} }
protected string GetThisClassName() { return GetType().Name; }
private string[] realData;
private bool CheckSurroundingCellsForSymbols(char[,] grid, List<(int, int)> coords, bool isTesting = false) private bool CheckSurroundingCellsForSymbols(char[,] grid, List<(int, int)> coords, bool isTesting = false)
{ {
char[,] grid2 = new char[grid.GetLength(0), grid.GetLength(1)]; char[,] grid2 = new char[grid.GetLength(0), grid.GetLength(1)];
foreach (var coord in coords) foreach ((int, int) coord in coords)
{ {
int x = coord.Item1; int x = coord.Item1;
int y = coord.Item2; int y = coord.Item2;
@@ -63,9 +63,11 @@ namespace AOC.Tests.Y2023
{ {
line += grid2[i, j] != '\u0000' ? grid2[i, j] : '.'; line += grid2[i, j] != '\u0000' ? grid2[i, j] : '.';
} }
Console.WriteLine(line); Console.WriteLine(line);
} }
} }
return false; return false;
} }
@@ -91,7 +93,7 @@ namespace AOC.Tests.Y2023
// Iterate over each cell in the grid. // Iterate over each cell in the grid.
for (int i = 0; i < rows; i++) for (int i = 0; i < rows; i++)
{ {
Console.WriteLine($"Line {i+1}"); Console.WriteLine($"Line {i + 1}");
for (int j = 0; j < cols; j++) for (int j = 0; j < cols; j++)
{ {
List<(int, int)> numberCoords = new(); List<(int, int)> numberCoords = new();
@@ -123,7 +125,7 @@ namespace AOC.Tests.Y2023
// Check the eight surrounding cells of each digit in the number. // Check the eight surrounding cells of each digit in the number.
if (numberCoords.Count > 0) if (numberCoords.Count > 0)
{ {
bool isValidPartNumber = CheckSurroundingCellsForSymbols(grid, numberCoords, false); bool isValidPartNumber = CheckSurroundingCellsForSymbols(grid, numberCoords);
// If any of the surrounding cells contain a symbol, add the number to a list. // If any of the surrounding cells contain a symbol, add the number to a list.
if (isValidPartNumber) if (isValidPartNumber)
{ {
@@ -140,15 +142,89 @@ namespace AOC.Tests.Y2023
return numbers; return numbers;
} }
public bool CheckSurroundingCellsForNumbers(char[,] grid, List<(int, int)> coords, bool isTesting = false) private int CountNumbers(List<(int, int)> numberCoords)
{ {
foreach (var gearCoord in coords) // Group coordinates by the X-axis and sort each group by the Y-axis
IEnumerable<IOrderedEnumerable<(int, int)>> groupedCoords = numberCoords.GroupBy(coord => coord.Item1)
.Select(group => group.OrderBy(coord => coord.Item2));
int numberCount = 0;
foreach (IOrderedEnumerable<(int, int)> group in groupedCoords)
{
int lastY = int.MinValue;
foreach ((int, int) coord in group)
{
// If there is a gap in the Y-axis, increment the number count
if (coord.Item2 - lastY > 1)
{
numberCount++;
}
lastY = coord.Item2;
}
}
return numberCount;
}
private List<int> ExtractNumbers(List<(int, int)> numberCoords, char[,] grid)
{
// Initialize a list to hold the extracted numbers
List<int> numbers = new();
// Sort the coordinates by Y-axis (Item2) then by X-axis (Item1)
List<(int, int)> sortedCoords =
numberCoords.OrderBy(coord => coord.Item2).ThenBy(coord => coord.Item1).ToList();
// Create a HashSet to keep track of processed coordinates
HashSet<(int, int)> processedCoords = new();
foreach ((int x, int y) in sortedCoords)
{
// Skip this coordinate if it has already been processed
if (processedCoords.Contains((x, y)))
{
continue;
}
// Start from the current coordinate and scan to the left until a non-digit is found or it reaches the beginning of the row
int startX = x;
while (startX > 0 && char.IsDigit(grid[startX - 1, y]))
{
startX--;
}
// Build the number by scanning to the right from the startX position
string currentNumberStr = "";
int currentX = startX;
while (currentX < grid.GetLength(0) && char.IsDigit(grid[currentX, y]))
{
currentNumberStr += grid[currentX, y];
// Mark the coordinate as processed
processedCoords.Add((currentX, y));
currentX++;
}
// If a number is formed, add it to the list
if (currentNumberStr.Length > 0)
{
numbers.Add(int.Parse(currentNumberStr));
}
}
// Return the list of extracted numbers
return numbers;
}
private int GetGearRatioFromExactlyTwoNumbersInSurroundingCells(char[,] grid, (int, int) gearCoord)
{ {
List<(int, int)> numberCoords = new(); List<(int, int)> numberCoords = new();
int x = gearCoord.Item1; int x = gearCoord.Item1;
int y = gearCoord.Item2; int y = gearCoord.Item2;
int gearRatio = 0;
// Check the eight surrounding cells of each digit in the number. // Check the eight surrounding cells of the gear
for (int i = x - 1; i <= x + 1; i++) for (int i = x - 1; i <= x + 1; i++)
{ {
for (int j = y - 1; j <= y + 1; j++) for (int j = y - 1; j <= y + 1; j++)
@@ -163,46 +239,59 @@ namespace AOC.Tests.Y2023
} }
} }
if (numberCoords.Count == 2) // Consider each set of cells in the same x axis with a digit to their immediate right as a single number
foreach ((int, int) numberCoord in numberCoords)
{ {
int number1 = int.Parse(grid[numberCoords[0].Item1, numberCoords[0].Item2].ToString()); Console.WriteLine($"{numberCoord.Item1},{numberCoord.Item2}");
int number2 = int.Parse(grid[numberCoords[1].Item1, numberCoords[1].Item2].ToString());
int gearRatio = number1 * number2;
// gearRatios.Add(gearRatio);
} }
Console.WriteLine("---");
List<int> numbers = ExtractNumbers(numberCoords, grid);
foreach (int number in numbers)
{
Console.WriteLine($"Number: {number}");
} }
return false;
Console.WriteLine("===");
if (numbers.Count == 2)
{
// If there are exactly two numbers around the gear, generate the gear ratio
gearRatio = numbers[0] * numbers[1];
Console.WriteLine($"{numbers[0]} * {numbers[1]} = {gearRatio}");
}
return gearRatio;
} }
private List<int> GetAllGearRatios(string[] lines) private int GetSumOfAllGearRatios(string[] lines)
{ {
// Create a 2D array to represent the grid. // Create a 2D array to represent the grid.
int rows = lines.Length;
int cols = lines[0].Length; int cols = lines[0].Length;
char[,] grid = new char[rows, cols]; int rows = lines.Length;
char[,] grid = new char[cols, rows];
// Populate the grid // Populate the grid
for (int i = 0; i < rows; i++) for (int j = 0; j < rows; j++)
{ {
string line = lines[i]; string line = lines[j];
for (int j = 0; j < cols; j++) for (int i = 0; i < cols; i++)
{ {
grid[i, j] = line[j]; grid[i, j] = line[i];
} }
} }
List<int> gearRatios = new();
List<(int, int)> gearCoords = new(); List<(int, int)> gearCoords = new();
// Iterate over each cell in the grid to find all gears // Iterate over each cell in the grid to find all gears
for (int i = 0; i < rows; i++) for (int i = 0; i < cols; i++)
{ {
Console.WriteLine($"Line {i+1}"); // Console.WriteLine($"Line {i + 1}");
for (int j = 0; j < cols; j++) for (int j = 0; j < rows; j++)
{ {
if (grid[i, j] == '*') if (grid[i, j] == '*')
{ {
gearCoords.Add((i, j)); gearCoords.Add((i, j));
@@ -210,10 +299,13 @@ namespace AOC.Tests.Y2023
} }
} }
// Now find all instances where exactly two numbers are adjacent to a gear int gearRatios = 0;
// Now find all instances where exactly two numbers are adjacent to a gear and sum their gear ratios
foreach ((int, int) gear in gearCoords)
{
gearRatios += GetGearRatioFromExactlyTwoNumbersInSurroundingCells(grid, gear);
}
// Return the list of numbers.
return gearRatios; return gearRatios;
} }
@@ -247,34 +339,34 @@ namespace AOC.Tests.Y2023
List<(int, int)> coords = new() List<(int, int)> coords = new()
{ {
(0,0), (0, 0),
(0,1), (0, 1),
(0,2), (0, 2),
(0,5), (0, 5),
(0,6), (0, 6),
(0,7), (0, 7),
(2,2), (2, 2),
(2,3), (2, 3),
(2,6), (2, 6),
(2,7), (2, 7),
(2,8), (2, 8),
(4,0), (4, 0),
(4,1), (4, 1),
(4,2), (4, 2),
(5,7), (5, 7),
(5,8), (5, 8),
(6,2), (6, 2),
(6,3), (6, 3),
(6,4), (6, 4),
(7,6), (7, 6),
(7,7), (7, 7),
(7,8), (7, 8),
(9,1), (9, 1),
(9,2), (9, 2),
(9,3), (9, 3),
(9,5), (9, 5),
(9,6), (9, 6),
(9,7), (9, 7)
}; };
CheckSurroundingCellsForSymbols(grid, coords, true); CheckSurroundingCellsForSymbols(grid, coords, true);
@@ -332,10 +424,10 @@ namespace AOC.Tests.Y2023
string[] lines = input != null ? input.Split("\n") : realData; string[] lines = input != null ? input.Split("\n") : realData;
// A gear is any * symbol that is adjacent to exactly two part numbers. Its gear ratio is the result of multiplying those two numbers together. // A gear is any * symbol that is adjacent to exactly two part numbers. Its gear ratio is the result of multiplying those two numbers together.
List<int> gearRatios = GetAllGearRatios(lines); int gearRatiosSum = GetSumOfAllGearRatios(lines);
// The result is the sum of all the gear ratios // The result is the sum of all the gear ratios
int result = gearRatios.Sum(); int result = gearRatiosSum;
if (expected != null) if (expected != null)
{ {
@@ -344,5 +436,4 @@ namespace AOC.Tests.Y2023
Console.WriteLine($"Part 2: {result}"); Console.WriteLine($"Part 2: {result}");
} }
}
} }