The applet illustrates 2 aspects of GUI programming in Scala, the first is how to interact with basic javax.swing APIs directly and the second is how to go one step further and achieve the same effect using the scala.swing wrapper API instead.

The function of the Applet can be broken down into 3 simple steps:

Step 1: Produce a random maze. This uses a modified version of Prim's algorithm, running backwards from the exit until all of the available space has been covered. This will produce a simple path from the source to the exit, which is the path we seek when we try to solve the maze by starting at the start. The standard Prim's algorithm is used to produce a minimum spanning tree from a directed acyclic graph by recursively adding safe edges to the current minimum spanning tree recursively, starting at a source node.

Step 2: Use a regular (recursive) DFS algorithm to search the maze, stopping only when the exit is reached (or all paths are explored fully if there were no reachable exit).

Step 3: Remove all backtrack paths and show the single simple path from start to exit as the solution to the maze.

During maze exploration, the parts of the maze explored are marked with coloured breadcrumbs, red indicates a forward search path and blue a backtracking path (which happens when a path reaches a dead-end).

In step 2, in order to stop immediately when the exit is found (rather than conclude all other possible search branches) the recursive maze solving function throws an exception to escape out of the call stack immediately.

The code given is compatible with the very latest Scala 2.8.x trunk development builds, and with 2.7.6 the latest stable release (some 2.7.6 only versions of functions such as shuffle are commented out in preference to the newer and better 2.8 versions). Note that there are currently some issues with Arrays in 2.8.x causing run time errors with trying to create a multidimensional array. The solution that still works with current 2.8 builds is to use the Array.tabulate function.

and there are similar problems with the new Array.ofDims function too. These issues should be resolved in 2.8 final release but recently arrays in scala have been undergoing some re-factoring and so stability in this area has not been too strong.

One interesting thing to note is the use of the new Scala 2.8+ Stream.iterate function to avoid undesirable vars instead of vals, here is an example of that extracted from the code.

A typical iterative piece of code, the while loops is used to iterate over some code block whilst a particular condition is met for a given variable. For this to work the variable n needs to be updated in the loop, hence it can't be a val and has to be a var instead. This is somewhat paradigmatic of iterative imperative programming, but doesn't sit well with the strive for a more functional style.

var n = cells(exit.x)(exit.y)

while (n != null) {

n.trail = Forward n = n.pi update}

What we can do here is make use of the Stream.iterate function to avoid the unsightly var n, as follows:

Given that this is new in Scala 2.8 and 2.8 isn't released yet, you can augment existing 2.7.6 code with a helper function to aid the transition and improve 2.7 based code in readiness for 2.8. Here is an example of a util class that defines iterate so the same idea can be used in 2.7 based code:

One thing that's quite clear is the obviously similarity between the function to generate and the function to solve the maze. Using the DSL-like features of Scala it should be possible to extract the common control structure / algorithm and create a new utility function to provide built-in like support for this, passing in a body function to provide the difference implementation of maze generate vs. solve.

// 1. Start at a particular cell, call it the "exit" // 2. Mark the current cell as visited, and get a list of all its neighbors. // For each neighbor, starting with a randomly selected neighbor: // 1. If that neighbor hasn't been visited, // remove the wall between this cell and that neighbor, // and then recurse with that neighbor as the current cell.

// cell 0,0 is the start, open the north wall to highlight this var s = cells(0)(0) s.clear(North);

// cell width-1,height-1 is the exit, open the south wall to highlight this val c = cells(exit.x)(exit.y) c.clear(South);

// make a stream of x, f(x), f(f(x)), etc. // in Haskell this is called "iterate". it ought to be in the standard library // as Stream.iterate. "unfold" should be more general, but nonetheless I'm // going to call this unfold for the moment... def unfold[T](x:T)(f:T=>T):Stream[T] = Stream.cons(x,unfold(f(x))(f))