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
150
151
152
153
154
155
156
157
158 | with Ada.Containers.Vectors;
with Ada.Strings.Fixed;
with Ada.Text_IO;
with PragmARC.Math;
procedure Day11_2 is
subtype Monkey_ID is Integer range 0 .. 7;
package Item_Lists is new Ada.Containers.Vectors (Index_Type => Positive, Element_Type => Natural);
type Operand_Info (Self : Boolean := True) is record
case Self is
when False =>
Value : Natural;
when True =>
null;
end case;
end record;
type Destination_List is array (Boolean) of Monkey_ID;
type U64 is mod 2 ** 64;
type Monkey_Info is record
Item : Item_Lists.Vector;
Operation : Character;
Operand : Operand_Info;
Modulus : Natural;
Destination : Destination_List;
Inspections : U64 := 0;
end record;
type Monkey_List is array (Monkey_ID) of Monkey_Info;
procedure Apply_Round (ID : in Monkey_ID; Monkey : in out Monkey_List);
-- Performs a round for monkey ID, emptying Item and updating Inspections
LCM : Natural;
procedure Apply_Round (ID : in Monkey_ID; Monkey : in out Monkey_List) is
Item : Natural;
Operand : Natural;
begin -- Apply_Round
All_Items : loop
exit All_Items when Monkey (ID).Item.Is_Empty;
Item := Monkey (ID).Item.First_Element;
Monkey (ID).Item.Delete_First;
Monkey (ID).Inspections := Monkey (ID).Inspections + 1;
Operand := (if Monkey (ID).Operand.Self then Item else Monkey (ID).Operand.Value);
if Monkey (ID).Operation = '+' then
Item := (Item + Operand) rem LCM;
else
Item := (Item * Operand) rem LCM;
end if;
Monkey (Monkey (ID).Destination (Item rem Monkey (ID).Modulus = 0) ).Item.Append (New_Item => Item);
end loop All_Items;
end Apply_Round;
type Max_Info is record
ID : Monkey_ID;
Value : U64 := 0;
end record;
Input : Ada.Text_IO.File_Type;
Monkey : Monkey_List;
Max_1 : Max_Info;
Max_2 : Max_Info;
begin -- Day11_2
Ada.Text_IO.Open (File => Input, Mode => Ada.Text_IO.In_File, Name => "input_11");
Read_Monkeys : for ID in Monkey'Range loop
exit Read_Monkeys when Ada.Text_IO.End_Of_File (Input);
All_Lines : for L in 1 .. 7 loop
exit Read_Monkeys when ID = Monkey'Last and L = 7;
One_Line : declare
Line : constant String := Ada.Text_IO.Get_Line (Input);
begin -- One_Line
case L is
when 1 | 7 => -- Monkey # & final null line; ignore
null;
when 2 => -- Item list
Parse_List : declare
Start : Positive := Ada.Strings.Fixed.Index (Line, ":") + 1;
Stop : Natural;
begin -- Parse_List
Parse_All : loop
exit Parse_All when Start not in Line'Range;
Stop := Ada.Strings.Fixed.Index (Line (Start .. Line'Last), ",");
Stop := (if Stop = 0 then Line'Last else Stop - 1);
Monkey (ID).Item.Append (New_Item => Natural'Value (Line (Start .. Stop) ) );
Start := Stop + 2;
end loop Parse_All;
end Parse_List;
when 3 => -- Operation & operand
Parse_Op : declare
Pos : constant Positive := Ada.Strings.Fixed.Index (Line, "old") + 4; -- Operator position
begin -- Parse_Op
Monkey (ID).Operation := Line (Pos);
if Line (Pos + 2) = 'o' then -- Operand is "old"
Monkey (ID).Operand := (Self => True);
else -- Operand is a number
Monkey (ID).Operand := (Self => False, Value => Natural'Value (Line (Pos + 2 .. Line'Last) ) );
end if;
end Parse_Op;
when 4 => -- Modulus
Parse_Mod : declare
Pos : constant Positive := Ada.Strings.Fixed.Index (Line, " ", Going => Ada.Strings.Backward);
begin -- Parse_Mod
Monkey (ID).Modulus := Natural'Value (Line (Pos .. Line'Last) );
end Parse_Mod;
when 5 .. 6 => -- Destinations
Parse_Dest : declare
Pos : constant Positive := Ada.Strings.Fixed.Index (Line, " ", Going => Ada.Strings.Backward);
begin -- Parse_Dest
Monkey (ID).Destination (L = 5) := Integer'Value (Line (Pos .. Line'Last) );
end Parse_Dest;
end case;
end One_Line;
end loop All_Lines;
end loop Read_Monkeys;
Ada.Text_IO.Close (File => Input);
LCM := Monkey (Monkey'First).Modulus;
Find_LCM : for ID in Monkey'First + 1 .. Monkey'Last loop
LCM := PragmARC.Math.LCM (Monkey(ID).Modulus, LCM);
end loop Find_LCM;
All_Rounds : for R in 1 .. 10_000 loop
All_Monkeys : for ID in Monkey'Range loop
Apply_Round (ID => ID, Monkey => Monkey);
end loop All_Monkeys;
end loop All_Rounds;
Find_1 : for ID in Monkey'Range loop
if Monkey (ID).Inspections > Max_1.Value then
Max_1 := (ID => ID, Value => Monkey (ID).Inspections);
end if;
end loop Find_1;
Find_2 : for ID in Monkey'Range loop
if ID /= Max_1.ID and Monkey (ID).Inspections > Max_2.Value then
Max_2 := (ID => ID, Value => Monkey (ID).Inspections);
end if;
end loop Find_2;
Ada.Text_IO.Put_Line (Item => Max_1.ID'Image & Max_1.Value'Image);
Ada.Text_IO.Put_Line (Item => Max_2.ID'Image & Max_2.Value'Image);
Ada.Text_IO.Put_Line (Item => U64'Image (Max_1.Value * Max_2.Value) );
end Day11_2;
|