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