using AdventOfCode.Core; using System.Text.RegularExpressions; namespace AdventOfCode.Solutions._2023 { public partial class Day03(InputReader reader) : IChallange { private InputReader _inputReader = reader; private struct Point { public int X { get; set; } public int Y { get; set; } } private class PartNumber { public int X { get; set; } public int Y { get; set; } public string Section { get; set; } = string.Empty; public int Length => Section.Length; public bool IsDigit() => Section.Length > 1; public bool IsPartSymbol() => !IsDigit(); public override string ToString() { return $"[{Y},{X}] {Section}"; } } public async Task GetSolutionPart1() { List parts = []; int row = 0; int total = 0; await foreach (string line in _inputReader.ReadAsStringLine()) { MatchCollection matchCollection = FindPartItems().Matches(line); parts.AddRange(matchCollection.Select(match => new PartNumber { X = match.Index, Y = row, Section = match.Value })); row++; } List numbers = parts.Where(p => p.IsDigit()).ToList(); List symbols = parts.Where(p => p.IsPartSymbol()).ToList(); var intersected = numbers.Where(number => IsPointInAnyBox(symbols, number)).ToList(); //var intersected = numbers.Where(number => GetSection(symbols, number.X - 1, number.Y - 1, number.X + number.Length, number.Y + 1).Any()).ToList(); total = numbers.Where(number => GetSection(symbols, number.X - 1, number.Y - 1, number.X + number.Length, number.Y + 1).Any()).Sum(number => int.Parse(number.Section)); //Grid grid = await _inputReader.ReadToGrid(); //int row = 0; // //await foreach(string line in _inputReader.ReadAsStringLine()) //{ // MatchCollection matchCollection = FindDigits().Matches(line); // // foreach (Match match in matchCollection.Cast()) // { // var section = grid.GetSection(match.Index - 1, row - 1, match.Index + match.Length, row + 1).ToList(); // bool isPartNumber = section.Any(n => !(n.Char == '.' || (n.Char >= '0' && n.Char <= '9'))); // if (isPartNumber) { // total += int.Parse(match.Value); // } // } // // row++; //} return total.ToString(); } public async Task GetSolutionPart2() { List parts = []; int row = 0; int total = 0; await foreach (string line in _inputReader.ReadAsStringLine()) { MatchCollection matchCollection = FindPartItems().Matches(line); parts.AddRange(matchCollection.Select(match => new PartNumber { X = match.Index, Y = row, Section = match.Value })); row++; } List numbers = parts.Where(p => p.IsDigit()).ToList(); List gears = parts.Where(p => p.IsPartSymbol() && p.Section == "*").ToList(); foreach (PartNumber gear in gears) { // check if there are 2 numbers around List ratios = GetSection(numbers, gear).ToList(); if (ratios.Count != 2) continue; int totalRatio = int.Parse(ratios[0].Section) * int.Parse(ratios[1].Section); total += totalRatio; } return total.ToString(); } private IEnumerable GetSection(List toSearch, int fromX, int fromY, int toX, int toY) { return toSearch.Where(node => node.X >= fromX && node.X + node.Length <= toX && node.Y >= fromY && node.Y <= toY); } private bool IsPointInAnyBox(List targets, PartNumber source) { return targets.Any(target => IsPointInBox(target, source)); } private bool IsPointInBox(PartNumber target, PartNumber source) { Point targetA = new Point { X = target.X, Y = target.Y }, targetB = new Point { X = target.X + target.Length - 1, Y = target.Y }; Point sourceA = new Point { X = source.X, Y = source.Y }; return IsPointInBox(targetA, targetB, sourceA); } private bool DoBoxesOverlap(List targets, PartNumber source) { return targets.Any(target => DoBoxesOverlap(target, source)); } private bool DoBoxesOverlap(PartNumber target, PartNumber source) { Point targetA = new Point { X = target.X, Y = target.Y }, targetB = new Point { X = target.X + target.Length - 1, Y = target.Y }; Point sourceA = new Point { X = source.X - 1, Y = source.Y - 1 }, sourceB = new Point { X = source.X + source.Length, Y = source.Y + 1 }; return IsPointInBox(targetA, targetB, sourceA) && IsPointInBox(targetA, targetB, sourceB); } private bool IsPointInBox(Point boxPointA, Point boxPointB, Point pointSource) { return pointSource.X >= boxPointA.X && pointSource.X <= boxPointB.X && pointSource.Y >= boxPointA.Y && pointSource.Y <= boxPointB.Y; } private IEnumerable GetSection(List toSearch, PartNumber source) { return toSearch.Where(target => target.X >= source.X - 1 && target.X + target.Length <= source.X && target.Y >= source.Y - 1 && target.Y <= source.Y + 1); } [GeneratedRegex("(\\d+)", RegexOptions.Compiled)] private static partial Regex FindDigits(); [GeneratedRegex("(\\d+)|([^.])", RegexOptions.Compiled)] private static partial Regex FindPartItems(); } }