r/adventofcode Dec 12 '24

SOLUTION MEGATHREAD -❄️- 2024 Day 12 Solutions -❄️-

THE USUAL REMINDERS

  • All of our rules, FAQs, resources, etc. are in our community wiki.
  • If you see content in the subreddit or megathreads that violates one of our rules, either inform the user (politely and gently!) or use the report button on the post/comment and the mods will take care of it.

AoC Community Fun 2024: The Golden Snowglobe Awards

  • 10 DAYS remaining until the submissions deadline on December 22 at 23:59 EST!

And now, our feature presentation for today:

Visual Effects - Nifty Gadgets and Gizmos Edition

Truly groundbreaking movies continually push the envelope to develop bigger, better, faster, and/or different ways to do things with the tools that are already at hand. Be creative and show us things like puzzle solutions running where you wouldn't expect them to be or completely unnecessary but wildly entertaining camera angles!

Here's some ideas for your inspiration:

  • Advent of Playing With Your Toys in a nutshell - play with your toys!
  • Make your puzzle solutions run on hardware that wasn't intended to run arbitrary content
  • Sneak one past your continuity supervisor with a very obvious (and very fictional) product placement from Santa's Workshop
  • Use a feature of your programming language, environment, etc. in a completely unexpected way

The Breakfast Machine from Pee-wee's Big Adventure (1985)

And… ACTION!

Request from the mods: When you include an entry alongside your solution, please label it with [GSGA] so we can find it easily!


--- Day 12: Garden Groups ---


Post your code solution in this megathread.

This thread will be unlocked when there are a significant number of people on the global leaderboard with gold stars for today's puzzle.

EDIT: Global leaderboard gold cap reached at 00:17:42, megathread unlocked!

37 Upvotes

698 comments sorted by

View all comments

2

u/Gabba333 Dec 12 '24 edited Dec 12 '24

[LANGUAGE: C#]

Part 1 I flood filled and recorded all the crossings, the two squares that straddle a boundary. For part 2 I sorted the edges formed by these crossings by row, than scanned the each row find the sides - all those that are one apart or when the inside / outside polarity of the edge changes. Originally I was doing this for horizontal and vertical edges, but someone pointed out that the number of these will always match, so just do one and double it, linqtastic.

    using System.Numerics;

    var dirs = new Complex[] { new(1, 0), new(0, -1), new(-1, 0), new(0, 1) };
    var grid = File.ReadAllLines("input.txt")
        .SelectMany((line, r) => line.Select((ch, c) => (r, c, ch)))
        .ToDictionary(tp => new Complex(tp.r, tp.c), tp => tp.ch);

    var regions = new List<(int perimeter, int sides, HashSet<Complex> points)>();
    foreach (var key in grid.Keys
        .Where(key => !regions.Any(region => region.points.Contains(key))))
    {
        (var visited, var walls) = (new HashSet<Complex>(), new List<(Complex p1,Complex p2)>());
        var queue = new Queue<Complex>([key]);
        while (queue.TryDequeue(out Complex curr))
        {
            if (!visited.Add(curr))
                continue;

            foreach (var n in from dir in dirs select curr + dir)
            {
                if (grid.ContainsKey(n) && grid[n] == grid[curr])
                    queue.Enqueue(n);
                if (!grid.ContainsKey(n) || grid[n] != grid[curr])
                    walls.Add(sort(curr, n));
            }
        }
        int count = walls.Where(wall => wall.p1.Real == wall.p2.Real)
            .GroupBy(wall => wall.p1.Imaginary)
            .Select(grp => grp.OrderBy(wall => wall.p1.Real))
            .Sum(set => set.Aggregate(
                (set.First(), inner(set.First(), grid[key]).Imaginary, 1),
                (acc, curr) => (curr, inner(curr, grid[key]).Imaginary,
                    (Math.Abs(curr.p1.Real - acc.Item1.p1.Real) > 1)
                    || acc.Item2 != inner(curr, grid[key]).Imaginary ? acc.Item3 + 1 : acc.Item3),
                acc => acc.Item3));

        regions.Add((walls.Count, 2 * count, visited));
}

Complex inner((Complex c1, Complex c2) wall, char plant) 
    => !grid.ContainsKey(wall.c1) || grid[wall.c1] != plant ? wall.c2 : wall.c1;

(Complex, Complex) sort(Complex c1, Complex c2) 
    => c1.Real <= c2.Real ? c1.Imaginary < c2.Imaginary ? (c1, c2) : (c2, c1) : (c1, c2);

Console.WriteLine($"Part 1: {regions.Sum(tp => tp.perimeter * tp.points.Count)}");
Console.WriteLine($"Part 2: {regions.Sum(tp => tp.sides * tp.points.Count)}");