Assume an array of cells with an initial distribution of live and dead cells,
and imaginary cells off the end of the array having fixed values.

Cells in the next generation of the array are calculated based on the value of the cell and its left and right nearest neighbours in the current generation.

If, in the following table, a live cell is represented by 1 and a dead cell by 0 then to generate the value of the cell at a particular index in the array of cellular values you use the following table:

000 -> 0  # 
001 -> 0  #
010 -> 0  # Dies without enough neighbours
011 -> 1  # Needs one neighbour to survive
100 -> 0  #
101 -> 1  # Two neighbours giving birth
110 -> 1  # Needs one neighbour to survive
111 -> 0  # Starved to death.

with Ada.Text_IO;  use Ada.Text_IO;
 
procedure Cellular_Automata is
   type Petri_Dish is array (Positive range <>) of Boolean;
 
   procedure Step (Culture : in out Petri_Dish) is
      Left  : Boolean := False;
      This  : Boolean;
      Right : Boolean;
   begin
      for Index in Culture'First..Culture'Last - 1 loop
         Right := Culture (Index + 1);
         This  := Culture (Index);
         Culture (Index) := (This and (Left xor Right)) or (not This and Left and Right);
         Left := This;
      end loop;
      Culture (Culture'Last) := Culture (Culture'Last) and not Left;
   end Step;
 
   procedure Put (Culture : Petri_Dish) is
   begin
      for Index in Culture'Range loop
         if Culture (Index) then
            Put ('#');
         else
            Put ('_');
         end if;
      end loop;
   end Put;
 
   Culture : Petri_Dish :=
      (  False, True, True,  True, False, True,  True, False, True, False, True,
         False, True, False, True, False, False, True, False, False
      );
begin
   for Generation in 0..9 loop
      Put ("Generation" & Integer'Image (Generation) & ' ');
      Put (Culture);
      New_Line;
      Step (Culture);
   end loop;
end Cellular_Automata;