You are on page 1of 9

Using a Maze Case Study to Teach

Object-Oriented Programming and Design Patterns


Chris Nevison Barbara Wells
Computer Science Dept. South Fork High School
Colgate University 10205 SW Pratt & Whitney Rd.
Hamilton, NY 13346 Stuart, FL 34997
chris@cs.colgate.edu bcw100@netzero.com

Abstract provide is that students get visual feedback and reward as


well as the satisfaction of completing an assignment. In
In order to teach object-oriented design and programming many cases the visualization shows errors in a program as
in introductory computer science it is imperative to teach well and may lead to an understanding of basic principles.
objects from the very beginning of the course. The use of
Finally, we will describe how this case study can be used
interacting objects is motivated by examples with an
to demonstrate the use of standard data structures,
inherent complexity. We describe a case study based on a
maze as an example that provides a complex framework including two-dimensional arrays, the Java List and Set
but at the same time admits to simple pieces that students classes, stacks, queues, and priority queues. These topics
can work with early in an introductory course. This case are often addressed in the second computer science
study can be used throughout the first year not only to course. We will also consider how general graphs might
introduce basic control structures, but also to introduce a be used to generalize the maze problem and point out
number of design ideas and algorithms. how the example could be extended to introduce topics
found in upper level algorithms courses, such as optimal
Keywords: Object-oriented programming, design path algorithms and branch-and-bound algorithms.
patterns, algorithms.
2 Other Work
1 Introduction
Kristen Nygaard (2001, 2001) has promoted the teaching
Kristen Nygaard (2001, 2002) and others (Nevison and of introductory programming using the object-oriented
Wells, 2003) have asserted that object-oriented paradigm in the context of complexity. This does not
programming should be taught in the context of complex mean that we expect students to grasp the many
examples. We present a case study based on finding a intricacies of programming at once. Rather, they should
way through a maze that demonstrates how this can be be shown how they can work on simple parts of a more
done. This case study provides material that students can complex program and see from the start how it is the
work with from early in a first computer science course to interaction of many objects that makes a program work.
problems appropriate for a second course on data Nygaard used a busy restaurant as an example. We use
structures and even beyond. the objects and concepts involved with a maze as one
example that can be used in this way.
After reviewing other work in the next section, we will
first describe the framework for the maze program. We Case studies have long been an important component of
will then describe how some basic programming teaching computer science. Clancy and Lin (1992) have
exercises on control structures appropriate to an promoted the use of case studies for teaching introductory
introductory class can be developed within this computer science for several years, working with
framework. procedural programming languages such as Pascal. We
are adapting this approach to the context of object-
This will lead to the introduction of some simple design
oriented programming and design patterns. In this
principles and patterns that can be used to demonstrate
context, we suggest that the use of case studies from the
how even at the introductory level, it makes sense to
very beginning of the first course can be a successful
discuss basic principles of design.
strategy.
We will then move on to using the case study to provide
Many authors have also emphasized the importance of
examples of recursive algorithms that are non-trivial. One
teaching "objects early" when teaching an object-oriented
advantage of working within the framework that we
programming paradigm in the first computer science
course. See, for example, (Alphonce and Ventura, 2002,
Copyright ©2004, Australian Computer Society, Inc. This Barnes and Kolling, 2003, Bruce, Danyluk and Murtaugh,
paper appeared at the Sixth Australasian Computing Education 2001). We agree that "objects early" is quite natural for
Conference (ACE2004), Dunedin, New Zealand. Conferences
the object-oriented paradigm. Well-chosen case studies
in Research and Practice in Information Technology, Vol. 30.
Raymond Lister and Allison Young, Eds. Reproduction for
can provide the complexity to motivate object-oriented
academic, not-for profit purposes permitted provided this text programming while also providing a context where
is included. concepts can be presented in a reasonably simple setting
within the more complex environment.

