Fundamentals of Computer Science II (CSC-152 97F)

[News] [Basics] [Syllabus] [Outlines] [Assignments] [Examples] [Readings] [Bailey Docs]

# Outline of Class 33: Puzzles and Iterators

## Miscellaneous

• I'm accepting applications for Spring Term for
• Any questions on assignment five?
• Three new assignments today, all due a week from Thursday. Note that rather than making one assignment with three parts, I've separated it into three assignments.
• assignment 6: sorting. This shouldn't take too much time.
• assignment 7: reverse polish notation. This also shouldn't take too much time.
• assignment 8: puzzle solving. This will be somewhat longer.

## Solving Puzzles

• We've done a quick generalization of both the shuffling coins and the maze solving problems from Bailey.
• There is a `Puzzle` object that supports
• `reset()` reset the puzzle to its initial state
• `legalMoves()` list the legal moves
• `makeMove(Move m)` make a legal move
• How do we solve it?
• Our first attempt, repeatedly picking a random legal move, isn't guaranteed to work.
• You can get loops, in which you keep switching between a set of intermediate stages, and never get any further.

### Shuffling Coins

• Let's step back and think about how we might solve the problem of shuffling the coins.
• We might improve our method by keeping track of whether we've seen positions.
```// As long as we haven't found a solution
// Pick a legal move that doesn't lead to a board we've already seen
// Make that move
```
• However, this improvement may make us fail to find a correct solution. Why? What if, at a particular board state, only one move can lead toward a correct solution. If we make another move, we can't return to the board state and try another. So, we need to keep track of possible board states to work from.
```// As long as we haven't found a solution AND
//   there is a board state + legal move combination we haven't tried
// Pick one of those combinations
// Make the move
```
• We can use any linear structure to keep track of the board state + legal move combinations. It's easy to store them by actually making the move (and, perhaps, keeping track of the move we just made).
• In something closer to Java (but not precisely java)
```/**
Find a solution to a puzzle using a brute-force method.
pre: The puzzle has been initialized.
post: The solution is printed.
*/
public void solve(Puzzle p) {
Set checked = new Set();	// The boards we've already checked
MoveList moves_to_make;	// The moves from current pos.
Linear todo = new Linear();	// The boards we still need to check
Puzzle current;		// The current state of the puzzle
Puzzle next;			// The next state of the puzzle
// Start at the beginning
current = p;
current.reset();
// Keep going until we find a solution (exit within loop) or
// run out of things to try
while (!todo.empty()) {
// Get the next board position and moves used to generate that position
current = todo.remove();
// Is it a solution?
if (current.solved()) {
print "Solved the puzzle.  Guess how?"
return;
}
// If not, consider all alternatives
moves_to_make = current.legalMoves();
for each move in moves_to_make {	// This is not legal Java
// Make the move
next = current;
next.makeMove(move);
// If we haven't seen the position, add it as something to consider
if (!checked.contains(next)) {
} # if we haven't seen this position yet
} // for each
} // while
print "The puzzle had no solution.";
} // solve
```
• We might also extend our code to print the solution.
• We'll put pairs consisting of the board and the moves to get there on the stack.
• Here's a revised solution ...
```/**
Find a solution to a puzzle using a brute-force method.
pre: The puzzle has been initialized.
post: The solution is printed.
*/
public void solve(Puzzle p) {
...
MoveList moves_made;		// The moves made to reach the current state
Move move;			// One move
Pair p;			// A board/moves pair,
...
// Start at the beginning
...
todo.add(new Pair(current, new MoveList());
// Keep going until we find a solution (exit within loop) or
// run out of things to try
while (!todo.empty()) {
// Get the next board position and moves used to generate that position
p = todo.remove();
current = p.first();
// Is it a solution?
if (current.solved()) {
return;
}
// If not, consider all alternatives
moves_to_make = current.legalMoves();
for each move in moves_to_make {	// This is not legal Java
// Make the move
...
// If we haven't seen the position, add it as something to consider
if (!checked.contains(next)) {
} # if we haven't seen this position yet
} // for each
} // while
print "The puzzle had no solution.";
} // solve
```
• Bailey cleverly observes that if we use a queue as our linear structure, then the first solution printed out is also one of the optimal solutuions. Why? Because of the structure of queues. First, all the states reachable in 0 moves are added, as each is removed and its successors are added, only those reachable in 1 move are added, as each is removed and its successors are added, only those reachable in 2 moves are added. So, we consider the reachability in order.

### Solving Mazes

• Clearly, we could use the same strategy to solve a maze, since we've written a generic puzzle-solving algorithm.
• This queue-based solution is typically called a breadth-first exploration of the maze. You look at all the squares of distance one, then all squares of distance two, then all squares of distance three, and so on and so forth.
• Unfortunately, this would not be so efficient if you had to do it by walking around the maze, as all squares of distance three may be widly separated in the maze.
• In practice, we typically do a depth-first exploration of the maze. You go as far as you can, making decisions as you go. If you reach the exit, you're done. If not, you back up to your last choice point with choices left to go, make a different choice, and go on.
• By using stacks instead of queues in our generic puzzle solver, we can acheive such a search.

## Iterators and Enumerations

• Many algorithms have portions that rely on looking at all the portions of a source structure.
• In our puzzle solving method above, we used a `for each move in legalMoves` strategy, which we would then need to implement more precisely for each type of puzzle.
• Similarly, I could write a generic minimum routine as follows (this is not real Java):
```/**
Compute the minimum in a group of integers.
pre: The group is nonempty.
post: The group is unaffected.
*/
public int min(Group g) {
int guess;	// Current guess as to the minimum
int val;		// The next value;
// Get a start guess
guess = g.someElement();
// Compare to each other element, reducing our guess whenever
// possible.
foreach val in g {
if val < guess
guess = val;
}
// We're done
return val;
} // min
```
• However, rather than rewriting my routine for each different structure, I might instead provide a standard way of getting all the elements in a structure.
• `Enumeration`s and `Iterator`s are structures that give you the elements of some structure, one by one, and thereby support these types of algorithms. They maintain a state that helps them keep track of which elements they have and have not returned.
• `Enumeration` is a standard Java interface, defined in `java.util`.
• `Iterator` is Bailey's refinement of `Enumeration`.
• Both provide
• `hasMoreElements()` which returns true if there are more elements to enumerate.
• `nextElement()` which returns the next element in the list.
• Using these two functions, one might write minimum as follows:
```/**
Compute the smallest element in an enumeration.
pre: The enumeration is nonempty.
pre: No elements have been removed from the enumeration.
pre: All elements in the enumeration are comparable.
post: The smallest element is returned.
*/
public Object min(Enumeration stuff) {
Object guess;	// Current guess as to the minimum
Object val;	// The next value in the enumeration
// Get a start guess
guess = stuff.nextElement();
// Compare to each other element, reducing our guess whenever
// possible.
while (stuff.hasMoreElements()) {
val = stuff.nextElement();
if (val.lessthan(guess))
guess = val;
} // while
// We're done
return val;
} // min
```

Outlines: prev next

[News] [Basics] [Syllabus] [Outlines] [Assignments] [Examples] [Readings] [Bailey Docs]

Disclaimer Often, these pages were created "on the fly" with little, if any, proofreading. Any or all of the information on the pages may be incorrect. Please contact me if you notice errors.

Source text last modified Mon Nov 3 09:31:50 1997.

This page generated on Wed Nov 5 12:38:27 1997 by SiteWeaver.

Contact our webmaster at rebelsky@math.grin.edu