using AdvenOfCode.Contracts; using AdventOfCode.HelperClasses; namespace AoC_2025; public class Day04 : IPuzzleSolver { private string[] ParsePuzzleInput(string path) { var puzzleInput = File.ReadAllLines(path) .Where(line => !string.IsNullOrWhiteSpace(line)) .Select(line => line.Trim()) .ToArray(); return puzzleInput; } public long SolvePart1(string pathToPuzzleInput) { var paperrollGrid = ParsePuzzleInput(pathToPuzzleInput); var accessiblePaperrolls = GetAccessiblePaperrolls(paperrollGrid); var countAccessibleRolls = accessiblePaperrolls.Count(); return countAccessibleRolls; } public long SolvePart2(string pathToPuzzleInput) { var paperrollGrid = ParsePuzzleInput(pathToPuzzleInput); var rollCoordinates = GetRollCoordinates(paperrollGrid); var countAccessibleRolls = RecursiveCountAllRemovableRolls(rollCoordinates); return countAccessibleRolls; } private IEnumerable GetAccessiblePaperrolls(IEnumerable paperrollGrid) { var rollCoordinates = GetRollCoordinates(paperrollGrid); var rollsWithNeighbours = GetNeighbours(rollCoordinates); var accessiblePaperrolls = FilterForLessThan(rollsWithNeighbours, 4); return accessiblePaperrolls; } private int RecursiveCountAllRemovableRolls(HashSet coordinates) { var rollsWithNeighbours = GetNeighbours(coordinates); var accessiblePaperrolls = FilterForLessThan(rollsWithNeighbours, 4).ToArray(); var countAccessibleRolls = accessiblePaperrolls.Length; coordinates.ExceptWith(accessiblePaperrolls); return countAccessibleRolls == 0 ? 0 : countAccessibleRolls + RecursiveCountAllRemovableRolls(coordinates); } private HashSet GetRollCoordinates(IEnumerable paperrollGrid) { var coordinates = paperrollGrid .SelectMany((line, xIndex) => GetRollCoordinates(line, xIndex)) .ToHashSet(); return coordinates; } private IEnumerable GetRollCoordinates(string gridLine, int xIndex) { var indexedCharacters = gridLine.Index(); var validRolls = indexedCharacters.Where(tuple => tuple.Item == '@'); var rollCoordinates = validRolls.Select(tuple => new Coordinate(xIndex, tuple.Index)); return rollCoordinates; } private IEnumerable<(Coordinate coordinate, Coordinate[] neighbours)> GetNeighbours(HashSet rollCoordinates) { var coordsWithNeighbourCount = rollCoordinates .Select(coord => (coord, GetNeighbours(coord, rollCoordinates))); return coordsWithNeighbourCount; } private Coordinate[] GetNeighbours(Coordinate coordinate, HashSet coordinates) { Coordinate[] neighbourDirections = [ new(-1, -1), new(-1, 0), new(-1, 1), new(0, -1), new(0, 1), new(1, -1), new(1, 0), new(1, 1), ]; var possibleNeighbours = neighbourDirections .Select(direction => coordinate + direction); var actualNeighbours = possibleNeighbours .Where(coord => coordinates.Contains(coord)) .ToArray(); return actualNeighbours; } private IEnumerable FilterForLessThan(IEnumerable<(Coordinate coordinate, Coordinate[] neighbours)> coordinatesWithNeighbours, int lessThan) { var coordinatesWithLess = coordinatesWithNeighbours .Where(roll => roll.neighbours.Length < lessThan) .Select(roll => roll.coordinate); return coordinatesWithLess; } }