Retrocomputing

Amazing program from BASIC Computer Games

The maze program is one of the games in the famous 101 BASIC Computer Games published in 1978. In the book it is called 'Amazing' and the code available in Vintage BASIC. I have rewritten it in Pascal. It relies on two external procedures to create random numbers as the standard library doesn't have that functionality. The code used non-standard bit-level operators: '!' for OR, '&' for AND, and '#' for XOR.

OS-9 Pascal edition

{ Generate a maze.
  The algoritm uses a two-dimensional matrix of cells, where the bottom
  or the right wall can be absent.
  Pascal does not have a 'continue' statement, therefore the goto 580.
}
PROGRAM maze(input);
label 580,750;

const
    MAXROWS = 25;
    MAXCOLS = 25;

    NO_FLOOR = 1;
    NO_RIGHT_WALL = 2;
    VISITED = 4;

type
  direction = (Left, Right, Up, Down);

var
  randstate: integer;
  rows,cols,c,r,dx,entry,x,cellinx,totcells: integer;
  bottom: boolean;
  d: array[1..10] of direction;
  cells: array[1..MAXROWS, 1..MAXCOLS] of integer;

function random(VAR block:integer) : real; EXTERNAL;
procedure randomize(VAR block:integer); EXTERNAL;

{ Provide a random integer }
function rnd(maxval:integer):integer;
begin
  rnd := trunc(random(randstate) * maxval);
end;

{ Ask for dimensions.
  Sets the global variables: cols and rows }
procedure AskDimensions;
  var
    goodsize : boolean;
  begin
    goodsize := false;
    repeat
      writeln('What are your length and width (e. g. 13 10)?');
      readln(rows, cols);
      if (rows > 1) or (rows <= MAXROWS) or (cols > 1) or (cols <= MAXCOLS) then
        goodsize := true
      else
        writeln('Meaningless dimensions.  Try again.');
    until goodsize = true;
  end;

procedure PrintMaze;
  var
    r, c : integer;
  begin
    { Print top of the maze with an opening. }
    writeln;
    for c := 1 to cols do
      if c = entry then
        write('.  ')
      else
        write('.--');
    writeln('.');

    for r := 1 to rows do
    begin
      write('|');
      for c := 1 to cols do
      begin
        if (cells[r, c] & NO_RIGHT_WALL) = 0 then
          write('  |')
        else
          write('   ');
      end;
      writeln;
      for c := 1 to cols do
      begin
        if (cells[r, c] & NO_FLOOR) = 0 then
          write(':--')
        else
          write(':  ');
      end;
      writeln(':');
    end
  end;

{ Find a cell that is already visited to continue from.
  Uses the global variables r, c, cols, rows and visited.
}
procedure FindVisited;
  begin
    repeat
      c := c + 1;
      if c > cols then
      begin
        r := r + 1;
        if r > rows then
          r := 1;
        c := 1
      end;
    until (cells[r, c] & VISITED) <> 0;
  end;

procedure InitMaze;
  var q,z : integer;
  begin
    for q := 1 to rows do
      for z := 1 to cols do
      begin
        cells[q,z] := 0;
      end;
  end;

procedure AddPossibility(go:direction);
  begin
    dx := dx + 1;
    d[dx] := go;
  end;

begin
  randstate := 0;
  randomize(randstate);
  AskDimensions;
  totcells := rows * cols;
  InitMaze;

  bottom := false;
  entry := rnd(cols) + 1;

  r := 1;
  c := entry;
  cellinx := 1;
  cells[r, c] := cells[r, c] ! VISITED;

  repeat
    dx := 0;
    if c <> 1 then
    begin
      if (cells[r, c - 1] & VISITED) = 0 then
      begin
        AddPossibility(Left)
      end;
    end;

    if c <> cols then
    begin
      if (cells[r, c + 1] & VISITED) = 0 then
      begin
        AddPossibility(Right)
      end
      else goto 750;
    end;

    if r > 1 then
    begin
      if (cells[r - 1, c] & VISITED) = 0 then
      begin
        AddPossibility(Up)
      end;
    end;

  750:
    if r < rows then
    begin
      if (cells[r + 1, c] & VISITED) = 0 then
        AddPossibility(Down);
    end
    else
    begin
      if bottom = false then
        AddPossibility(Down);
    end;

    if dx = 0 then
    begin
      FindVisited;
      goto 580;
    end;
    x := rnd(dx) + 1;
    case d[x] of
      Down:
        begin
          cells[r, c] := cells[r, c] ! NO_FLOOR;
          r := r + 1;
          if r > rows then
          begin
            bottom := true;
            r := 1;
            c := 0;
            FindVisited;
            goto 580;
          end
        end;
      Up:
        begin
          r := r - 1;
          cells[r, c] := NO_FLOOR
        end;
      Right:
        begin
          cells[r, c] := cells[r, c] ! NO_RIGHT_WALL;
          c := c + 1
        end;
      Left:
        begin
          c := c - 1;
          cells[r, c] := NO_RIGHT_WALL
        end;
    end;

    cellinx := cellinx + 1;
    cells[r, c] := cells[r, c] ! VISITED;
580:
  until cellinx >= totcells;

  PrintMaze;
end.