207
Many of these same authors suggest that graphics is an Constructors
important motivating tool for teaching introductory WalkerState(Location loc, Direction dir)
computer science and provide helpful programming constructs an instance with the given Location
environments for this approach (Proulx, Raab, and and Direction
Rasala, 2002). We do not advocate teaching low-level WalkerState(WalkerState state)
Java graphics in the first programming course. In the creates a new WalkerState that is a copy of
context of the maze case study, we provide the graphical state
user interface, so that students work on programs in the Accessors
context of using graphics, but do not do any graphics Location location() returns the location
programming proper. An advanced project might be to Direction direction()returns the direction
create an alternative graphics interface in the context of Direction toRight() returns the direction
the structure provided by the case study. 90 degrees to the right of the
state's direction
Alphonce and Ventura (2002) advocate the use of design
Direction toLeft() returns the direction 90
patterns in the first computer science course, an approach
degrees to the left of the state's
that fits well with our use of case studies approach in the
direction
first courses. Examples of introducing patterns into the
Direction toReverse()returns the direction 180
first year were presented at the OOPSLA02 "Killer
degrees from the state's
Examples for Design Patterns and Objects First"
direction
workshop, (Alphonce, 2002). Astrachan et al. (1998) also Location neighborTo(Direction dir)
consider design patterns an essential part of the early returns the location immediately adjacent to the
computer science curriculum, as does Proulx (2000). state's location in the given direction
Using a maze as the basis of explaining ideas in String toString() returns a string representation
Computer Science or for programming assignments is not of this state
original. A notable example of using a maze program to Modifiers
illustrate design ideas is the book by Gamma, Helm, void turnRight() changes direction 90 degrees
Johnson, and Vlissides on design patterns (1995). They to the right
use a different structure for their maze but find it a rich void turnLeft() changes direction 90 degrees
source for illustrating design patterns. We use our own to the left
maze to illustrate some design principles and patterns. void turnAround() changes direction 180 degrees
void moveForward() changes the state's location to
3 The Maze Framework the adjacent location in the
current direction
We provide a framework within which students work. void moveToward(Direction dir)
This framework provides several classes that are "black- changes the state's location to the adjacent
box" for the students. Some of these classes set up the location in the given direction
graphical user interface and need not be seen by the Since the operations of the class WalkerState and the
students at all. Others provide functionality used by the interactions with the other parts of the program can be
students, so that they need to know about the methods done completely in terms of Location and Direction
that they are expected to use, but need not know about the objects, there is no need for students to know about the
implementation of the classes providing those methods. methods for these two classes. This is a good lesson in
Some of these black-box classes may be opened for study working with objects without worrying about the details -
later in the course. This is a setup similar to the one used - taking their interactions as defined by the class given, in
by the Marine Biology Simulation case study developed
this case WalkerState and Maze.
for the College Board Advanced Placement program in
Computer Science (Brady, 2002). 3.2 The maze
3.1 Walker state The maze consists of a grid of cells which can either be
walls or open. A walker in the maze can only move into
The framework includes two low-level classes for
open cells, not walls. One open cell is designated as the
describing the position of a walker in the maze,
goal to be reached and an initial state (location and
Location and Direction. These are borrowed from the
direction) is also part of the maze specification.
College Board Marine Biology Simulation Case Study
(Brady, 2002).1 Both these classes are immutable. A third We represent the maze with the class Maze. It has
class, WalkerState, encapsulates the geometry of the methods to provide information about the maze.
two dimensional grid that forms the maze and the state of Accessors
a walker in the maze. The WalkerState class provides int numRows() returns number of rows in maze grid
the following constructors and methods: int numCols() returns number of columns in maze grid
WalkerState start() returns starting state
Location goal() returns location of goal
1 boolean isWall(Location loc)
The MBS case study code is distributed by the College
returns true if location is a wall, otherwise false
Board under the GNU General Public License, as is the
code for this maze case study.

