2023 Day 6: Wait For It

Didn’t see a thread for this yet, so figured I would start one. I’ve only worked on part 1. I did like that I could come up with various methods of doing this right off the bat. I decided on an algorithmic approach .

Yes, there are various methods to solve this problem.
I also followed an algorithmic approach for part 1, just for fun. I solved part two with the bc calculator: sqrt(T^2-4*D).

1 Like

I solved both approaches with the quadratic formula (@rocher what calls the bc calculator is part of it). The difficulties I had with this problem are that it’s been so long since I used Ada’s digits type and the Numerics.Elementary_Functions crate that I had to spend some time reading up on those, experimenting with them, and, once the inevitable bug arose, figuring out what I’d misunderstood.

My general solution:

I kept the times and distances as integers to make the math at the end a bit easier (comparing floats has a lot of edge cases to consider). I converted them all to Floats for the quadratic equation match, found the X intercepts, rounded the result (casting rounds in Ada), use the integer version of the X intercepts to calculate the corresponding distance and then compared the distances to the record to see if the x intercepts rounded past the values I needed (in which case I adjusted them).

   type Race_Time is new Positive;
   type Race_Distance is new Positive;
   type Ways_To_Win is new Natural;

   -- Calculation that lets all execptions propagate
   function Calculate_Ways_To_Win_Unhandled
      (Max_Time        : Race_Time;
       Distance_Record : Race_Distance)
       return Ways_To_Win
   is 

      -- Hold time can never be 0 nor can it be the maximum time
      -- or the boat would never move
      subtype Hold_Time is Race_Time range 1..Max_Time-1;

      -- (Max_Time - Hold_Time) * Hold_Time > Distance_Record
      --
      -- -(Hold_Time**2) + Max_Time * Hold_Time - Distance_Record > 0
      --
      --    -B +- SQRT(B**2 - 4*A*C)
      -- => ------------------------ = X intercepts
      --             2*A
      -- Where:
      --    A = -1
      --    B = Max_Time
      --    C = - (Distance_Record)
      --
      -- Inverted quadratic means all integer values between X intercepts are
      -- win conditions
      A : constant       := -1.0;
      B : constant Float := Float(Max_Time);
      C : constant Float := -1.0 * Float(Distance_Record);
      Square_Root : constant Float := Sqrt((B**2) - (4.0  * A * C));

      -- Calculate X intercepts as rounded integers, where X is the hold time
      -- Values may be outside the range of Hold_Time initially, so temporarily
      -- use Hold_Time'Base for intermediate calculations.  Note that converting
      -- from Float to Hold_Time'Base does a rounding operation
      x1 : constant Hold_Time'Base := Hold_Time'Base((((-1.0) * B) + Square_Root ) / (2.0 * A));
      x2 : constant Hold_Time'Base := Hold_Time'Base((((-1.0) * B) - Square_Root ) / (2.0 * A));

      -- Calculate corresponding y values for integer x intercepts
      -- Values may be outside the range of Race_Distance initially, so temporarily
      -- use Race_Distance'Base for intermediate calculations
      x1_Distance : constant Race_Distance'Base := Race_Distance'Base((Max_Time - x1) * x1);
      x2_Distance : constant Race_Distance'Base := Race_Distance'Base((Max_Time - x2) * x2);

      -- Rounding may have pushed x1 and x2 out of range.
      -- Adjust values based on how y values compared to the record
      -- This assignment should ensure the results are in the correct
      -- range of the Hold_Time type.
      First : constant Hold_Time := 
         (if x1_Distance > Distance_Record then
            x1
          else
            x1 + 1); -- A little too far left, so adjust
      Last  : constant Hold_Time :=
         (if x2_Distance > Distance_Record then
            x2
          else
            x2 - 1); -- A little too far right, so adjust
   begin
      -- since these are essentially integers, the number of ways to win
      -- is just the number of integers in the range of values
      -- or the length of the range;
      return Ways_To_Win((Last - First) + 1);
   end Calculate_Ways_To_Win_Unhandled;

   function Calculate_Ways_To_Win
      (Max_Time        : Race_Time;
       Distance_Record : Race_Distance)
       return Ways_To_Win
   is begin
      return Calculate_Ways_To_Win_Unhandled
         (Max_Time        => Max_Time,
          Distance_Record => Distance_Record);
   exception
      when others => return 0;  -- Means no solution
   end Calculate_Ways_To_Win;

Yep, that was my approach