aoa_23_20230119.0.0_38d1c7e5/src/aoa_19_1.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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
with Ada.Containers.Indefinite_Hashed_Maps;
with Ada.Containers.Vectors;
with Ada.Strings.Fixed;
with Ada.Strings.Hash;
with Ada.Strings.Unbounded;
with Ada.Text_IO;
with PragmARC.Conversions.Unbounded_Strings;
with PragmARC.Line_Fields;

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

   type Category_ID is (Cool, Musical, Aerodynamic, Shiny); -- 'x', 'm', 'a', 's'

   function To_Category (Char : in Character) return Category_ID is
      (case Char is
       when 'x' => Cool,
       when 'm' => Musical,
       when 'a' => Aerodynamic,
       when 's' => Shiny,
       when others => raise Program_Error with "Invalid category character " & Char);

   type Rule_Info (Test : Boolean := False) is record
      Next_Rule : Unbounded_String;

      case Test is
      when False =>
         null;
      when True =>
         Category : Category_ID;
         Operator : Character;
         Value    : Natural;
      end case;
   end record;

   package Rule_Lists is new Ada.Containers.Vectors (Index_Type => Positive, Element_Type => Rule_Info);
   package Workflows is new Ada.Containers.Indefinite_Hashed_Maps (Key_Type        => String,
                                                                   Element_Type    => Rule_Lists.Vector,
                                                                   Hash            => Ada.Strings.Hash,
                                                                   Equivalent_Keys => "=",
                                                                   "="             => Rule_Lists."=");

   type Part_Map is array (Category_ID) of Natural;

   Input : Ada.Text_IO.File_Type;
   Map   : Workflows.Map;
   Sum   : Natural := 0;
begin -- AOA_19_1
   Ada.Text_IO.Open (File => Input, Mode => Ada.Text_IO.In_File, Name => "input_19");

   Read_Workflows : loop
      One_Flow : declare
         Line : constant String := Ada.Text_IO.Get_Line (Input);

         Brace : Natural;
         List  : PragmARC.Line_Fields.Line_Field_Info;
         Colon : Natural;
         Rule  : Rule_Lists.Vector;
      begin -- One_Flow
         exit Read_Workflows when Line = "";

         Brace := Ada.Strings.Fixed.Index (Line, "{");
         List := PragmARC.Line_Fields.Parsed (Line (Brace + 1 .. Line'Last - 1), ',');

         All_Rules : for I in 1 .. List.Field.Last_Index loop
            One_Rule : declare
               Field : constant String := +List.Field.Element (I);
            begin -- One_Rule
               Colon := Ada.Strings.Fixed.Index (Field, ":");

               if Colon = 0 then
                  Rule.Append (New_Item => (Test => False, Next_Rule => +Field) );
               else
                  Rule.Append (New_Item => (Test      => True,
                                            Next_Rule => +Field (Colon + 1 .. Field'Last),
                                            Category => To_Category (Field (1) ),
                                            Operator => Field (2),
                                            Value    => Integer'Value (Field (3 .. Colon - 1) ) ) );
               end if;
            end One_Rule;
         end loop All_Rules;

         Map.Insert (Key => Line (1 .. Brace - 1), New_Item => Rule);
      end One_Flow;
   end loop Read_Workflows;

   All_Parts : loop
      exit All_Parts when Ada.Text_IO.End_Of_File (Input);

      One_Part : declare
         Line : constant String := Ada.Text_IO.Get_Line (Input);
         Field : constant PragmARC.Line_Fields.Line_Field_Info := PragmARC.Line_Fields.Parsed (Line (2 .. Line'Last - 1), ',');

         Part : Part_Map;
         Next : Unbounded_String := +"in";
         Flow : Rule_Lists.Vector;
         Rule : Rule_Info;
         Test : Boolean := False;
      begin -- One_Part
         All_Categories : for I in 1 .. Field.Field.Last_Index loop
            One_Category : declare
               Assoc : constant String := +Field.Field.Element (I);
            begin -- One_Category
               Part (To_Category (Assoc (1) ) ) := Integer'Value (Assoc (3 .. Assoc'Last) );
            end One_Category;
         end loop All_Categories;

         All_Flows : loop
            Flow := Map.Element (+Next);

            Flow_Rules : for I in 1 .. Flow.Last_Index loop
               Rule := Flow.Element (I);

               if Rule.Test then
                  if Rule.Operator = '<' then
                     Test := Part (Rule.Category) < Rule.Value;
                  else
                     Test := Part (Rule.Category) > Rule.Value;
                  end if;
               end if;

               if Test or not Rule.Test then
                  Next := Rule.Next_Rule;

                  exit All_Flows when Next = "R";

                  if Next = "A" then
                     Sum_Values : for Category in Part'Range loop
                        Sum := Sum + Part (Category);
                     end loop Sum_Values;

                     exit All_Flows;
                  end if;

                  exit Flow_Rules;
               end if;

               if I = Flow.Last_Index then
                  raise Program_Error with "Invalid flow with no matching rule";
               end if;
            end loop Flow_Rules;
         end loop All_Flows;
      end One_Part;
   end loop All_Parts;

   Ada.Text_IO.Close (File => Input);
   Ada.Text_IO.Put_Line (Item => Sum'Image);
end AOA_19_1;