-
Notifications
You must be signed in to change notification settings - Fork 0
/
day9_1.adb
91 lines (80 loc) · 2.5 KB
/
day9_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
with Advent_IO; use Advent_IO;
with Advent_IO.Integers; use Advent_IO.Integers;
with Ada.Unchecked_Conversion;
with Ada.Containers.Hashed_Sets;
with Ada.Containers;
with Str;
procedure Day9_1 is
type Position is record
Y, X : Integer;
end record;
function Hash (Element : Position)
return Ada.Containers.Hash_Type
is
use Ada.Containers;
function To_Hash_Type is new Ada.Unchecked_Conversion
(Integer, Hash_Type);
function Shift_Left
(N : Hash_Type;
Amount : Natural)
return Hash_Type
with Import, Convention => Intrinsic;
begin
return Shift_Left (To_Hash_Type (Element.X), 16) + To_Hash_Type (Element.Y);
end Hash;
package Position_Sets is new Ada.Containers.Hashed_Sets
(Element_Type => Position,
Hash => Hash,
Equivalent_Elements => "=");
use Position_Sets;
Visited : Set := Empty_Set;
Head, Tail : Position := (0, 0);
procedure Update_Tail is
function Adjacent
return Boolean
is (Tail.X in Head.X - 1 .. Head.X + 1 and then
Tail.Y in Head.Y - 1 .. Head.Y + 1);
begin
if not Adjacent then
if Tail.X < Head.X then
Tail.X := Tail.X + 1;
elsif Tail.X > Head.X then
Tail.X := Tail.X - 1;
end if;
if Tail.Y < Head.Y then
Tail.Y := Tail.Y + 1;
elsif Tail.Y > Head.Y then
Tail.Y := Tail.Y - 1;
end if;
end if;
end Update_Tail;
Direction : Character;
Count : Natural;
Num : String (1 .. 2);
Last : Natural;
begin
-- Allocate much more space than we need. One big malloc is faster than
-- lots of small ones.
Reserve_Capacity (Visited, Ada.Containers.Count_Type (Length (Input)));
Include (Visited, Tail);
while not End_Of_Input loop
Character'Read (Input, Direction);
Seek (Input, 1, Seek_Current); -- skip space
Read_Until (Input, ASCII.LF, Num, Last);
Count := Str.To_Natural (Num (1 .. Last));
for I in 1 .. Count loop
case Direction is
when 'U' => Head.Y := Head.Y + 1;
when 'D' => Head.Y := Head.Y - 1;
when 'L' => Head.X := Head.X - 1;
when 'R' => Head.X := Head.X + 1;
when others =>
raise Program_Error with "Invalid direction";
end case;
Update_Tail;
Include (Visited, Tail);
end loop;
end loop;
Put (Output, Natural (Length (Visited)));
New_Line (Output);
end Day9_1;