2025 Day 2: Gift Shop

Part 1 was mildly annoying but Long_Long_Integer to the rescue!.

Part 2 had me fussing over off-by-one errors for 20 minutes. :sweat_smile:

Whew! That was ugly, but at least I didn’t have to iterate through the entire range each time. Replaced some exponentiation with a hand-coded function to get it past gnatprove.

I am quite sad to announce that I did it “pythonicly“. Had massive problems reading in the data since I couldn’t find any “split“ function for strings. Also got a problem with the limited Integer range and used Long_Long_Integer as well. And had problems with floor and log. And due to time constraints I could only do the first halve of and didn’t get a gold star.

This function is the worst and I hate it but it works

Value : String := Input'Image;
if Long_Long_Integer'Value (Value (1 .. Integer (Float (Value'Length) / 2.0))) = Long_Long_Integer'Value (Value (Integer (Float (Value'Length) / 2.0) + 1 .. Value'Length)) then
   return True;
end if;

Overall today was pain. At least I learned a lot about reading input…

I misread both parts (hence the deleted post, which featured a :woozy_face:), but by working through the example I managed to make it work.

Interestingly, HAC doesn’t have an issue with the large integers. It’s pretty slow, though; it takes almost 3 minutes. I tried recompiling it as Ada, but gnat chokes on reading the large integers (as others reported). An optimization to try would be to loop down in substring length, rather than up; i.e., test substring lengths from string'length / 2 down to 1 rather than the other way around. If it doesn’t work for length 4, it won’t work for length 2, so you’re more likely to catch it that way. Maybe?

Also, this would be a great healthy candidate for parallelization.

I had the same problem in previous AoC’s. If interested, a generalized solution below (click to reveal the code):

Ada.Strings.Fixed (link) has the pieces to make a quick splitter function though if you want for later. In particular you can make use of the function Ada.Strings.Fixed.Index to facilitate the splitting. In the past, I stored the results in a vector of strings. Here’s an example:

   package String_Vectors is new Ada.Containers.Indefinite_Vectors(Positive, String);
   type String_Vector is new String_Vectors.Vector with null record;

   function Split(Item : String; Pattern : String) return String_Vector is
      Result : String_Vector;
      First  : Positive := Item'First;
      Last   : Natural;
      use Ada.Strings.Fixed;
   begin

      -- Look for pattern separated chunks
      loop
         Last := Index(Item, Pattern, First);
         exit when Last not in Item'Range;
         Result.Append(Item(First .. Last - 1)); 
         First := Last + Pattern'Length;
      end loop;

      -- Append the end stuff
      Result.Append(Item(First .. Item'Last));

      return Result;
   end Split;

That’ll put all the split pieces into separate strings in the vector. This implementation includes any empty chunks in the vector as empty strings. If you want to skip empty chunks, then in the loop, you can replace

 Result.Append(Item(First .. Last - 1)); 

with

if Last > First then -- Only append non empty results
   Result.Append(Item(First .. Last - 1));
end if;

And after the loop replace

Result.Append(Item(First .. Item'Last));

with

if Item'Last >= First then -- Only append a non empty result
   Result.Append(Item(First .. Item'Last));
end if;

EDIT: I don’t know if general utility functions (for all puzzles) are considered spoilers or not, so I marked it as one to be safe

3 Likes

These were fairly easy. I used PragmARC.Line_Fieldsto split the input into individual ranges, Ada.Strings.Fixed to find the hyphen in a range, and then, for each value in a range, PragmARC.Images to obtain an image without a leading space. For part one I just checked that the image length was a multiple of two and then compared the two halves of the string. For part two, for each possible substring length, it became checking that the image length is a multiple of the substring length and comparing the first substring to the subsequent substrings.

I took the approach of generating invalid IDs and just checking if there were within range.