208
The maze has no modifier methods since it cannot be provided. This and the fact that any interactive walker
changed once it has been constructed. class must implement the MazeDisplayListener
For the first few examples using the framework, the interface is a good opportunity for describing the
student only needs to know two Maze methods: isWall Observer design pattern. The MazeDisplayListener
and goal. Later the methods for getting the dimensions interface has one method:
of the maze, numRows and numCols, and the start void onMazeInput(String mazeInput)
method can be useful. responds to call by MazeDisplay to which this
listener has been added; the parameter is set to
3.3 Displaying the maze "forward," "right," "left," or "reverse" according
The mechanism for displaying the maze is black-box to the button or location clicked.
code. The only information that a student or other user Diagram 2 shows the relationship between the
needs to know about is the interface MazeDisplay that MazeDisplay and the MazeDisplayListener.
specifies the operations of a display and the interface
register
MazeDisplayListener that any maze walker that is
interactive must implement. MazeDisplay addMazeDisplayListener MazeDisplayListener
notify
There are two different maze displays that implement the object object
onMazeInput
MazeDisplay interface. The first we call the rat's view
and it provides a display as if the user were inside the Diagram 2. Listener Relationship
maze. and could see ahead up to three cells and right or
left one cell from the current cell or any of those ahead, if 4 Early Assignments
the view is not blocked by a wall. Diagram 1 shows two
examples of what can be seen, where the bottom center The student would not see the details described above
looking up is the initial position, white cells are open, before the first assignment. A programming assignment
black cells are walls and gray cells are unknown since the would be provided with the black-box and other code and
view is blocked by a wall. a brief explanation of the nature of the listener
mechanism. This need not be in any great detail, since the
mechanism is already in place.

Diagram 1. Rat's View of Maze 4.1 An interactive maze walker


The first assignment requires that the student complete
This view is used in the first assignment that asks the the code for one method, onMazeInput, for an
student to complete the implementation of an interactive interactive walker class that is already provided. In fact a
walker that responds to commands input by mouse clicks. working version of the interactive walker called
The second display is a bird's eye view, showing the InteractiveWalkerStart is provided so that the
whole maze and indicating the current state of the walker student can first compile and run the code. This is run
with a cell color (blue) and arrow. This display is from a driver class MazeDriver that sets up the rat's
introduced when we ask the student to create or modify a view of the maze and constructs the walker with the line
random walker, where the program steps through the new InteractiveWalkerStart(maze, display);
maze "automatically," rather than in response to mouse The student only needs to modify this one line to run a
clicks, until the goal is reached. different maze walker. The student assignment is to
rename this class InteractiveWalker and replace the
The MazeDisplay interface includes these methods: body of the onMazeInput method so that the walker
Modifiers changes state appropriately in response to mouse clicks:
void displayState(WalkerState state)
displays the view of the maze appropriate for the public class InteractiveWalkerStart
given state. implements MazeDisplayListener
void eraseState(WalkerState state) {
private WalkerState myState;
erases appropriate parts of state display private Maze myMaze;
void markLocation(Location loc) private MazeDisplay display;
marks a location in the maze display
void unmarkLocation(Location loc) public InteractiveWalkerStart(Maze maze,
MazeDisplay md)
removes the mark for a location {
void addMazeDisplayListener myMaze = maze;
(MazeDisplayListener listener) myState = maze.start();
adds the listener to this display display = md;
void removeMazeDisplayListener display.addMazeDisplayListener(this);
(MazeDisplayListener listener) display.displayState(myState);
}
removes the listener from this display
Initially the student only needs to be concerned with the public void onMazeInput(String action)
first two methods that display and erase the state. The {
System.out.println(action);
addMazeDisplayListener method is called in the }}
constructor of the interactive walker class that is initially

