this post was submitted on 09 Dec 2025
17 points (87.0% liked)

Advent Of Code

1207 readers
4 users here now

An unofficial home for the advent of code community on programming.dev! Other challenges are also welcome!

Advent of Code is an annual Advent calendar of small programming puzzles for a variety of skill sets and skill levels that can be solved in any programming language you like.

Everybody Codes is another collection of programming puzzles with seasonal events.

EC 2025

AoC 2025

Solution Threads

M T W T F S S
1 2 3 4 5 6 7
8 9 10 11 12

Visualisations Megathread

Rules/Guidelines

Relevant Communities

Relevant Links

Credits

Icon base by Lorc under CC BY 3.0 with modifications to add a gradient

console.log('Hello World')

founded 2 years ago
MODERATORS
 

Day 9: Movie Theater

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

you are viewing a single comment's thread
view the rest of the comments
[โ€“] gedhrel@lemmy.world 1 points 1 week ago

Haskell, part 2

I broke down the outline into a set of boxes by scanning over them.

type Box = (C, C) -- inclusive coordinates
makeBoxes :: [C] -> [Box]
makeBoxes cs =
    let cs' = sort cs -- left-to-right first, top-to-bottom second
        scanLines = cs' & groupOn fst
     in scanOver 0 [] scanLines
  where
    scanOver lastX currentYs [] = []
    scanOver lastX currentYs (new : rest) =
        let newX = new & head & fst
            closedBoxes = do
                [y1, y2] <- currentYs & chunksOf 2
                pure ((lastX, y1), (newX, y2))
            newYs =
                -- Take the new column and remove anything that
                -- corresponds to a y value that appears in both
                merge currentYs (map snd new)
         in -- Close the current boxes
            closedBoxes ++ scanOver newX newYs rest
    merge [] ns = ns
    merge ms [] = ms
    merge (m : ms) (n : ns)
        | m < n = m : merge ms (n : ns)
        | m > n = n : merge (m : ms) ns
        | otherwise = merge ms ns

The fiddly bit was handling all the cases for shape subtraction. I don't give it here because it's just a slog, but the gist is this:

type Shape = [Box]
subtractBox :: Box -> Box -> Shape -- returns whatever's left

subtractShape :: Shape -> Shape -> Shape -- this is just a fold.

The idea: take a bounding box that's just large enough to cover all coordinates. From that, subtract the set of boxes above. You get a set of boxes that are in the "outside", ie, illegal region. [I did it this way because managing shape subtraction from the set of "inside" boxes is just more work.]

Then for each candidate rectangle, if it overlaps with any of the "out-of-bounds" boxes, it's not a solution.