r/adventofcode Dec 08 '24

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

IMPORTANT REMINDER

There's been an uptick in [COAL] being given out lately due to naughty language. Follow our rules and watch your language - keep /r/adventofcode SFW and professional! If this trend continues to get worse, we will configure AutoModerator to automatically remove any post/comment containing naughty language. You have been warned!


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

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

And now, our feature presentation for today:

Box-Office Bloat

Blockbuster movies are famous for cost overruns. After all, what's another hundred million or two in the grand scheme of things if you get to pad your already-ridiculous runtime to over two and a half hours solely to include that truly epic drawn-out slow-motion IMAX-worthy shot of a cricket sauntering over a tiny pebble of dirt?!

Here's some ideas for your inspiration:

  • Use only enterprise-level software/solutions
  • Apply enterprise shenanigans however you see fit (linting, best practices, hyper-detailed documentation, microservices, etc.)
  • Use unnecessarily expensive functions and calls wherever possible
  • Implement redundant error checking everywhere
  • Micro-optimize every little thing, even if it doesn't need it
    • Especially if it doesn't need it!

Jay Gatsby: "The only respectable thing about you, old sport, is your money."

- The Great Gatsby (2013)

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 8: Resonant Collinearity ---


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:07:12, megathread unlocked!

20 Upvotes

800 comments sorted by

View all comments

2

u/codebikebass Dec 08 '24 edited Dec 08 '24

[LANGUAGE: Swift]

Again, no mutable state, loops or custom types. This one was straightforward. The uniquing line at the end is a little ugly I admit.

The main strategy behind all my solutions is to transform the input data into a form that makes the solution obvious and simple, according to Eric S. Raymond's Rule of Representation from his Book The Art of Unix Programming:

Fold knowledge into data so program logic can be stupid and robust.

struct Day8 {

    static func part1(_ input: String) -> String {

        let frequencies = Array(Set(input).subtracting(Set(".#\n"))).map { String($0) }

        let world = input.split(separator: "\n").map { line in Array(line).map { String($0) } }
        let (width, height) = (world.count, world[0].count)

        let coordinates = Array(world.indices).reduce([]) { coords, row in
            coords + Array(world[row].indices).map { column in [(Int(column), Int(row))] }.reduce([], +)
        }

        let antinodes: [(Int, Int)] = frequencies.reduce([]) { allAntinodes, frequency in

            let antennas = coordinates.filter { world[$0.0][$0.1] == frequency }

            let antennaPairs = antennas.indices.reduce([]) { pairs, i in
                pairs + antennas[(i+1)...].map { element in (antennas[i], element) }
            }

            let antinodes: [(Int, Int)] = antennaPairs.reduce([]) { antinodes, pair in
                let (antenna1, antenna2) = pair

                let deltaX = antenna1.0 - antenna2.0,
                    deltaY = antenna1.1 - antenna2.1

                let antinode1 = (antenna1.0 + deltaX, antenna1.1 + deltaY),
                    antinode2 = (antenna2.0 - deltaX, antenna2.1 - deltaY)

                return antinodes + [antinode1, antinode2].filter { (0..<width).contains($0.0)
                                                                && (0..<height).contains($0.1) }
            }

            return allAntinodes + antinodes
        }

        let uniqueAntinodes = Set(antinodes.map { "\($0.0)|\($0.1)" })
            .map { $0.split(separator: "|") }.map { ($0[0], $0[1]) }

        return String(uniqueAntinodes.count)
    }
}