209
• when the user enters "forward" the walker should
import java.util.Random;
move forward one location, if that location is not a public class RandomWalker
wall. {
• when the user enters "right" the walker should turn to private WalkerState myState;
private Maze myMaze;
the right without changing location private MazeDisplay myDisplay;
• when the user enters "left" the walker should turn to
the left without changing location public RandomWalker(Maze maze,
• when the user enters "reverse" the walker should turn MazeDisplay md)
{ myMaze = maze;
around without changing location myState = maze.start();
In order to complete this assignment, the student must use myDisplay = md;
methods from the WalkerState and Maze classes. myDisplay.displayState(myState);
}
There are two variations of this assignment that result in
slightly different walker behaviors. One might require public void run()
that on "right" or "left" the walker not only turn but also { Random rand = new Random();
while(!myState.location().equals(
move into the cell to that side if it is not a wall. A second myMaze.goal()))
variation might have the walker move ahead several cells { myDisplay.eraseState(myState);
to the next location that has either a wall in front or an myDisplay.markLocation(
myState.location());
open cell to the right or left. Other variations of this sort int choice = rand.nextInt(4);
of walker could also be devised. The second type of if(choice == 0)
walker does not just using conditional statements, it also { if(!myMaze.isWall
needs loops, the objective of the next set of programs. (myState.neighborTo
(myState.direction())))
{ myState.moveForward();
4.2 A random maze walker }
}
The second set of assignments involves loops. The else if(choice == 1)
simplest version is a walker that randomly chooses from myState.turnRight();
else if(choice == 2)
the actions of the interactive walker described above at myState.turnLeft();
each step. It repeats these actions until the goal of the else // choice == 3
maze is reached. We give this example to the student as a myState.turnAround();
demonstration of the while loop. The code for
myDisplay.displayState(myState);
RandomWalker is shown below. This class is not try
interactive and therefore does not use the listener model. { Thread.sleep(50);
This class calls the methods that display the current state }
of the walker and the locations that have already been catch(InterruptedException ex){}
}}}
visited. It also includes a time delay, so that the progress
of the walker can be viewed.
4.3 Classroom experience
One can get dizzy running the original MazeDriver with
this program (although it is fun to let the students do it One of the authors, Wells, has used these assignments in
this way at first). Consequently we also supply an introductory Java programming class with great
MazeDriver2 that not only includes the bird's eye view success. The interactive walker assignments were used
of the maze but also allows the user to select the rat's shortly after the students learned about if-else statements.
view, bird's eye view, or both. They found the assignment challenging, but not
overwhelming and they had the motivation to get the
A first assignment on loops asks the student to modify the walker to find their way through the maze with the
RandomWalker class so that it does not spin in place so graphical user interface. Many students came up with
much but instead moves in whatever direction was their own variations on the interactive walker.
randomly chosen, if possible. This also gets to the goal of
In the same class, students were given the assignment of
the maze considerably faster than the given version.
writing the random walker -- they were not given the first
Other variations of random walker include walkers that version of the random walker that we gave above. They
use the Direction class constants NORTH, SOUTH, EAST, found this to be an exciting assignment and immediately
WEST and walkers that keep track of where they have demanded a bird's eye view display. These students found
been, using some data structure, and do not repeat the right-hand walker to be a challenging assignment.
locations unless there was no other choice (this involves
interesting conditional logic). Another variation would 5 Design Issues
generate a list of possible moves that are not walls, then
randomly select the next location from that list. Sometime after the interactive and the "automatic"
A challenging assignment that exercises a student's ability (random and right-hand) walkers have been developed in
to use conditional logic is the right-hand (or left-hand) class and assignments, and after inheritance has been
walker. The right-hand walker moves through the maze in introduced, these can be used to demonstrate some ideas
a deterministic fashion as if keeping the right hand on the about object-oriented design and design patterns. We do
wall at all times. This algorithm will solve many, but not not advocate an emphasis on the use of design patterns in
all mazes. the first programming course, but some discussion of

210
GenericWalker <<interface>>
MazeDisplayListener

RandomWalker RighthandWalker InteractiveWalker1 InteractiveWalker2

Diagram 3. Inheritance Hierarchy

patterns helps students begin to develop an understanding


of design principles. public class GenericWalker
{
One of the motivations of object-oriented design and private Maze myMaze;
private MazeDisplay myDisplay;
programming is code reuse. An experienced designer will private WalkerState myState;
often anticipate the possibilities of code reuse and plan an
appropriate inheritance hierarchy. The novice public GenericWalker(Maze maze,
programmer and sometimes the experienced programmer MazeDisplay display)
{ myMaze = maze;
(we speak from experience here) will realize the myDisplay = display;
possibilities after developing several classes without myState = myMaze.start();
inheritance that have some elements in common. The myDisplay.displayState(myState);
}
maze is an excellent example for illustrating this.
This can be developed as a class discussion. The idea is to protected Maze maze()
{ return myMaze;
discuss what the different maze walkers have in common }
and to "refactor" the code by pulling out the common
elements into a base class from which the other maze protected MazeDisplay display()
{ return myDisplay;
walker classes can inherit, adding only the additional }
functionality. This can be effectively done in two stages,
the first handling all the walker classes and the second protected WalkerState state()
breaking down into groups of similar classes, interactive { return myState;
}
on the one hand and "automatic" on the other. }

5.1 Refactoring: a walker base class public abstract class


