aoa_23_20230119.0.0_38d1c7e5/src/aoa_15_2.adb

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
with Ada.Containers.Vectors;
with Ada.Strings.Unbounded;
with Ada.Text_IO;
with PragmARC.Conversions.Unbounded_Strings;
with PragmARC.Line_Fields;

procedure AOA_15_2 is
   use Ada.Strings.Unbounded;
   use PragmARC.Conversions.Unbounded_Strings;

   function Sum_Powers (Line : in String) return Natural;
   -- Divides Line into substrings separated by commas, uses them to fill a map of lenses, and returns the sum of the powers of
   -- the mapped lenses

   function Sum_Powers (Line : in String) return Natural is
      type Hash_Value is mod 256;

      subtype Focal_Length is Integer range 1 .. 9;

      type Lens_Info is record
         ID     : Unbounded_String;
         Length : Focal_Length;
      end record;

      function "=" (Left : in Lens_Info; Right : in Lens_Info) return Boolean is
         (Left.ID = Right.ID);

      package Lens_Lists is new Ada.Containers.Vectors (Index_Type => Positive, Element_Type => Lens_Info);
      type Lens_Map is array (Hash_Value) of Lens_Lists.Vector;

      function Hash (Line : in String) return Hash_Value;
      -- Returns the HASH algorithm result for Line

      function Hash (Line : in String) return Hash_Value is
         Result : Hash_Value := 0;
      begin -- Hash
         All_Chars : for C of Line loop
            Result := 17 * (Result + Character'Pos (C) );
         end loop All_Chars;

         return Result;
      end Hash;

      Field : constant PragmARC.Line_Fields.Line_Field_Info := PragmARC.Line_Fields.Parsed (Line, ',');

      Map : Lens_Map;
      Sum : Natural := 0;
   begin -- Sum_Powers
      All_Fields : for I in 1 .. Field.Field.Last_Index loop
         One_Field : declare
            Line : constant String := +Field.Field.Element (I);

            Sep  : Positive;
            Box  : Hash_Value;
            Lens : Lens_Info;
            Idx  : Natural;
         begin -- One_Field
            Sep := (if Line (Line'Last) = '-' then Line'Last else Line'Last - 1);
            Box := Hash (Line (Line'First .. Sep - 1) );
            Lens := (ID => +Line (Line'First .. Sep - 1),
                     Length => (if Line (Sep) = '=' then Integer'Value (Line (Sep + 1 .. Sep + 1) ) else 1) );
            Idx := Map (Box).Find_Index (Lens);

            if Line (Sep) = '=' then
               if Idx = 0 then
                  Map (Box).Append (New_Item => Lens);
               else
                  Map (Box).Replace_Element (Index => Idx, New_Item => Lens);
               end if;
            elsif Idx > 0 then
               Map (Box).Delete (Index => Idx);
            else
               null;
            end if;
         end One_Field;
      end loop All_Fields;

      All_Boxes : for B in Map'Range loop
         All_Lenses : for I in 1 .. Map (B).Last_Index loop
            Sum := Sum + (Integer (B) + 1) * I * Map (B).Element (I).Length;
         end loop All_Lenses;
      end loop All_Boxes;

      return Sum;
   end Sum_Powers;

   Test_Input  : constant String := "rn=1,cm-,qp=3,cm=2,qp-,pc=4,ot=9,ab=5,pc-,pc=6,ot=7";
   Test_Result : constant        := 145;

   Input : Ada.Text_IO.File_Type;
   Sum   : Natural;
begin -- AOA_15_2
   Sum := Sum_Powers (Test_Input);
   Ada.Text_IO.Put_Line (Item => Sum'Image);

   if Sum = Test_Result then
      Ada.Text_IO.Open (File => Input, Mode => Ada.Text_IO.In_File, Name => "input_15");
      Sum := Sum_Powers (Ada.Text_IO.Get_Line (Input) );
      Ada.Text_IO.Close (File => Input);
      Ada.Text_IO.Put_Line (Item => Sum'Image);
   end if;
end AOA_15_2;