Advent of Code 2025 - Day 5: Cafeteria

Published: (December 10, 2025 at 11:48 AM EST)
3 min read
Source: Dev.to

Source: Dev.to

Me solving AoC Day 5

The Problem

The Elves have a database with fresh ingredient ID ranges and need to check their inventory.

  • Part 1: Given specific ingredient IDs, how many are fresh (i.e., fall within the ranges)?
  • Part 2: How many total IDs do these ranges cover?

Example

Ranges: 3-5, 10-14, 16-20, 12-18
IDs to check: 1, 5, 8, 11, 17, 32

  • Fresh IDs from the list: 3 (IDs 5, 11, 17)
  • Total IDs covered by the ranges: 14

My Approach

When I saw overlapping ranges in Part 1, I anticipated that Part 2 would ask about the ranges themselves. A brute‑force check works for Part 1, but counting all IDs with overlaps is messy.
The solution is to merge the ranges first; overlapping intervals are combined into a single interval, making Part 2 trivial.

Merging Ranges

Sort the ranges and merge overlapping intervals. For example, 10-14 and 12-18 become 10-18.

fn merge_ranges(fresh_ranges: &mut Vec) -> Vec {
    // Sort ranges in descending order by start value
    // This allows us to pop from the end (smallest start) for processing
    fresh_ranges.sort_by(|a, b| b.0.cmp(&a.0));
    let mut merged_ranges: Vec = Vec::new();

    while !fresh_ranges.is_empty() {
        // Pop the range with the smallest start value
        let mut range = fresh_ranges.pop().unwrap();

        if fresh_ranges.is_empty() {
            // Last range, just add it
            merged_ranges.push(range);
        } else {
            // Check if the current range overlaps with the next range
            // Ranges overlap if current end >= next start
            if range.1 >= fresh_ranges.last().unwrap().0 {
                // Merge: pop the next range and extend the current range's end
                let another = fresh_ranges.pop().unwrap();
                range.1 = range.1.max(another.1);
                // Push merged range back to continue merging
                fresh_ranges.push(range);
            } else {
                // No overlap, add to merged list
                merged_ranges.push(range);
            }
        }
    }
    merged_ranges
}

Part 1: Check Specific IDs

Check if each ingredient falls within any merged range.

fn fresh_ingredients(fresh_ranges: &Vec, ingredients: &Vec) -> u32 {
    let mut count = 0;
    for ingredient in ingredients {
        for range in fresh_ranges {
            if range.0 = *ingredient {
                count += 1;
                break;
            }
        }
    }
    count
}

Part 2: Count All Fresh IDs

Sum the size of each merged range.

fn all_fresh_ingredients(fresh_ranges: &Vec) -> u64 {
    let mut count = 0;
    for range in fresh_ranges {
        count += range.1 - range.0 + 1;
    }
    count
}

Why This Works

Merging ranges eliminates overlaps, turning Part 2 into a simple sum of interval lengths instead of complex overlap handling.

Practice interval merging: LeetCode – Merge Intervals

Full Solution

You can find the complete solution, including input parsing and tests, on GitHub:

View Full Solution on GitHub

Have you solved this puzzle differently? I’d love to hear about alternative approaches in the comments!

Back to Blog

Related posts

Read more »

Monkey Market

Part 1 Another math gauntlet I get to program a bunch of math operations. Some will be part of several conditionals. I've done it before. I'm confident I can d...

Advent of Code 2025 - Day 6

Check out my full solution for day 6 on GitHub. Part one The first part gives us a few rows of numbers and a last line with operations that are either addition...

Advent of Code 2025 - December 11th

!Cover image for Advent of Code 2025 - December 11thhttps://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fd...