Every maze walker must have the following components InteractiveWalkerStart2
extends GenericWalker
in our model: implements
• a maze MazeDisplayListener
{
• a maze display public InteractiveWalker2(Maze maze,
• its state MazeDisplay md)
{ super(maze, md);
Each also has a constructor that takes as parameters the display().addListener(this);
maze and the maze display and assigns those to its }
instance variables as well as setting the initial state using
the maze's start method. These can all be wrapped into a public void onMazeInput(String mazeInput)
{ System.out.println(mazeInput);
base class that we will call GenericMaze. In addition, of }
course, the interactive walkers need to implement the }
MazeDisplayListener interface. This results in an using the accessor methods to access the instance
inheritance hierarchy as shown in diagram 3. Here is the variables inherited from the GenericWalker. Here is the
code for a generic walker. InteractiveWalkerStart rewritten as a subclass of
This code follows the recommended pattern of keeping GenericWalker. Any of the interactive walkers would
all data fields private and providing methods for look just like this, differing only by the code within the
accessing them in subclasses. Specifying that these onMazeInput method. The random walkers or right
accessor methods are protected indicates the intent that hand rule walkers would not have the onMazeInput
they should only be accessed within the inheritance method but would instead have the run method.
hierarchy.
The code for any other walker is then simplified because
5.2 Refinement: abstract interactive walker
it does not need to redo the construction given here and Once students get the idea that inheritance can lead to
can focus on the code that makes the walker operate, much simpler code in the subclasses, then we can look

211
further into this example. A good guide for this example
is the Template design pattern that suggests a base class GenericWalker <<interface>>
implement the aspects of an algorithm that are common
MazeDisplayListener
to the prospective subclasses, and encapsulates the details
of the algorithm in abstract methods that are filled in by
the subclasses. This abstract class fits nicely into the
inheritance hierarchy.
Looking at the family of interactive walkers that were <<abstract>>
developed in the exercises, every one has a common
control structure in the onMazeInput method - they all InteractiveWalker
check the value of the parameter mazeInput and take a
different action based on its value. They all also display
the new state after taking an action. These aspects can be
drawn out in discussion with students and result in the InteractiveWalker1 InteractiveWalker2
abstract class, InteractiveWalker, a subclass of
GenericWalker, which the new versions of concrete
interactive walkers will extend, a shown in diagram 4. Diagram 4. Refinement
The code for the abstract InteractiveWalker class is public abstract class InteractiveWalker
shown below the diagram, followed by the code that extends GenericWalker
implements InteractiveWalkerStart3, functionally implements MazeDisplayListener
{
the same as InteractiveWalkerStart, as a subclass. public InteractiveWalker(Maze maze,
Each concrete interactive walker need only fill in the four MazeDisplay md)
abstract methods that specify what the walker is to do in { super(maze, md);
response to each command. Students can reimplement display.addMazeListener(this);
}
one or more of the other interactive walker variations.
public void onMazeInput(String mazeInput)
The use of the template design pattern here demonstrates {
the power of inheritance. display().eraseState(state());

5.3 Refinement: abstract automatic walker if(mazeInput.equals("forward"))


forward();
The automatic maze walkers, random and right-hand rule else if(mazeInput.equals("right"))
right();
walkers, can be refactored in a similar manner. Creating else if(mazeInput.equals("left"))
the class hierarchy is a good assignment after working left();
through the interactive walker example. It could also be a else if(mazeInput.equals("reverse"))
reverse();
fruitful class discussion, followed by students working up else
their own versions followed by presentations and throw new IllegalArgumentException();
additional discussion. The resulting inheritance hierarchy
should look much like the one given for the abstract display().displayState(state());
}
interactive walker and its subclasses, except there is no
MazeDisplayListener interface. Of course, both of protected abstract forward();
these are parts of the same hierarchy with the protected abstract right();
protected abstract left();
GenericWalker as the base class.
protected abstract reverse();
Some of the points that come up when applying the }
template design pattern to the automatic walkers are the
following: public class InteractiveWalkerStart3
extends InteractiveWalker
• they all loop until the goal is found {
• within the loop they all apply the same calls to the public InteractiveWalker1(Maze maze,
MazeDisplay md)
display methods and also incorporate a timing delay { super(maze, md);
• some, but not all, use a data structure to keep track }
of where they have been; this data structure must be protected void forward()
{ System.out.println("forward");
initialized before the loop }
• some students may have had variations that did protected void right()
something after the loop, like printing a message { System.out.println("right");
These points suggest the outline of the algorithm: }
protected void left()
initialize -- specific to each version (not needed by all) { System.out.println("left");
while loop -- }
display and timing protected void reverse()
{ System.out.println("reverse");
take a step -- specific to each version }
wrapup after loop -- specific to each version (not needed }
by all)

