with Ada.Text_IO; use Ada.Text_IO; with Ada.Numerics.Elementary_Functions; use Ada.Numerics.Elementary_Functions; with Ada.Containers.Generic_Array_Sort; with Ada.Containers.Vectors; procedure Day_1 is type Index is new Natural; type Input is array ( Index range <>) of Integer; type Count is new Natural; type Counted_Data is record Data : Integer; Data_Count : Count; end record; type Count_Array is array (Index range <> ) of Counted_Data; function Day_1_1( Left, Right : Input ) return Integer is Sorted_Left : Input := Left; Sorted_Right : Input := Right; Score : Integer := 0; procedure Sort is new Ada.Containers.Generic_Array_Sort(Index, Integer, Input); begin Sort(Sorted_Left); Sort(Sorted_Right); for I in Sorted_Left'Range loop Score := @ + abs(Sorted_Left(I) - Sorted_Right(I)); end loop; return Score; end Day_1_1; function Sort_And_Deduplicate( Arr : Input ) return Count_Array is Sorted : Input := Arr; Out_Arr : Count_Array( Index'First .. Arr'Length ); Arr_Index : Index := Index'First; In_Index : Index := Index'First; procedure Sort is new Ada.Containers.Generic_Array_Sort(Index, Integer, Input); begin Sort(Sorted); Out_Arr(Arr_Index).Data := Sorted(Index'First); Out_Arr(Arr_Index).Data_Count := 0; for I in Index'First .. (Index'First + Arr'Length - 1) loop if( Sorted(I) = Out_Arr(Arr_Index).Data) then Out_Arr(Arr_Index).Data_Count := @ + 1; else Arr_Index := @ + 1; Out_Arr(Arr_Index).Data := Sorted(I); Out_Arr(Arr_Index).Data_Count := 1; end if; end loop; return Out_Con : Count_Array(Index'First .. Arr_Index) do for I in Index'First .. Arr_Index loop Out_Con(I) := Out_Arr(I); end loop; end return; end Sort_And_Deduplicate; function Find( Num : Integer; Arr : Count_Array ) return Count is Lower_Bound : Index := Index'First; Upper_Bound : Index := Arr'Length - 1; Upper : Integer := 1 + Integer(Log(Float(Arr'Length), 2.0)); Mid : Index; begin for I in 0 .. Upper loop if Upper_Bound - Lower_Bound <= 1 then if Num = Arr(Upper_Bound).Data then return Arr(Upper_Bound).Data_Count; elsif Num = Arr(Upper_Bound).Data then return Arr(Upper_Bound).Data_Count; else return 0; end if; end if; Mid := (Upper_Bound + Lower_Bound) / 2; if Num > Arr(Mid).Data then Lower_Bound := Mid; elsif Num < Arr(Mid).Data then Upper_Bound := Mid; else return Arr(Mid).Data_Count; end if; end loop; return 0; end Find; function Day_1_2( Left, Right : Input ) return Integer is C_Left : Count_Array := Sort_And_Deduplicate(Left); C_Right : Count_Array := Sort_And_Deduplicate(Right); Score : Integer := 0; begin for I in C_Left'Range loop declare D : Integer := Integer(Find(C_Left(I).Data, C_Right)); C : Integer := Integer(C_Left(I).Data_Count); begin Score := @ + D * C * C_Left(I).Data; end; end loop; return Score; end Day_1_2; type Array2( Count : Index ) is record Left : Input( 0 .. Count); Right : Input( 0 .. Count); end record; function Read_Arrays_Into_File( Filename : String ) return Array2 is File : File_Type; package Vec is new Ada.Containers.Vectors( Index, Integer ); use Vec; Left : Vec.Vector; Right : Vec.Vector; begin Open(File, In_File, Filename); while not End_Of_File(File) loop declare Line : String := Get_Line(File); Start_First : Integer := Line'First; End_First : Integer := 0; Start_Second : Integer := 0; End_Second : Integer := Line'Last; Index : Integer := Line'First; begin while Line(Index) /= ' ' loop Index := @ + 1; end loop; End_First := Index - 1; while Line(Index) = ' ' loop Index := @ + 1; end loop; Start_Second := Index; Left.Append( Integer'Value(Line(Start_First .. End_First))); Right.Append( Integer'Value(Line(Start_Second .. End_Second))); end; end loop; Close(File); return Out_Arr : Array2( Index(Left.Length) ) do for I in Left.First_Index .. Left.Last_Index loop Out_Arr.Left(I) := Left(I); Out_Arr.Right(I) := Right(I); end loop; end return; end Read_Arrays_Into_File; Filename : String := "input_day_1_1.txt"; Data : Array2 := Read_Arrays_Into_File(Filename); begin Put_Line("Sum score: " & Day_1_1(Data.Left, Data.Right)'Image); Put_Line("Simi score: " & Day_1_2(Data.Left, Data.Right)'Image); end Day_1;