Day 4: Ceres Search
Megathread guidelines
- Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
- You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL
FAQ
- What is this?: Here is a post with a large amount of details: https://programming.dev/post/6637268
- Where do I participate?: https://adventofcode.com/
- Is there a leaderboard for the community?: We have a programming.dev leaderboard with the info on how to join in this post: https://programming.dev/post/6631465
C#
namespace Day04; static class Program { public record struct Point(int Row, int Col); static void Main(string[] args) { var sample = File.ReadAllLines("sample.txt"); var data = File.ReadAllLines("data.txt"); Console.WriteLine($"Part 1 (sample): {SolvePart1(sample)}"); Console.WriteLine($"Part 1 (data): {SolvePart1(data)}"); Console.WriteLine($"Part 2 (sample): {SolvePart2(sample)}"); Console.WriteLine($"Part 2 (data): {SolvePart2(data)}"); } private static readonly string Search = "XMAS"; private static readonly Func<Point, Point>[] DirectionalMoves = { p => new Point(p.Row + 1, p.Col), p => new Point(p.Row + 1, p.Col + 1), p => new Point(p.Row, p.Col + 1), p => new Point(p.Row - 1, p.Col + 1), p => new Point(p.Row - 1, p.Col), p => new Point(p.Row - 1, p.Col - 1), p => new Point(p.Row, p.Col - 1), p => new Point(p.Row + 1, p.Col - 1), }; private static readonly Func<Point, Point>[] ForwardSlashMoves = { p => new Point(p.Row - 1, p.Col - 1), p => new Point(p.Row + 1, p.Col + 1), }; private static readonly Func<Point, Point>[] BackSlashMoves = { p => new Point(p.Row + 1, p.Col - 1), p => new Point(p.Row - 1, p.Col + 1), }; static long SolvePart1(string[] data) { return Enumerable .Range(0, data.Length) .SelectMany(row => Enumerable.Range(0, data[row].Length) .Select(col => new Point(row, col))) .Where(p => IsMatch(data, p, Search[0])) .Sum(p => DirectionalMoves .Count(move => DeepMatch(data, move(p), move, Search, 1))); } static long SolvePart2(string[] data) { return Enumerable .Range(0, data.Length) .SelectMany(row => Enumerable.Range(0, data[row].Length) .Select(col => new Point(row, col))) .Where(p => IsMatch(data, p, 'A')) .Count(p => CheckDiagonalMoves(data, p, ForwardSlashMoves) && CheckDiagonalMoves(data, p, BackSlashMoves)); } static bool CheckDiagonalMoves(string[] data, Point p, Func<Point, Point>[] moves) => (IsMatch(data, moves[0](p), 'S') && IsMatch(data, moves[1](p), 'M')) || (IsMatch(data, moves[0](p), 'M') && IsMatch(data, moves[1](p), 'S')); static bool DeepMatch(string[] data, Point p, Func<Point, Point> move, string search, int searchIndex) => (searchIndex >= search.Length) ? true : (!IsMatch(data, p, search[searchIndex])) ? false : DeepMatch(data, move(p), move, search, searchIndex + 1); static bool IsMatch(string[] data, Point p, char searchChar) => IsInBounds(data, p) && (data[p.Row][p.Col] == searchChar); static bool IsInBounds(string[] data, Point p) => (p.Row >= 0) && (p.Col >= 0) && (p.Row < data.Length) && (p.Col < data[0].Length); }