with Ada.Text_IO; use Ada.Text_IO; with Ada.Containers.Vectors; procedure Day_2 is type Safety is (Unsafe, Safe); type Ordering is (Increasing, Decreasing, Equal); type Levels is array (Natural range <> ) of Integer; type Report is record Values : Levels(0 .. 9) := (others => 0); Count : Natural := 0; end record; type Reports is array (Natural range <>) of Report; type Orderings is array (Natural range <>) of Ordering; type Safeties is array (Natural range <>) of Safety; type Level_Report is record Order : Orderings( 0 .. 9 ) := (others => Equal); Diff : Levels( 0 .. 9 ) := (others => 0); Count : Natural := 0; end record; function Calculate_Levels( R : Report ) return Level_Report is Out_R : Level_Report; begin for I in 0 .. R.Count - 2 loop declare Diff : Integer := R.Values(I+1) - R.Values(I); begin if Diff > 0 then Out_R.Order(I) := Increasing; elsif Diff < 0 then Out_R.Order(I) := Decreasing; else Out_R.Order(I) := Equal; end if; Out_R.Diff(I) := abs(Diff); end; end loop; Out_R.Count := R.Count - 1; return Out_R; end Calculate_Levels; function Calculate_Report( Levels : Level_Report ) return Safety is begin if Levels.Diff(0) < 1 or Levels.Diff(0) > 3 then return Unsafe; end if; for I in 0 .. Levels.Count - 2 loop if not (Levels.Order(I+1) = Levels.Order(I)) then return Unsafe; end if; if Levels.Diff(I+1) < 1 or Levels.Diff(I+1) > 3 then return Unsafe; end if; end loop; if Levels.Order(0) = Equal then return Unsafe; end if; return Safe; end Calculate_Report; function Calculate_Report_Lossy( R : Report ) return Safety is Levels : Level_Report := Calculate_Levels(R); begin if Calculate_Report( Levels ) = Safe then return Safe; else for I in 0 .. R.Count - 1 loop declare New_Report : Report; begin for J in 0 .. I-1 loop New_Report.Values(J) := R.Values(J); end loop; for J in I+1 .. R.Count -1 loop New_Report.Values(J-1) := R.Values(J); end loop; New_Report.Count := R.Count - 1; Put_Line("Check level reduced report @" & Integer'Image(I)); Put_Line(R'Image); Put_Line(New_Report'Image); if Calculate_Report(Calculate_Levels( New_Report)) = Safe then return Safe; end if; end; end loop; return Unsafe; end if; end Calculate_Report_Lossy; function Get_Safe_Reports_Lossy( R : Reports ) return Natural is Sum : Natural := 0; begin for Rep of R loop declare Result : Safety := Calculate_Report_Lossy(Rep); begin if Result = Safe then Sum := @ + 1; end if; end; end loop; return Sum; end Get_Safe_Reports_Lossy; function Get_Safe_Reports( R : Reports ) return Natural is Sum : Natural := 0; begin for Rep of R loop declare Result : Safety := Calculate_Report(Calculate_Levels(Rep)); begin if Result = Safe then Sum := @ + 1; end if; end; end loop; return Sum; end Get_Safe_Reports; function ToNum( Num : String ) return Integer is begin return Integer'Value(Num); end ToNum; function Read_Report( Line : String ) return Report is In_Num : Boolean := False; Start_Num : Natural; Result : Report; begin for I in Line'Range loop case Line(I) is when '-' | '0' .. '9' => if not In_Num then In_Num := True; Start_Num := I; end if; when others => if In_Num then Result.Values(Result.Count) := ToNum(Line(Start_Num .. I-1)); Result.Count := @ + 1; In_Num := False; end if; end case; end loop; if In_Num then Result.Values(Result.Count) := ToNum(Line(Start_Num .. Line'Last)); Result.Count := @ + 1; end if; return Result; end Read_Report; function Read_File( File_Name : String ) return Reports is File : File_Type; package vec is new Ada.Containers.Vectors( Natural, Report ); use vec; Result : vec.Vector; begin Open( File, In_File, File_Name ); while not End_Of_File(File) loop Result.Append(Read_Report(Get_Line(File))); end loop; Close( File); return R : Reports( 0 .. Natural(Result.Length) - 1) do for I in Result.First_Index .. Result.Last_Index loop R(Natural(I)) := Result(Natural(I)); end loop; end return; end Read_File; File_Name : String := "input_day_2.txt"; begin Put_Line("Day 2 1:" & Get_Safe_Reports(Read_File(File_Name))'Image); Put_Line("Day 2 2:" & Get_Safe_Reports_Lossy(Read_File(File_Name))'Image); end Day_2;