Powered by AppSignal & Oban Pro

--- Day 5: Cafeteria ---

2025/day_5.livemd

— Day 5: Cafeteria —

Mix.install([{:kino_aoc, "~> 0.1"}])

Setup

{:ok, puzzle_input} =
  KinoAOC.download_puzzle("2025", "5", System.fetch_env!("LB_AOC_SESSION_COOKIE"))
test_input = Kino.Input.textarea("test_input")
test_input = Kino.Input.read(test_input)
defmodule Cafeteria do
  def parse_db(input) do
    [ranges, ingr_ids] = String.split(input, "\n\n")

    fresh_ranges =
      for range <- String.split(ranges) do
        [low, high] = range |> String.split("-") |> Enum.map(&amp;String.to_integer/1)
        low..high
      end

    ingr_ids = ingr_ids |> String.split() |> Enum.map(&amp;String.to_integer/1)

    {fresh_ranges, ingr_ids}
  end

  def ranges_overlap?(r1, r2), do: !Range.disjoint?(r1, r2)
  def merge_ranges(r1, r2), do: min(r1.first, r2.first)..max(r1.last, r2.last)
end

Part 1

import Cafeteria

# {fresh_ranges, ingr_ids} = Cafeteria.parse_db(test_input)
{fresh_ranges, ingr_ids} = Cafeteria.parse_db(puzzle_input)

Enum.sum_by(ingr_ids, fn id ->
  if Enum.any?(fresh_ranges, &amp;(id in &amp;1)), do: 1, else: 0
end)

Part 2

import Cafeteria

# {fresh_ranges, _ingr_ids} = Cafeteria.parse_db(test_input)
{fresh_ranges, _ingr_ids} = Cafeteria.parse_db(puzzle_input)

[first_range | fresh_ranges] = Enum.sort(fresh_ranges)

fresh_ranges
|> Enum.reduce([first_range], fn next_range, [previous_range | rest] = acc ->
  if ranges_overlap?(previous_range, next_range) do
    [merge_ranges(previous_range, next_range) | rest]
  else
    [next_range | acc]
  end
end)
|> Enum.sum_by(&amp;Range.size/1)