173 lines
5.4 KiB
Ada
173 lines
5.4 KiB
Ada
with Ada.Numerics.Discrete_Random;
|
|
with Ada.Text_IO;
|
|
|
|
package body Mazes is
|
|
package RNG is new Ada.Numerics.Discrete_Random (Positive);
|
|
package Random_Direction is new Ada.Numerics.Discrete_Random (Directions);
|
|
|
|
Generator : RNG.Generator;
|
|
Dir_Generator : Random_Direction.Generator;
|
|
|
|
function "-" (Dir : Directions) return Directions is
|
|
begin
|
|
case Dir is
|
|
when North =>
|
|
return South;
|
|
when South =>
|
|
return North;
|
|
when East =>
|
|
return West;
|
|
when West =>
|
|
return East;
|
|
end case;
|
|
end "-";
|
|
|
|
procedure Move
|
|
(Row : in out Height_Type;
|
|
Column : in out Width_Type;
|
|
Direction : Directions;
|
|
Valid_Move : out Boolean)
|
|
is
|
|
begin
|
|
Valid_Move := False;
|
|
case Direction is
|
|
when North =>
|
|
if Row > Height_Type'First then
|
|
Valid_Move := True;
|
|
Row := Row - 1;
|
|
end if;
|
|
when East =>
|
|
if Column < Width_Type'Last then
|
|
Valid_Move := True;
|
|
Column := Column + 1;
|
|
end if;
|
|
when West =>
|
|
if Column > Width_Type'First then
|
|
Valid_Move := True;
|
|
Column := Column - 1;
|
|
end if;
|
|
when South =>
|
|
if Row < Height_Type'Last then
|
|
Valid_Move := True;
|
|
Row := Row + 1;
|
|
end if;
|
|
end case;
|
|
end Move;
|
|
|
|
procedure Depth_First_Algorithm
|
|
(Maze : in out Maze_Grid;
|
|
Row : Height_Type;
|
|
Column : Width_Type)
|
|
is
|
|
Next_Row : Height_Type;
|
|
Next_Column : Width_Type;
|
|
Next_Direction : Directions;
|
|
Valid_Direction : Boolean;
|
|
Tested_Wall : array (Directions) of Boolean := (others => False);
|
|
All_Tested : Boolean;
|
|
begin
|
|
-- mark as visited
|
|
Maze (Row, Column).Visited := True;
|
|
loop
|
|
-- use random direction
|
|
loop
|
|
Next_Direction := Random_Direction.Random (Dir_Generator);
|
|
exit when not Tested_Wall (Next_Direction);
|
|
end loop;
|
|
Next_Row := Row;
|
|
Next_Column := Column;
|
|
Move (Next_Row, Next_Column, Next_Direction, Valid_Direction);
|
|
if Valid_Direction then
|
|
if not Maze (Next_Row, Next_Column).Visited then
|
|
-- connect the two cells
|
|
Maze (Row, Column).Walls (Next_Direction) :=
|
|
False;
|
|
Maze (Next_Row, Next_Column).Walls (-Next_Direction) :=
|
|
False;
|
|
Depth_First_Algorithm (Maze, Next_Row, Next_Column);
|
|
end if;
|
|
end if;
|
|
Tested_Wall (Next_Direction) := True;
|
|
-- continue as long as there are unvisited neighbours left
|
|
All_Tested := True;
|
|
for D in Directions loop
|
|
All_Tested := All_Tested and Tested_Wall (D);
|
|
end loop;
|
|
-- all directions are either visited (from here,
|
|
-- or previously visited), or invalid.
|
|
exit when All_Tested;
|
|
end loop;
|
|
end Depth_First_Algorithm;
|
|
|
|
procedure Initialize (Maze : in out Maze_Grid) is
|
|
Row, Column : Positive;
|
|
begin
|
|
-- initialize random generators
|
|
RNG.Reset (Generator);
|
|
Random_Direction.Reset (Dir_Generator);
|
|
-- choose starting cell
|
|
Row := RNG.Random (Generator) mod Height + 1;
|
|
Column := RNG.Random (Generator) mod Width + 1;
|
|
Ada.Text_IO.Put_Line
|
|
("Starting generation at " &
|
|
Positive'Image (Row) &
|
|
" x" &
|
|
Positive'Image (Column));
|
|
Depth_First_Algorithm (Maze, Row, Column);
|
|
end Initialize;
|
|
|
|
procedure Put (Item : Maze_Grid) is
|
|
begin
|
|
for Row in Item'Range (1) loop
|
|
if Row = Item'First (1) then
|
|
Ada.Text_IO.Put ('+');
|
|
for Col in Item'Range (2) loop
|
|
if Item (Row, Col).Walls (North) then
|
|
Ada.Text_IO.Put ("---+");
|
|
else
|
|
Ada.Text_IO.Put (" +");
|
|
end if;
|
|
end loop;
|
|
Ada.Text_IO.New_Line;
|
|
end if;
|
|
for Col in Item'Range (2) loop
|
|
if Col = Item'First (2) then
|
|
if Item (Row, Col).Walls (West) then
|
|
Ada.Text_IO.Put ('|');
|
|
else
|
|
Ada.Text_IO.Put (' ');
|
|
end if;
|
|
elsif Item (Row, Col).Walls (West)
|
|
and then Item (Row, Col - 1).Walls (East)
|
|
then
|
|
Ada.Text_IO.Put ('|');
|
|
elsif Item (Row, Col).Walls (West)
|
|
or else Item (Row, Col - 1).Walls (East)
|
|
then
|
|
Ada.Text_IO.Put ('>');
|
|
else
|
|
Ada.Text_IO.Put (' ');
|
|
end if;
|
|
if Item (Row, Col).Visited then
|
|
Ada.Text_IO.Put (" ");
|
|
else
|
|
Ada.Text_IO.Put ("???");
|
|
end if;
|
|
end loop;
|
|
if Item (Row, Item'Last (2)).Walls (East) then
|
|
Ada.Text_IO.Put_Line ("|");
|
|
else
|
|
Ada.Text_IO.Put_Line (" ");
|
|
end if;
|
|
Ada.Text_IO.Put ('+');
|
|
for Col in Item'Range (2) loop
|
|
if Item (Row, Col).Walls (South) then
|
|
Ada.Text_IO.Put ("---+");
|
|
else
|
|
Ada.Text_IO.Put (" +");
|
|
end if;
|
|
end loop;
|
|
Ada.Text_IO.New_Line;
|
|
end loop;
|
|
end Put;
|
|
end Mazes;
|