# 2025 Day 5: Cafeteria

**URL:** <https://forum.ada-lang.io/t/2025-day-5-cafeteria/4014>\
**Category:** Advent of Code\
**Tags:** spoilers\
**Created:** [December 5, 2025, 10:02pm UTC](https://forum.ada-lang.io/t/2025-day-5-cafeteria/4014 "2025-12-05T22:02:23Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![cantanima](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/cantanima/32/121_2.png) [@cantanima](https://forum.ada-lang.io/u/cantanima)\
**Post date:** [December 5, 2025, 10:02pm UTC](https://forum.ada-lang.io/t/2025-day-5-cafeteria/4014/1 "2025-12-05T22:02:24Z")

</div>

No spoilers about spoiled food in this puzzle; IMHO it was surprisingly easier than yesterday’s.

---

<div class="post-metadata">

**Author:** ![AdaOrbit](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/adaorbit/32/879_2.png) [@AdaOrbit](https://forum.ada-lang.io/u/AdaOrbit)\
**Post date:** [December 5, 2025, 11:12pm UTC](https://forum.ada-lang.io/t/2025-day-5-cafeteria/4014/2 "2025-12-05T23:12:14Z")

</div>

I actually had a lot of problems again…  
especially parsing strings. I still have to look at a good string parsing library but I barely fit in the time to do AoC.  
At least I learned from the past days to use Long\_Long\_Integer!

I’ll have to look at how others implemented the range. My approach may be a bit overdone/underdone

```ada
type ID_Range is record
   Begining : Long_Long_Integer;
   Ending : Long_Long_Integer;
end record;

Fresh_IDs : array (1 .. 177) of ID_Range; -- magic numbers

```

---

<div class="post-metadata">

**Author:** ![Heziode](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/heziode/32/709_2.png) [@Heziode](https://forum.ada-lang.io/u/Heziode)\
**Post date:** [December 5, 2025, 11:13pm UTC](https://forum.ada-lang.io/t/2025-day-5-cafeteria/4014/3 "2025-12-05T23:13:22Z")

</div>

On my side, with Claude Code Opus 4.5, part 1 and 2 worked on the 1st try.

Relatively impressive, even if the code can be a bit lighter

---

<div class="post-metadata">

**Author:** ![cantanima](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/cantanima/32/121_2.png) [@cantanima](https://forum.ada-lang.io/u/cantanima)\
**Post date:** [December 5, 2025, 11:46pm UTC](https://forum.ada-lang.io/t/2025-day-5-cafeteria/4014/4 "2025-12-05T23:46:04Z")

</div>

> [@AdaOrbit](#):
>
> I still have to look at a good string parsing library but I barely fit in the time to do AoC. … I’ll have to look at how others implemented the range.

Assuming you’re using gnat, you may want to try something like this (taken from my code; your issues addressed in reverse order):

```ada
type ID_Number is range 0 .. 2**64 - 1;

   package ID_Vectors is new
     Ada.Containers.Vectors
       (Index_Type => Positive,
        Element_Type => ID_Number);
   subtype ID_Vector is ID_Vectors.Vector;

   Questionable_IDs : ID_Vector;

```

and for reading and parsing them, I basically did this:

```ada
with Ada.Text_IO;
-- ...
   package ID_IO is new IO.Integer_IO (Num => ID_Number);
-- ...
               -- the following inside a loop in the Read_Input function
               ID_IO.Get (Line, Start, Position);
               ID_IO.Get (Line (Position + 2 .. Line'Last), Finish, Position);
               ID_Ranges.Append (ID_Range_Record'(Start, Finish));

```

Some real Ada programmers may weigh in with better options, but this worked fine for me.

---

<div class="post-metadata">

**Author:** ![cantanima](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/cantanima/32/121_2.png) [@cantanima](https://forum.ada-lang.io/u/cantanima)\
**Post date:** [December 5, 2025, 11:49pm UTC](https://forum.ada-lang.io/t/2025-day-5-cafeteria/4014/5 "2025-12-05T23:49:23Z")

</div>

> [@Heziode](#):
>
> On my side, with Claude Code Opus 4.5, part 1 and 2 worked on the 1st try.
> 
> Relatively impressive, even if the code can be a bit lighter

😭

(+16 characters)

---

<div class="post-metadata">

**Author:** ![jcmoyer](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/jcmoyer/32/373_2.png) [@jcmoyer](https://forum.ada-lang.io/u/jcmoyer)\
**Post date:** [December 6, 2025, 2:48am UTC](https://forum.ada-lang.io/t/2025-day-5-cafeteria/4014/6 "2025-12-06T02:48:23Z")

</div>

For me this one was basically “import solution from 2023.” Not super exciting but I’m not implementing interval merging again. I hope the difficulty ramps up - there’s not much time left with only 12 puzzles.

---

<div class="post-metadata">

**Author:** ![JC001](https://forum.ada-lang.io/letter_avatar_proxy/v4/letter/j/e56c9b/32.png) [@JC001](https://forum.ada-lang.io/u/JC001)\
**Post date:** [December 6, 2025, 8:06am UTC](https://forum.ada-lang.io/t/2025-day-5-cafeteria/4014/7 "2025-12-06T08:06:24Z")

</div>

I had a lot of trouble getting the merging logic correct for part 2. Maybe an interval library would be a good thing, but I don’t think I ever use them outside of AoA.

---

<div class="post-metadata">

**Author:** ![tgv](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/tgv/32/548_2.png) [@tgv](https://forum.ada-lang.io/u/tgv)\
**Post date:** [December 6, 2025, 8:35am UTC](https://forum.ada-lang.io/t/2025-day-5-cafeteria/4014/8 "2025-12-06T08:35:52Z")

</div>

> [@AdaOrbit](#):
>
> I actually had a lot of problems again… especially parsing strings.

In this case, you can strings read line by line. Until you encounter an empty line, you’re reading ranges. So you split the string at the hyphen, and then convert both resulting strings to numbers. There isn’t much more to it, but Ada doesn’t make such tasks as easy as e.g. JavaScript. A generic parsing library seems overkill. I’ve been looking into functions that perform common use cases, but my Ada skills are too limited to make something compact, useful and elegant.

Your range record is also how I did it. Another option is two arrays: one for start and one for end of range. Or even just one array and alternate start/end (ugly, but sometimes handy).

---

<div class="post-metadata">

**Author:** ![dmitry-kazakov](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/dmitry-kazakov/32/522_2.png) [@dmitry-kazakov](https://forum.ada-lang.io/u/dmitry-kazakov)\
**Post date:** [December 6, 2025, 9:40am UTC](https://forum.ada-lang.io/t/2025-day-5-cafeteria/4014/9 "2025-12-06T09:40:50Z")

</div>

> [@tgv](#):
>
> > [@AdaOrbit](#):
> >
> > I actually had a lot of problems again… especially parsing strings.
> 
> In this case, you can strings read line by line. Until you encounter an empty line, you’re reading ranges. So you split the string at the hyphen, and then convert both resulting strings to numbers. There isn’t much more to it, but Ada doesn’t make such tasks as easy

Nonsence:

```ada
loop
   declare
      Line : constant String := Get_Line (File);
      Pointer : Integer := Line'First;
      Low, High : Positive;
      ID : Positive;
   begin
      Get (Line, Pointer); -- Skip blanks
      if Pointer <= Line'Last then -- Non-empty line
         Get (Line, Pointer, Low);
         Get (Line, Pointer); -- Skip blanks
         if Pointer > Line'Last then
            ID := Low; -- This is ID
            ...
         elsif Line (Pointer) = '-' then
            Pointer := Pointer + 1;
            Get (Line, Pointer); -- Skip blanks
            Get (Line, Pointer, High);
         else
            raise Data_Error;
         end if;
      end if;
   end;
end loop;

```

---

<div class="post-metadata">

**Author:** ![dmitry-kazakov](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/dmitry-kazakov/32/522_2.png) [@dmitry-kazakov](https://forum.ada-lang.io/u/dmitry-kazakov)\
**Post date:** [December 6, 2025, 9:43am UTC](https://forum.ada-lang.io/t/2025-day-5-cafeteria/4014/10 "2025-12-06T09:43:14Z")

</div>

> [@JC001](#):
>
> Maybe an interval library would be a good thing

A set of discrete elements is meant for the job:

> **[Simple components for Ada](https://www.dmitry-kazakov.de/ada/components.htm#3.1.2)**
>
> Simple components for Ada

You can put ranges of elements into it and then check if an element is in the set.

---

<div class="post-metadata">

**Author:** ![AdaOrbit](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/adaorbit/32/879_2.png) [@AdaOrbit](https://forum.ada-lang.io/u/AdaOrbit)\
**Post date:** [December 6, 2025, 11:38am UTC](https://forum.ada-lang.io/t/2025-day-5-cafeteria/4014/11 "2025-12-06T11:38:23Z")

</div>

> [@dmitry-kazakov](#):
>
> ```ada
> if Pointer > Line'Last then
> ID := Low; -- This is ID
> ...
> elsif Line (Pointer) = '-' then
> Pointer := Pointer + 1;
> Get (Line, Pointer); -- Skip blanks
> Get (Line, Pointer, High);
> else
> raise Data_Error;
> end if;
> 
> ```

That is good way to parse! I didn’t know that you could use “pointers” in the `Get` function. I checked the hyphen by using a separate boolean. Also used this trick to see if I am done reading the ranges and have to start checking the values.

```ada
   procedure Read_Range_List (Line : String; Line_Index : Integer) is
      number1 : Unbounded_String := To_Unbounded_String ("");
      number2 : Unbounded_String := To_Unbounded_String ("");
      read_one : Boolean := True;
   begin
      -- Get Ranges
      if Line'Length = 0 then
         reading_ranges := False;
         return;
      end if;

      for I in 1 .. Line'Length loop
        if Line (I) = '-' then
           read_one := False;
        elsif read_one then
           number1 := number1 & Line (I);
        else
           number2 := number2 & Line (I);
        end if;
     end loop;
     ...
   end Read_Range_List;

```

The way I read in the numbers might also be dumb but at least it works ¯\_(ツ)\_/¯

---

<div class="post-metadata">

**Author:** ![jere](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/jere/32/87_2.png) [@jere](https://forum.ada-lang.io/u/jere)\
**Post date:** [December 6, 2025, 4:09pm UTC](https://forum.ada-lang.io/t/2025-day-5-cafeteria/4014/12 "2025-12-06T16:09:54Z")

</div>

> [@AdaOrbit](#):
>
> I actually had a lot of problems again…  
> especially parsing strings. I still have to look at a good string parsing library but I barely fit in the time to do AoC.  
> At least I learned from the past days to use Long\_Long\_Integer!

I didn’t do this one yet, so I’m only going off what yall are talking about in this thread, but if it is just two numbers separated by a hyphen per line, each line can be parsed this way:

```Ada
   procedure Get_2(File : in out File_Type; Left, Right : out Integer) is
      Line : constant String := Ada.Text_IO.Get_Line(File);
      Hyphen : constant Positive := Ada.Strings.Fixed.Index(Line, "-");
   begin
      Left := Integer'Value(Line(Line'First .. Hyphen - 1));
      Right := Integer'Value(Line(Hyphen + 1 .. Line'Last));
   end Get_2;

```

You can call this for each line and then save each Left, Right pair however you like.

---

<div class="post-metadata">

**Author:** ![zertovitch](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/zertovitch/32/90_2.png) [@zertovitch](https://forum.ada-lang.io/u/zertovitch)\
**Post date:** [December 6, 2025, 5:28pm UTC](https://forum.ada-lang.io/t/2025-day-5-cafeteria/4014/13 "2025-12-06T17:28:56Z")

</div>

I have progressively lost patience with sophisticated parsers for that game.  
So my parser for Day 5 is:

```ada
  input_name : constant VString := +"aoc_2025_05"; ranges : constant := 187; ingredients : constant := 1000;

  from, to : array (1 .. ranges) of Integer;
  id : array (1 .. ingredients) of Integer;

  procedure Read_Data is
    f : File_Type;
  begin
    Open (f, input_name & ".txt");
    for i in 1 .. ranges loop
      Get (f, from (i)); -- NB: replaced all '-' by ' '.
      Get (f, to (i));
    end loop;
    for i in 1 .. ingredients loop
      Get (f, id (i));
    end loop;
    Close (f);
  end Read_Data;

```

NB: `Open`, `Get`, `Close`and so on are from the `HAT` package for HAC (but not only). They resemble and actually use `Ada.Text_IO`’s routines.  
A nice thing with `Ada.Text_IO`’s number parsing is that you don’t have to worry about blanks or line breaks.

The only thing I was about to do with that AoC parser would have been to check End\_Of\_Line for the empty line which separates the ranges from the ingredient list, so `ranges` and `ingredients` would not have been hardcoded…

---

<div class="post-metadata">

**Author:** ![dmitry-kazakov](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/dmitry-kazakov/32/522_2.png) [@dmitry-kazakov](https://forum.ada-lang.io/u/dmitry-kazakov)\
**Post date:** [December 6, 2025, 6:46pm UTC](https://forum.ada-lang.io/t/2025-day-5-cafeteria/4014/14 "2025-12-06T18:46:52Z")

</div>

> [@zertovitch](#):
>
> I have progressively lost patience with sophisticated parsers for that game.

Ada is for patient careful people.

> [@zertovitch](#):
>
> A nice thing with `Ada.Text_IO`’s number parsing is that you don’t have to worry about blanks or line breaks.

No, not in the production code. A parsing action must do exactly one thing. The definition of “blank”  
or semantics of line end varies greatly in practice.

The big lie about all these examples and scripting hacks is that it is not how you parse in real life, where you need to validate input and give reasonable diagnostics. Ada is exceptionally good at that, but its code always looks longer in these exercises while **wrong** run-once code looks shorter.

---

<div class="post-metadata">

**Author:** ![JC001](https://forum.ada-lang.io/letter_avatar_proxy/v4/letter/j/e56c9b/32.png) [@JC001](https://forum.ada-lang.io/u/JC001)\
**Post date:** [December 7, 2025, 11:20am UTC](https://forum.ada-lang.io/t/2025-day-5-cafeteria/4014/15 "2025-12-07T11:20:27Z")

</div>

> [@zertovitch](#):
>
> A nice thing with `Ada.Text_IO`’s number parsing

For non-text values input as text, I follow the basic rule: Always read in a complete line of text, then parse it. This avoids a number of common problems when reading the text directly as the image of a non-text value. You can use Ada.Text\_IO’s sub-packages to help with the parsing, though I usually parse out substrings using tools like Ada.Strings.Fixed and pass them to ‘Value.
