-
Notifications
You must be signed in to change notification settings - Fork 0
/
day2.adb
151 lines (122 loc) · 4.34 KB
/
day2.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
150
151
with Ada.Text_IO;
with GNAT.String_Split;
procedure Day2
with SPARK_Mode => On
is
type Opcode is
(Add,
Multiply,
Halt,
Error);
subtype Operation is Opcode range Add .. Multiply;
function Int_To_Opcode (Int : Integer) return Opcode is
(case Int is
when 1 => Add,
when 2 => Multiply,
when 99 => Halt,
when others => Error);
procedure Split_To_Array (Split : GNAT.String_Split.Slice_Set)
is
-- Create type to hold the program. Slice_Count needs - 1 because
-- we start from position 0, but slice_count starts from 1.
type Program_T is array
(Natural range 0 .. Natural
(GNAT.String_Split.Slice_Count (Split)) - 1) of Integer;
procedure Run_Program
(Prog : in Program_T;
Result : out Natural)
is
--------------------------------------------------------------
-- Perform_Op: --
-- Performs an operation Store := Left OP Right. --
-- For convenience, also returns a result. --
-- Given the day 2 hint, increment the Program Counter. --
--------------------------------------------------------------
procedure Perform_Op
(Operand : in Operation;
Left : in Natural;
Right : in Natural;
PC : in out Natural;
Store : out Natural;
Result : out Natural)
is
begin
case Operand is
when Add =>
Result := Left + Right;
PC := PC + 4;
when Multiply =>
Result := Left * Right;
PC := PC + 4;
end case;
Store := Result;
end Perform_Op;
Current_Opcode : Opcode;
Program_Counter : Natural := 0;
Program : Program_T := Prog;
begin
while Program_Counter <= Program'Last loop
Current_Opcode := Int_To_Opcode (Program(Program_Counter));
case Current_Opcode is
when Operation =>
-- Do something
Perform_Op
(Operand => Current_Opcode,
Left => Program(Program(Program_Counter + 1)),
Right => Program(Program(Program_Counter + 2)),
PC => Program_Counter,
Store => Program(Program(Program_Counter + 3)),
Result => Result);
when Halt =>
exit;
when Error =>
Ada.Text_IO.Put_Line("Oops.");
end case;
end loop;
end Run_Program;
Program : Program_T;
Result : Natural;
Desired_Result : constant Natural := 19690720;
begin
for I in Program'Range loop
-- Slice_Number 0 is the input string (i.e. everything), so skip it.
Program (I) := Natural'Value
(GNAT.String_Split.Slice
(Split, GNAT.String_Split.Slice_Number(I + 1)));
end loop;
-- So we now have Program, which contains our... program?
-- Let's try to run it.
-- Part 1:
-- Patch it
Program (1) := 12;
Program (2) := 2;
Run_Program (Program, Result);
Ada.Text_IO.Put_Line("Part 1:" & Result'Image);
-- Part 2: Find Nounphrase/Verbphrase
Main_Loop :
for Noun in Natural range 0 .. 99 loop
for Verb in Natural range 0 .. 99 loop
Program (1) := Noun;
Program (2) := Verb;
Run_Program (Program, Result);
if Result = Desired_Result then
Ada.Text_IO.Put_Line("Part 2:" & Noun'Image & Verb'Image);
exit Main_Loop;
end if;
end loop;
end loop Main_Loop;
end Split_To_Array;
Input_Split : GNAT.String_Split.Slice_Set;
begin
loop
declare
Line : constant String := Ada.Text_IO.Get_Line;
begin
GNAT.String_Split.Create(From => Line,
Separators => ",",
S => Input_Split);
Split_To_Array(Input_Split);
exit when Ada.Text_IO.End_Of_File;
end;
end loop;
end Day2;