mirror of
https://github.com/jcreek/advent-of-code.git
synced 2026-07-12 18:53:47 +00:00
feat(*): Add array searching helper methods
This commit is contained in:
@@ -0,0 +1,200 @@
|
||||
namespace AOC.Tests.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Provides utility methods for searching within 2D character arrays.
|
||||
/// </summary>
|
||||
public static class ArraySearching
|
||||
{
|
||||
// Directions: Right, Left, Down, Up, Diagonal Down-Right, Diagonal Down-Left, Diagonal Up-Right, Diagonal Up-Left
|
||||
private static readonly (int RowOffset, int ColOffset)[] Directions = new[]
|
||||
{
|
||||
(0, 1), // Right
|
||||
(0, -1), // Left
|
||||
(1, 0), // Down
|
||||
(-1, 0), // Up
|
||||
(1, 1), // Diagonal down-right
|
||||
(1, -1), // Diagonal down-left
|
||||
(-1, 1), // Diagonal up-right
|
||||
(-1, -1) // Diagonal up-left
|
||||
};
|
||||
|
||||
public static char[,] ConvertListTo2DArray(List<string> list)
|
||||
{
|
||||
int rows = list.Count;
|
||||
int cols = list[0].Length;
|
||||
char[,] grid = new char[rows, cols];
|
||||
for (int r = 0; r < rows; r++)
|
||||
{
|
||||
string row = list[r];
|
||||
for (int c = 0; c < cols; c++)
|
||||
{
|
||||
grid[r, c] = row[c];
|
||||
}
|
||||
}
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
public static void Print2DCharArray(char[,] array)
|
||||
{
|
||||
for (int i = 0; i < array.GetLength(0); i++) // Iterate rows
|
||||
{
|
||||
for (int j = 0; j < array.GetLength(1); j++) // Iterate columns
|
||||
{
|
||||
Console.Write(array[i, j] + " ");
|
||||
}
|
||||
|
||||
Console.WriteLine(); // New line after each row
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds all occurrences of the specified target string within the given 2D character array.
|
||||
/// Occurrences are searched in all eight directions (horizontal, vertical, and diagonals).
|
||||
/// Returns a collection of matches, where each match is represented as a collection of coordinates.
|
||||
/// </summary>
|
||||
/// <param name="grid">The 2D character array to search.</param>
|
||||
/// <param name="target">The string to find.</param>
|
||||
/// <returns>
|
||||
/// A list of matches, where each match is a list of (row, column) tuples indicating the positions of the found
|
||||
/// string.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">Thrown if grid or target is null.</exception>
|
||||
/// <exception cref="ArgumentException">Thrown if target is empty.</exception>
|
||||
public static List<List<(int Row, int Col)>> FindStringOccurrences(char[,] grid, string target)
|
||||
{
|
||||
if (grid == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(grid));
|
||||
}
|
||||
|
||||
if (target == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(target));
|
||||
}
|
||||
|
||||
if (target.Length == 0)
|
||||
{
|
||||
throw new ArgumentException("Target string cannot be empty.", nameof(target));
|
||||
}
|
||||
|
||||
List<List<(int, int)>>? matches = new();
|
||||
int rows = grid.GetLength(0);
|
||||
int cols = grid.GetLength(1);
|
||||
char firstChar = target[0];
|
||||
|
||||
for (int r = 0; r < rows; r++)
|
||||
{
|
||||
for (int c = 0; c < cols; c++)
|
||||
{
|
||||
// Optimization: Only start search if first char matches
|
||||
if (grid[r, c] == firstChar)
|
||||
{
|
||||
foreach ((int rowOffset, int colOffset) in Directions)
|
||||
{
|
||||
if (CanFit(grid, r, c, rowOffset, colOffset, target.Length))
|
||||
{
|
||||
List<(int, int)>? coords = TryMatch(grid, r, c, rowOffset, colOffset, target);
|
||||
if (coords != null)
|
||||
{
|
||||
matches.Add(coords);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts all integer values from a 2D character array.
|
||||
/// Consecutive digits are combined to form a number. Non-digit characters separate numbers.
|
||||
/// Returns a list of all parsed integers.
|
||||
/// </summary>
|
||||
/// <param name="grid">The 2D character array to search.</param>
|
||||
/// <returns>A list of integers found in the grid.</returns>
|
||||
/// <exception cref="ArgumentNullException">Thrown if grid is null.</exception>
|
||||
public static List<int> ExtractNumbers(char[,] grid)
|
||||
{
|
||||
if (grid == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(grid));
|
||||
}
|
||||
|
||||
List<int>? numbers = new();
|
||||
int rows = grid.GetLength(0);
|
||||
int cols = grid.GetLength(1);
|
||||
|
||||
// We'll parse row-by-row for simplicity
|
||||
for (int r = 0; r < rows; r++)
|
||||
{
|
||||
int currentNumber = 0;
|
||||
bool buildingNumber = false;
|
||||
|
||||
for (int c = 0; c < cols; c++)
|
||||
{
|
||||
char ch = grid[r, c];
|
||||
if (char.IsDigit(ch))
|
||||
{
|
||||
buildingNumber = true;
|
||||
currentNumber = currentNumber * 10 + (ch - '0');
|
||||
}
|
||||
else
|
||||
{
|
||||
if (buildingNumber)
|
||||
{
|
||||
numbers.Add(currentNumber);
|
||||
currentNumber = 0;
|
||||
buildingNumber = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the row ended but we were still building a number
|
||||
if (buildingNumber)
|
||||
{
|
||||
numbers.Add(currentNumber);
|
||||
}
|
||||
}
|
||||
|
||||
return numbers;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the target string can fit starting at position (r, c) in the given direction.
|
||||
/// </summary>
|
||||
private static bool CanFit(char[,] grid, int r, int c, int rowOffset, int colOffset, int length)
|
||||
{
|
||||
int rows = grid.GetLength(0);
|
||||
int cols = grid.GetLength(1);
|
||||
|
||||
int endRow = r + (length - 1) * rowOffset;
|
||||
int endCol = c + (length - 1) * colOffset;
|
||||
|
||||
return endRow >= 0 && endRow < rows && endCol >= 0 && endCol < cols;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to match the target string starting at (r, c) in a given direction.
|
||||
/// If matched, returns the list of coordinates. Otherwise, returns null.
|
||||
/// </summary>
|
||||
private static List<(int, int)> TryMatch(char[,] grid, int r, int c, int rowOffset, int colOffset, string target)
|
||||
{
|
||||
List<(int, int)>? coords = new(target.Length);
|
||||
for (int i = 0; i < target.Length; i++)
|
||||
{
|
||||
int rr = r + i * rowOffset;
|
||||
int cc = c + i * colOffset;
|
||||
if (grid[rr, cc] != target[i])
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
coords.Add((rr, cc));
|
||||
}
|
||||
|
||||
return coords;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user