###
NOTE: This module is being re-written. From now on version 1.0x will only be changed for bug fixes and maintenance. New features will be in the version 2.00-track. See the TODO file for more information. ###

Revision history:

0.01 Wed Apr 28 14:14:56 1999

0.7     Tue Feb 8 16:51:03 2000
        - Many incremental changes, leading up to:
          1) Hash-style parameters to new()
          2) Inheritance in similarly-dimensioned classes.
             We now have Games::Maze, and Games::MazeFlat.
          3) Code re-organized as a result of inheritance -
             there are a lot more hidden member functions
             created from sniplets of code that cannot cross the
             package barrier.
          4) More efficient use of internal constants.  We
             no longer have separate constants for the direction
             and the wall in that direction.  Now one constant
             handles both the wall and the direction we face.
          5) "make test" has tests for the 48-bit rand() function.

0.8     Wed Apr 19 10:57:35 2000
        - Games::MazeFlat goes away.  There was no real reason
          beyond sentimentality to keep it.
        - The direction values for all mazes are now the same.  South,
          for example, is now 0x20 for all mazes, instead of being 0x08
          for square mazes, and 0x10 for hexagon mazes.  This is an
          obvious thing to do in retrospect, but way back when they were
          separate programs with separate constants.
        - This lets me move the contants and some more functions
          into the base class, which makes the reading of the hex
          dump easier.

0.9     Thu Oct 19 11:39:54 2000
        - The maze object is now created via a call to
          Games::Maze->new() only.  The child classes ::Rect and
          ::Hex are dealt with in new().  The user need not deal
          with it at all.

1.0     Wed Apr 24 13:27:19 2002
        - Hexagonal Hexagon mazes
        - Big changes in the stringifying functions, mostly by deleting
          code, and fixing up the border cells values.
        - The 'cols', 'rows', and 'lvls' parameters have been replaced by
          a single 'dimensions' parameter.
        - New parameter 'start' tells the make() method where to start
          the random walk from.
        - New parameter 'fn_choosedir' chooses which direction your random
          walk takes while making the maze.
        - New parameters 'entry' and 'exit' let you place the beginning
          and ending points.

1.01 Tue May 07 21:55:39 2002

1.02 Mon Jun 03 19:29:53 2002

1.03 Wed Feb 21 2007

HISTORY & BACKGROUND INFORMATION

The code started out as a fairly direct translation of the CDC Pascal source, which in turn was translated from the original CDC Fortran (well, MNF to be precise) program written back in 1978 or 1979.

The Algorithm

The algorithm is simple. The maze is considered to be an array of cells, each cell bounded by walls that are shared with its neighbor. The program starts with a random cell, and randomly 'walks' through a wall (knocking it down in the process) into a neighboring enclosed cell. If it reaches a dead end, it returns to a point where it can continue its random walk. When it runs out of enclosed cells to break into, the algorithm is done.

Solving

Since this process creates singly-connected mazes (that is, a maze where there is only one path between any two points), the solving method is straightforward. Go forward until either you reach the exit, or until you run into a wall. If you have run into a wall, turn to the next direction and walk forward. Repeat. Drop off or pick up path marks as you exit one cube for another.

A 'hand-on-wall' method of solving (not included in the packages) that you may have learned as a kid works, but only for the 2-dimensional mazes. Sadly, it will often wind up in an infinite loop when it is extended to the three-dimensional case. I suspect that for this solving algorithm to work, it would have to chose its next move based not only on the current wall, but the prior move's wall as well. I haven't bothered to test this, though. Since the go-forward method works so well with both 2- and 3-dimensional mazes, I haven't attempted to adapt the hand-on-wall methd.

Representing Hexagonal Mazes

Hexagonal mazes, as you may notice if you study the code, are simply rectangular mazes with a 'hexagonal drift'. That is,

hexagonal mesh square grid with 'hexagonal drift'

  1  2  3  4  5  6  7  8             1   2   3   4   5   6   7   8
  __    __    __    __              ___     ___     ___     ___    
 /  \__/  \__/  \__/  \__          |   |___|   |___|   |___|   |___
 \__/  \__/  \__/  \__/  \         |___|   |___|   |___|   |___|   |
 /  \__/  \__/  \__/  \__/         |   |___|   |___|   |___|   |___|
 \__/  \__/  \__/  \__/  \         |___|   |___|   |___|   |___|   |
 /  \__/  \__/  \__/  \__/         |   |___|   |___|   |___|   |___|
 \__/  \__/  \__/  \__/  \         |___|   |___|   |___|   |___|   |
 /  \__/  \__/  \__/  \__/         |   |___|   |___|   |___|   |___|
 \__/  \__/  \__/  \__/  \         |___|   |___|   |___|   |___|   |
    \__/  \__/  \__/  \__/             |___|   |___|   |___|   |___|

Moving the squares back in position gives us a basic 8x4 matrix, which is easy to represent in perl code. This leaves only the question of which six of the eight cells we can move to after choosing one of the six possible directions to go. There are two possible choices:

      _\|/_  or   __|__
        |          /|\

Which one we use depends upon whether we are in an up-shifted column or not.

Incidently, these are also the moves allowed to the opposing Gold General pieces in the game Shogi (a chess-like game from Japan). Coincidence? Well, probably, but it is interesting to contemplate.