212
This outline is the basis for our version of the code for the give a solution that has the correct recursive algorithm in
abstract AutoWalker. terms of recursive calls and checking for walls, but leave
out any data structure that keeps track of where you have
In this code we have used a variation that can be useful in been, thereby causing an infinite recursion. Give the
application of the template pattern. Since not every students the problem of fixing this version. This puts the
AutoWalker needs to do an initialize method or a
focus on the issue of the second rule of recursion: you
wrapup method, we have made these empty methods must make progress toward the base case (the first rule is
rather than abstract methods. In that way, those versions that you must have a base case). Depending on what data
of an automatic walker that do not need them can simply structures have been covered at this point in your course,
leave them unimplemented -- the empty version in the the following are reasonable solutions to this problem:
template will be called and will do nothing. On the other • an ArrayList of locations visited
hand, the takeStep method must be implemented by
• a Boolean two-dimensional array where true
any concrete automatic walker for it to make sense, so it
indicates the corresponding position has been visited
is an abstract class.
• a Java List or Set of locations that have been
When we look at recursive walkers we will see that we visited.
can use a similar approach to organizing our classes. We
will look at advanced iterative walkers that do depth-first 6.2 Variations on recursion
and breadth-first search as classes that extend
Students can do different variations of recursive solutions
AutoWalker.
as additional exercises. For example, they can do the
recursion based on going forward, right, left, reverse from
public abstract class AutoWalker the current state or they can use the constants from the
extends GenericWalker
{ Direction class to drive the recursion. These give
public AutoWalker(Maze maze, somewhat different behavior, although there is no reason
MazeDisplay md) to prefer one over the other. A "guided" recursion would
{ super(maze, md);
first move to locations closer to the goal.
}

public void run() 6.3 Refinement of the recursion classes


{ initialize();
If more than one version of a recursive solution is done
while(!state().location().equals( by the students or used for demonstration, then one might
maze().goal()))
{ display().eraseState(state()); also look into refactoring the recursive walker classes
display().markLocation( along the lines of the interactive walker and automatic
state().location()); walker class hierarchy. Factor out the common elements
takeStep(); of a recursive solution into an abstract class and each
display().displayState(state()); specific recursive walker would be a concrete subclass of
try that abstract class.
{ Thread.sleep(100);
}
catch(InterruptedException ex){} 7 The Maze Implementation
}
An independent line of work within this framework is the
wrapup(); implementation of the Maze class. For the initial
} assignments that emphasize control structures, the Maze
protected void initialize()
{}
is left as a black-box class. But it can easily be opened
protected abstract void takeStep(); and discussed as an example for different data structures.
protected wrapup()
{} The Maze class is basically a container class that carries
} the information about the maze. The numbers of rows
ands columns and the starting state and goal location are
6 Recursion trivial instance variables. The interesting data structure is
how to store the information about walls for use by the
Finding a path through a maze is a classic problem for isWall method. In the original implementation, we use
recursion, so we will not dwell on it here, other than to an ArrayList of locations that are walls. The
make some observations as to how it fits into the implementation of the isWall method is then just a
framework that we have developed. sequential search through the ArrayList. We do not use
the ArrayList method contains because we wanted to
6.1 A recursive walker as an assignment be able to use this example in the context of using an
There are several ways to present the problem of ArrayList with a limited number of methods, accessing
recursively solving a maze as an assignment. One is to elements by index. Of course, it would be easy to
simply ask the students to develop a recursive maze substitute a call to the contains method, if desired.
walker class. In the context of what we have done up to
In fact, this brings up the issue that the appropriate
this point, this should be a subclass of the
abstraction is a set. We are using an ArrayList to
GenericWalker class. One could also give students a
partial solution to the problem. One way to do this is to represent a set; why not just use a Java Set class? This is,

