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;