mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-22 07:10:42 -08:00
Spaces tend to cause annoyances in a Unix-style shell environment. This change fixes that.
281 lines
5.4 KiB
ObjectPascal
281 lines
5.4 KiB
ObjectPascal
unit Maze;
|
|
|
|
{$IFDEF FPC}
|
|
{$mode ObjFPC}{$H+}
|
|
{$ENDIF}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes
|
|
, SysUtils
|
|
, Room
|
|
;
|
|
|
|
type
|
|
TDirection = (dUp, dRight, dDown, dLeft);
|
|
TDirections = set of TDirection;
|
|
{ TMaze }
|
|
TMaze = class(TObject)
|
|
private
|
|
FWidth: Integer;
|
|
FLength: Integer;
|
|
FEntry: Integer;
|
|
FLabyrinth: Array of Array of TRoom;
|
|
|
|
function GetRandomDirection(const ADirections: TDirections): TDirection;
|
|
|
|
procedure DebugVisited;
|
|
procedure DebugWalls;
|
|
protected
|
|
public
|
|
constructor Create(const AWidth, ALength: Integer);
|
|
destructor Destroy; override;
|
|
|
|
procedure Build;
|
|
procedure Print;
|
|
published
|
|
end;
|
|
|
|
implementation
|
|
|
|
const
|
|
EXIT_DOWN = 1;
|
|
EXIT_RIGHT = 2;
|
|
|
|
{ TMaze }
|
|
|
|
function TMaze.GetRandomDirection(const ADirections: TDirections): TDirection;
|
|
var
|
|
count: Integer;
|
|
position: Integer;
|
|
directions: array [0..3] of TDirection;
|
|
begin
|
|
count:= 0;
|
|
position:= 0;
|
|
if dUp in ADirections then
|
|
begin
|
|
Inc(count);
|
|
directions[position]:= dUp;
|
|
Inc(position);
|
|
end;
|
|
if dRight in ADirections then
|
|
begin
|
|
Inc(count);
|
|
directions[position]:= dRight;
|
|
Inc(position);
|
|
end;
|
|
if dDown in ADirections then
|
|
begin
|
|
Inc(count);
|
|
directions[position]:= dDown;
|
|
Inc(position);
|
|
end;
|
|
if dLeft in ADirections then
|
|
begin
|
|
Inc(count);
|
|
directions[position]:= dLeft;
|
|
Inc(position);
|
|
end;
|
|
Result:= directions[Random(count)];
|
|
end;
|
|
|
|
procedure TMaze.DebugVisited;
|
|
var
|
|
indexW: Integer;
|
|
indexL: Integer;
|
|
begin
|
|
WriteLN('Visited');
|
|
for indexL:= 0 to Pred(FLength) do
|
|
begin
|
|
for indexW:= 0 to Pred(FWidth) do
|
|
begin
|
|
Write(FLabyrinth[indexW][indexL].Visited:3,' ');
|
|
end;
|
|
WriteLN;
|
|
end;
|
|
WriteLN;
|
|
end;
|
|
|
|
procedure TMaze.DebugWalls;
|
|
var
|
|
indexW: Integer;
|
|
indexL: Integer;
|
|
begin
|
|
WriteLN('Walls');
|
|
for indexL:= 0 to Pred(FLength) do
|
|
begin
|
|
for indexW:= 0 to Pred(FWidth) do
|
|
begin
|
|
Write(FLabyrinth[indexW][indexL].Walls:3,' ');
|
|
end;
|
|
WriteLN;
|
|
end;
|
|
WriteLN;
|
|
end;
|
|
|
|
constructor TMaze.Create(const AWidth, ALength: Integer);
|
|
var
|
|
indexW: Integer;
|
|
indexL: Integer;
|
|
begin
|
|
Randomize;
|
|
FWidth:= AWidth;
|
|
FLength:= ALength;
|
|
FEntry:= Random(FWidth);
|
|
SetLength(FLabyrinth, FWidth, FLength);
|
|
for indexW:= 0 to Pred(FWidth) do
|
|
begin
|
|
for indexL:= 0 to Pred(FLength) do
|
|
begin
|
|
FLabyrinth[indexW][indexL]:= TRoom.Create;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
destructor TMaze.Destroy;
|
|
var
|
|
indexW: Integer;
|
|
indexL: Integer;
|
|
begin
|
|
for indexW:= 0 to Pred(FWidth) do
|
|
begin
|
|
for indexL:= 0 to Pred(FLength) do
|
|
begin
|
|
if Assigned(FLabyrinth[indexW][indexL]) then
|
|
begin
|
|
FLabyrinth[indexW][indexL].Free;
|
|
end;
|
|
end;
|
|
end;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TMaze.Build;
|
|
var
|
|
indexW: Integer;
|
|
indexL: Integer;
|
|
direction: TDirection;
|
|
directions: TDirections;
|
|
count: Integer;
|
|
begin
|
|
FEntry:= Random(FWidth);
|
|
indexW:= FEntry;
|
|
indexL:= 0;
|
|
count:= 1;
|
|
FLabyrinth[indexW][indexL].Visited:= count;
|
|
Inc(count);
|
|
repeat
|
|
directions:= [dUp, dRight, dDown, dLeft];
|
|
if (indexW = 0) or (FLabyrinth[Pred(indexW)][indexL].Visited <> 0) then
|
|
begin
|
|
Exclude(directions, dLeft);
|
|
end;
|
|
if (indexL = 0) or (FLabyrinth[indexW][Pred(indexL)].Visited <> 0) then
|
|
begin
|
|
Exclude(directions, dUp);
|
|
end;
|
|
if (indexW = Pred(FWidth)) or (FLabyrinth[Succ(indexW)][indexL].Visited <> 0) then
|
|
begin
|
|
Exclude(directions, dRight);
|
|
end;
|
|
if (indexL = Pred(FLength)) or (FLabyrinth[indexW][Succ(indexL)].Visited <> 0) then
|
|
begin
|
|
Exclude(directions, dDown);
|
|
end;
|
|
|
|
if directions <> [] then
|
|
begin
|
|
direction:= GetRandomDirection(directions);
|
|
case direction of
|
|
dLeft:begin
|
|
Dec(indexW);
|
|
FLabyrinth[indexW][indexL].Walls:= EXIT_RIGHT;
|
|
end;
|
|
dUp:begin
|
|
Dec(indexL);
|
|
FLabyrinth[indexW][indexL].Walls:= EXIT_DOWN;
|
|
end;
|
|
dRight:begin
|
|
FLabyrinth[indexW][indexL].Walls:= FLabyrinth[indexW][indexL].Walls + EXIT_RIGHT;
|
|
Inc(indexW);
|
|
end;
|
|
dDown:begin
|
|
FLabyrinth[indexW][indexL].Walls:= FLabyrinth[indexW][indexL].Walls + EXIT_DOWN;
|
|
Inc(indexL);
|
|
end;
|
|
end;
|
|
FLabyrinth[indexW][indexL].Visited:= count;
|
|
Inc(count);
|
|
end
|
|
else
|
|
begin
|
|
while True do
|
|
begin
|
|
if indexW <> Pred(FWidth) then
|
|
begin
|
|
Inc(indexW);
|
|
end
|
|
else if indexL <> Pred(FLength) then
|
|
begin
|
|
Inc(indexL);
|
|
indexW:= 0;
|
|
end
|
|
else
|
|
begin
|
|
indexW:= 0;
|
|
indexL:= 0;
|
|
end;
|
|
if FLabyrinth[indexW][indexL].Visited <> 0 then
|
|
begin
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
until count = (FWidth * FLength) + 1;
|
|
indexW:= Random(FWidth);
|
|
indexL:= Pred(FLength);
|
|
FLabyrinth[indexW][indexL].Walls:= FLabyrinth[indexW][indexL].Walls + 1;
|
|
end;
|
|
|
|
procedure TMaze.Print;
|
|
var
|
|
indexW:Integer;
|
|
indexL: Integer;
|
|
begin
|
|
|
|
//DebugVisited;
|
|
//DebugWalls;
|
|
|
|
for indexW:= 0 to Pred(FWidth) do
|
|
begin
|
|
if indexW = FEntry then
|
|
begin
|
|
Write('. ');
|
|
end
|
|
else
|
|
begin
|
|
Write('.--');
|
|
end;
|
|
end;
|
|
WriteLN('.');
|
|
|
|
for indexL:= 0 to Pred(FLength) do
|
|
begin
|
|
Write('I');
|
|
for indexW:= 0 to Pred(FWidth) do
|
|
begin
|
|
FLabyrinth[indexW][indexL].PrintRoom;
|
|
end;
|
|
WriteLN;
|
|
for indexW:= 0 to Pred(FWidth) do
|
|
begin
|
|
FLabyrinth[indexW][indexL].PrintWall;
|
|
end;
|
|
WriteLN('.');
|
|
end;
|
|
end;
|
|
|
|
end.
|
|
|