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 | with Ada.Strings.Fixed;
with Ada.Text_IO;
procedure Day14_1 is
subtype X_Value is Integer range 450 .. 520;
subtype Y_Value is Integer range 0 .. 170;
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 => (others => Air) );
X : Positive;
Y : Natural;
Count : Natural := 0;
begin -- Day14_1
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;
Count := Count + 1;
-- Ada.Text_IO.Put_Line("grain"&Count'Image&" at"&X'Image&Y'Image);
exit All_Grains when Cave (X, Y) /= Air;
All_Motions : loop
-- Ada.Text_IO.Put_Line(" falling");
Fall : loop
exit All_Grains when Y >= Y_Value'Last;
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 and then 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 and then 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 => Integer'Image (Count - 1) );
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_1;
|