aoa_22_20220720.0.0_6d9ebd71/src/day14_2.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
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;