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 | with Ada.Strings.Fixed;
with Ada.Text_IO;
procedure Day14_2 is
subtype X_Value is Integer range 0 .. 1000;
subtype Y_Value is Integer range 0 .. 168;
procedure Extract_Point (From : in String; X : out X_Value; Y : out Y_Value; Last : out Positive);
-- Parses "mmm,nnn" from From, putting mmm in X and nnn in Y
-- "nnn" is terminated by a space or the end of From
-- Finished is True if "nnn" is terminated by the end of From; False if it's terminated by a space
procedure Extract_Point (From : in String; X : out X_Value; Y : out Y_Value; Last : out Positive) is
Stop : Natural := Ada.Strings.Fixed.Index (From, ",") - 1;
Start : Positive;
begin -- Extract_Point
X := Integer'Value (From (From'First .. Stop) );
Start := Stop + 2;
Stop := Ada.Strings.Fixed.Index (From (Start .. From'Last), " ");
Stop := (if Stop = 0 then From'Last else Stop - 1);
Last := Stop;
Y := Integer'Value (From (Start .. Stop) );
end Extract_Point;
type Tile_ID is (Air, Rock, Sand);
type Cave_Map is array (X_Value, Y_Value) of Tile_ID;
Input : Ada.Text_IO.File_Type;
Cave : Cave_Map := (others => (Y_Value'Last => Rock, others => Air) );
X : Natural;
Y : Natural;
Count : Natural := 0;
begin -- Day14_2
Ada.Text_IO.Open (File => Input, Mode => Ada.Text_IO.In_File, Name => "input_14");
All_Paths : loop
exit All_Paths when Ada.Text_IO.End_Of_File (Input);
One_Path : declare
Line : constant String := Ada.Text_IO.Get_Line (Input);
From_X : X_Value;
From_Y : Y_Value;
Last : Positive;
To_X : X_Value;
To_Y : Y_Value;
begin -- One_Path
Extract_Point (From => Line, X => From_X, Y => From_Y, Last => Last);
All_Lines : loop
exit All_Lines when Last >= Line'Last;
Extract_Point (From => Line (Last + 5 .. Line'Last), X => To_X, Y => To_Y, Last => Last);
if From_X = To_X then -- Vertical
Vert_Rock : for Y in Integer'Min (From_Y, To_Y) .. Integer'Max (From_Y, To_Y) loop
Cave (From_X, Y) := Rock;
end loop Vert_Rock;
else -- Horizontal
Horiz_Rock : for X in Integer'Min (From_X, To_X) .. Integer'Max (From_X, To_X) loop
Cave (X, From_Y) := Rock;
end loop Horiz_Rock;
end if;
From_X := To_X;
From_Y := To_Y;
end loop All_Lines;
end One_Path;
end loop All_Paths;
Ada.Text_IO.Close (File => Input);
All_Grains : loop
X := 500;
Y := 0;
-- Ada.Text_IO.Put_Line("grain"&Count'Image&" at"&X'Image&Y'Image);
exit All_Grains when Cave (X, Y) /= Air;
Count := Count + 1;
All_Motions : loop
-- Ada.Text_IO.Put_Line(" falling");
Fall : loop
exit Fall when Cave (X, Y + 1) /= Air;
Y := Y + 1;
-- Ada.Text_IO.Put_Line(" grain at"&X'Image&Y'Image);
end loop Fall;
-- Ada.Text_IO.Put_Line(" fall ended");
if X <= X_Value'First then
Ada.Text_IO.Put_Line (Item => "Min X too large");
exit All_Grains;
elsif Cave (X - 1, Y + 1) = Air then
X := X - 1;
Y := Y + 1;
-- Ada.Text_IO.Put_Line(" moved left"&X'Image&Y'Image);
elsif X >= X_Value'Last then
Ada.Text_IO.Put_Line (Item => "Max X too small");
exit All_Grains;
elsif Cave (X + 1, Y + 1) = Air then
X := X + 1;
Y := Y + 1;
-- Ada.Text_IO.Put_Line(" moved right"&X'Image&Y'Image);
else
-- Ada.Text_IO.Put_Line(" motion ended");
Cave (X, Y) := Sand;
exit All_Motions;
end if;
end loop All_Motions;
end loop All_Grains;
Ada.Text_IO.Put_Line (Item => Count'Image);
-- for Y in Cave'Range (2) loop
-- for X in Cave'Range (1) loop
-- case Cave(X,Y) is
-- when Air =>
-- Ada.Text_IO.Put('.');
-- when Rock =>
-- Ada.Text_IO.Put('#');
-- when Sand =>
-- Ada.Text_IO.Put('o');
-- end case;
-- end loop;
-- Ada.Text_IO.New_Line;
-- end loop;
end Day14_2;
|