213
of course the correct thing to do, as soon as the Set
public class DepthWalker0 extends AutoWalker
hierarchy has been introduced into your course. {
Stack searchStack;
Another implementation of the Maze would use a Stack visitStack;
Boolean two-dimensional array to represent the walls.
This is another exercise that can be used when two- public DepthWalker0(Maze maze,
dimensional arrays are covered in your course. MazeDisplay md)
{ super(maze, md);
Thus the Maze class provides an interesting context for }
protected void initialize()
demonstrating or making assignments on some of the { searchStack = new StackAL();
standard data structures that we cover in the first year of visitStack = new StackAL();
Computer Science: expandable arrays (ArrayList), two- searchStack.push(new
WalkerState(state()));
dimensional arrays, sets. }
protected void takeStep()
8 Data Structures { if(searchStack.isEmpty())
{ throw new IllegalStateException(
The maze framework provides some interesting "no solution");
applications of standard data structures: stacks, queues, }
setState((WalkerState)searchStack.pop());
and priority queues. By controlling an iterative search visitStack.push(state());
using these data structures we develop depth-first, if(!state().location().
breadth-first, and best-first (heuristic) searches equals(maze().goal()))
{ Location loc =
respectively. The problem of recording the moves made state().neighborTo(Direction.NORTH);
during the search and reconstructing the path provides an if(!maze().isWall(loc))
interesting application of stacks. { searchStack.push(new
WalkerState(loc, Direction.NORTH));
Since each of these searches is iterative, the classes }
implementing them can be developed as subclasses of the loc =
state().neighborTo(Direction.EAST);
AutoWalker class discussed above. Then the focus can be if(!maze().isWall(loc))
on the steps that need to be done, without regard to the { searchStack.push(new
graphics display that is taken care of in the AutoWalker WalkerState(loc, Direction.EAST));
class. }
loc =
state().neighborTo(Direction.SOUTH);
8.1 Depth-first search if(!maze().isWall(loc))
{ searchStack.push(new
We propose giving a partial solution for this class, WalkerState(loc, Direction.SOUTH));
leaving the students two parts to complete. First, we give }
loc =
a correct iterative depth-first search algorithm using a state().neighborTo(Direction.WEST);
stack for the intermediate storage structure, but without if(!maze().isWall(loc))
any means for preventing the search from repeating itself. { searchStack.push(new
The first problem is for the student to select a data WalkerState(loc, Direction.WEST));
}
structure and modify the methods so that the search does }
not loop endlessly, but eventually moves to the goal. }
The second part of this assignment that the student needs protected void wrapup()
to complete is the recovery of the path from start to goal { displayPath(extractPath());
that is found, with no side paths. We have the main }
search put every state that is checked onto the stack private Stack extractPath()
visitStack. The problem is then to write a helper { Stack path = new StackAL();
method extractPath, that extracts the path itself as a // code to extract path
// from visitStack here
stack, with goal at the bottom and start at the top. return path;
}
Here is the initial code for the DepthWalker class that
the student is given. It is a subclass of AutoWalker. private void displayPath(Stack path)
Recall that any such subclass needs to implement the { while(!path.isEmpty())
takeStep method and, optionally, the initialize and { WalkerState current =
(WalkerState)path.pop();
wrapup methods. We use an interface for Stack, with display().displayState(current);
implementing class StackAL, These are taken from }
materials developed for the College Board AP CS }
}
program, available at http://apcentral.collegeboard.com
pop to enqueue and dequeue. (We provide a Queue
8.2 Breadth-first search interface and implementation from the AP CS program.)
We can modify the depth-first search, once completed, to Note that the visitStack stack should not be changed.
become a breadth-first search simply by replacing the These two walkers demonstrate two standard search
searchStack with a queue, changing calls to push and strategies used for finding a goal and even for an optimal
solution to a problem, such as a shortest path.

