Contributor: MATTHEW MASTRACCI
{
From: Matthew.Mastracci@matrix.cambo.cuug.ab.ca (Matthew Mastracci)
 l> This is just cool enough that I'm going to post publicly too.
 l> LOU'S MAZE ALGORITHM
 Great algorithm! I read your posting, pondered it, sat down for an hour
and wrote this:
}
{$r-} { Increases speed a marginal amount }
{
 Maze Generator - PD 1995, by Matthew Mastracci
 rayban@matrix.cambo.cuug.ab.ca
 This program generates a maze using a plant-like approach. It starts by
 sowing "seeds" about every four units around the edge, and two in the
 middle. These then grow out in a random order in three directions. This
 prevents seeds from sprouting if they would grow into another.
 The original algorithm for generating mazes was written by Lou Duchez and
 posted in comp.lang.pascal. Here's a small excerpt from the part which
 describes how to work with the seeds:
 ---
Keep executing this loop until you run out of seeds:
 - Randomly select a seed. Extend the wall in some valid direction from
 this seed point, by turning into walls the grid locations one unit and
 two units away from the seed. To prevent the maze from closing off at
 any point, DO NOT EXTEND A WALL TO ANY POINT THAT IS ALREADY MARKED AS A
 WALL! (With this rule, you never close off the maze; you simply
 complicate the path from beginning to end.)
 - Remove this seed. It's done its job.
 - Add three seed points at this new location. (The assumption is that the
 wall could grow in three directions from this new point; if you want to
 be more exacting, you can add as many seeds as there are directions that
 the wall could extend from that point. It really doesn't matter much,
 except for the possibility of running out of seed point array elements if
 you always add 3.)
 - Seed maintenance: go through your list of seeds and eliminate any
 seeds that cannot extend in any valid direction.
 ---
 Feel free to use this source anywhere you want in anyway you want. I
 recommend you use it to generate mazes for games, however... :)
}
program
 MazeGenerator;
uses
 Crt;
const
 xMax = 79;
 yMax = 49;
 sMax = (xMax - 3) * (yMax - 3) div 2;
type
 tMap = record
 Data : array[1..xMax, 1..yMax] of Boolean;
 xEntrance, yEntrance : Byte;
 xExit, yExit : Byte;
 end;
 tSeed = record
 x, y, Dir : Byte;
 Valid : Boolean;
 end;
var
 Map : tMap;
{ Draws the map }
procedure DrawMap(Map : tMap);
var
 x, y : Byte;
begin
 for x := 1 to xMax do begin
 for y := 1 to yMax do begin
 if Map.Data[x, y] then Mem[$b800 : y * 160 + x * 2] := 219;
 end;
 end;
end;
{ Generates the map }
procedure GenerateMap(var Map : tMap);
var
 Seeds : array[1..sMax] of tSeed;
{ Reports TRUE if any seeds are "unsprouted" }
function NoSeeds : Boolean;
var
 i : Word;
 FoundSeeds : Boolean;
begin
 FoundSeeds := False;
 for i := 1 to sMax do begin
 if Seeds[i].Valid then FoundSeeds := True;
 end;
 NoSeeds := not FoundSeeds;
end;
{ "Plant" a seed }
procedure AddSeed(x, y, Dir : Byte);
var
 i : Word;
begin
 i := 0;
 repeat
 Inc(i);
 until (i = sMax) or not Seeds[i].Valid;
 if Seeds[i].Valid then begin
 WriteLn('Error: Out of seed space!');
 Halt;
 end else begin
 Seeds[i].x := x;
 Seeds[i].y := y;
 Seeds[i].Dir := Dir;
 Seeds[i].Valid := True;
 end;
end;
{ "Sprout" a seed }
procedure Sprout;
var
 i : Word;
begin
 repeat
 i := Random(sMax) + 1;
 until Seeds[i].Valid;
 with Seeds[i] do begin
 case Dir of
 0: begin { up }
 if not Map.Data[x, y - 2] then begin
 AddSeed(x, y - 2, 1);
 AddSeed(x, y - 2, 2);
 AddSeed(x, y - 2, 3);
 Map.Data[x, y - 1] := True;
 Map.Data[x, y - 2] := True;
 end;
 end;
 1: begin { down }
 if not Map.Data[x, y + 2] then begin
 AddSeed(x, y + 2, 0);
 AddSeed(x, y + 2, 2);
 AddSeed(x, y + 2, 3);
 Map.Data[x, y + 1] := True;
 Map.Data[x, y + 2] := True;
 end;
 end;
 2: begin { left }
 if not Map.Data[x - 2, y] then begin
 AddSeed(x - 2, y, 0);
 AddSeed(x - 2, y, 1);
 AddSeed(x - 2, y, 3);
 Map.Data[x - 1, y] := True;
 Map.Data[x - 2, y] := True;
 end;
 end;
 3: begin { right }
 if not Map.Data[x + 2, y] then begin
 AddSeed(x + 2, y, 0);
 AddSeed(x + 2, y, 1);
 AddSeed(x + 2, y, 2);
 Map.Data[x + 1, y] := True;
 Map.Data[x + 2, y] := True;
 end;
 end;
 end;
 end;
 Seeds[i].Valid := False;
end;
var
 x, y : Byte;
 DrawCount : Byte;
begin
 FillChar(Map, SizeOf(Map), 0); { Zero out map }
 FillChar(Seeds, SizeOf(Seeds), 0); { Erase seeds }
 { Draw border }
 with Map do begin
 for x := 1 to xMax do begin
 Data[x, 1] := True;
 Data[x, yMax] := True;
 end;
 for y := 1 to yMax do begin
 Data[1, y] := True;
 Data[xMax, y] := True;
 end;
 { Map entrance }
 yEntrance := 1;
 xEntrance := (Random(yMax div 2) + 1) * 2;
 Data[xEntrance, yEntrance] := False;
 { Map exit }
 yExit := yMax;
 xExit := (Random(yMax div 2) + 1) * 2;
 Data[xExit, yExit] := False;
 { Add a couple of seeds in the middle (islands) }
 AddSeed((Random(xMax div 2) + 1) * 2 + 1, (Random(yMax div 2) + 1) * 2 + 1,
Random(4));
 AddSeed((Random(xMax div 2) + 1) * 2 + 1, (Random(yMax div 2) + 1) * 2 + 1,
Random(4));
 { Add seeds around the edges, about every 4 units }
 for DrawCount := 1 to (2 * xMax + 2 * yMax) div 4 do begin
 case Random(4) of
 0: AddSeed((Random(xMax div 2) + 1) * 2 + 1, 1, 1); { top, going down }
 1: AddSeed((Random(xMax div 2) + 1) * 2 + 1, yMax, 0); { bottom, going
up }
 2: AddSeed(1, (Random(yMax div 2) + 1) * 2 + 1, 3); { left, going right
}
 3: AddSeed(xMax, (Random(yMax div 2) + 1) * 2 + 1, 2); { right, going
left }
 end;
 end;
 end;
 DrawCount := 0;
 repeat
 Inc(DrawCount);
 if DrawCount = 100 then begin
 DrawCount := 0;
 DrawMap(Map);
 end;
 if KeyPressed then begin
 while KeyPressed do ReadKey;
 DrawMap(Map);
 end;
 Sprout;
 until NoSeeds;
 DrawMap(Map);
end;
begin
 Randomize;
 TextMode(CO80 + Font8x8);
 GenerateMap(Map);
end.


AltStyle によって変換されたページ (->オリジナル) /