214
8.3 Best-first search The advantages we see to using case studies include:
• Complexity in a controlled situation
A "best-first," "guided," or "heuristic" search is a search
• Introduction of objects early
based on a criterion for determining that some steps in the
search are more promising than others. In the case of the • Incremental introduction of topics
maze problem, we take the location with the shortest • Provide a familiar context for students throughout a
distance to the goal as the most likely to lead to the goal. course
In order to carry out a best-first search we replace the • Provide a realistic context for the application of
stack or queue used previously with a priority queue with concepts
the distance to the goal from a given state as the priority • Provide a context for introducing design patterns
For the priority queue we use the PriorityQueue
interface used for the AP CS program and provide a min- 10 References
heap implementation. This requires a class that contains Alphonce, Carl, and Phil Ventura, 2002. "Object-
an item (state) and its priority (distance to maze goal). Orientation in CS1-CS2 by Design," Proceedings of the
Otherwise we simply replace the searchStack with a 7thAnnual Conference on Innovation and Technology in
priority queue, using the methods add and removeMin in computer Science Education (ITiCSE 2002), 70-74.
place of push and pop.
Astrachan, Owen, Geoffrey Berry, Landon Cox, Garrett
This sequence of assignments gives examples of the use Mitchener, 1998. "Design Patterns: An Essential
of these three standard data structures within an Component of CS Curricula," ACM SIGCSE Bulletin v
interesting context. It also is the beginning of topics that 30 n 1, 153-160.
would be covered in a more advanced course on
Barnes, David, and Michael Kolling, 2003. Objects First
algorithms, such as finding the shortest path or
with Java, Prentice-Hall: New York.
developing a branch-and-bound algorithm.
Brady, Alyce, 2002. The Marine Biology Simulation Case
8.4 Classroom experience Study, The College Board: New York. Available from
http://apcentral.collegeboard.com. Accessed Nov., 2003.
One of the authors, Nevison, has used both the recursion
assignment and the depth-first, breadth-first, and best-first Bruce, Kim, Andrea Danyluk, Thomas Murtagh, 2001.
search assignments in a second computer science course, "A Library to Support a Graphics-Based Objects-First
with the focus on data structures. These assignments Approach to CS 1," ACM SIGCSE Bulletin v33 n1, 6-10.
worked quite well. The students liked working with a Christensen, Henrik, and Michael Caspersen, 2002.
problem with a visual component, and the visualization "Frameworks in CS1 - a Different Way of Introducing
provided feedback on the how their program was Event-driven Programming," Proceedings of the
working. For example, seeing a recursive or iterative 7thAnnual Conference on Innovation and Technology in
solution that continuously moves between two or a few computer Science Education (ITiCSE 2002), 75-79.
states demonstrates the problem of not keeping track of
where one has been previously to force progress toward Clancy, Michael, and Marcia Lin, 1992. "Case Studies in
the base case (the maze goal). the Classroom," ACM SIGCSE Bulletin v 24 n 1, 220-
224.
Another example of the effectiveness of visual feedback
is the assignment to implement the extractPath Gamma, Helm, Johnson, and Vlissides, 1994. Design
method for the depth-first and other iterative searches. Patterns, Addison-Wesley: Boston.
Students will often get a "solution" that compiles and Nevison, Christopher, and Barbara Wells, 2003.
runs, but when run marks a "path" from start to goal with "Teaching Objects Early and Design Patterns in Java
many side branches. This visual feedback shows that the Using Case Studies," Proceedings of the 8th Annual
program has problems and may provide clues as to what Conference on Innovation and Technology in computer
the problem is. Science Education (ITiCSE 2003).
Students find these assignments to be interesting and get Nygaard, Kristen, 2001. Invited Talk OOPSLA'01,
engaged with finding good solutions. Some students are Educators' Symposium
ready to take the problem a step further with an extra
credit shortest-path solution for the maze. Nygaard, Kristen, 2002. "COOL (Comprehensive Object-
Oriented Learning," (keynote address) Proceedings of the
9 Summary 7th Annual Conference on Innovation and Technology in
computer Science Education (ITiCSE 2002), 218.
We have presented an example demonstrating how one
can use case studies to teach introductory computer Proulx, Viera, 2000. "Programing Patterns and Design
science from the early in the first course through the Patterns in the Introductory Computer Science Course,"
material typically covered in the first year of Computer ACM SIGCSE Bulletin v 32 n 1, 80-84.
Science. We have had success with this approach in our Proulx, Viera, Jeff Raab, Richard Rasala, 2002. "Objects
own classes. from the Beginning," Proceedings of the 7th Annual
Conference on Innovation and Technology in computer
Science Education (ITiCSE 2002), 70-74.

215

You might also like