Download presentation

Presentation is loading. Please wait.

Published byAllison Alexander Modified over 3 years ago

1
Programming Problems That Illustrate Reuse Dr. William Mitchell LSU-Shreveport

2
Having taught the Software Engineering Project Course for several years, I approached the assignment last summer of teaching Java as a second language in the majors programming sequence with the motivation to impress upon the class the opportunity that Java offers to solve problems with an eye to reusing the classes generated. My Motivation One of my students dropped a problem into my lap that I recognized could make the point.

3
The goal of this board game is to manipulate the red piece to the position now occupied by the four yellow pieces.

4
There are 6 different initial moves (only blue pieces can move, and the vertical blue piece has two moves--top two blue moves not shown) Initial state--> Neighbor states

5
Once a blue piece adjacent to a yellow piece is moved, the yellow pieces can be re-distributed (not all pictures are neighbors).

6
The solution strategy was to employ Wirths back- tracking algorithm (depth-first recursive search). I partitioned the problem into GameStates, represented by the different diagrams and I searched for the solution state (cells row 3 and row 2, columns 4 and columns 5 all RED, numbering rows from the bottom and columns from the left). The algorithm starts in the initial state, asks if it is the solution state, else creates a new state if possible. Either the new state is a solution or another state can be created. Either the solution state is encountered among those created, or the point is reached at which no new states can be created. Certain problems have to be dealt with.

7
I defined two GameStates to be neighbors if one could be converted into the other by moving a single piece. I then constructed a nextNeighbor method to cycle through the neighbors of any state. To avoid loops, I needed a way to determine if any created GameState had previously been created. I seized upon the two empty squares as a method for partitioning all the GameStates and used them to key a lookup table into which I placed all visited states. A not-previously-visited neighbor state became the next candidate for a solution when a non-solution GameState was found. When a solution was found, I needed to recount the path taken to the solution, so I recorded the path in a linked list as I snapped back from the tail recursion.

8
The main class, PlayGame, therefore creates the initial instance of GameState, tests each state for solution and if not, recursively calles for the generation of a new state. It declares a global array to hold the link lists of visited states and received a solution in the form of a linked list of GameStates. To this class I added a routine that refined the solution by cutting out ox-bowloops, and a display routine that prints out a list of moves from initial to terminal state. PlayGame is concerned with the search space of GameStates. It doesnt care what the game is. The GameState class knows that the game involves a rectangular board and various pieces. Its constructors build a board with the pieces in their initial positions, or create a new state from a given GameState instance.

9
Each GameState instance owns a GameBoard instance that encapsulates how the pieces are registered on the board. The GameState class uses a square number to identify the location of a piece and the GameBoard takes care of determining which squares are occupied and where the two empty squares are. Each GameState owns an array of pieces. The abstract class Pieces provides fields for color and location, but each individual piece class provides methods for determining what, if any, moves that piece can make (zero, one or two). Pieces determine their move possibilities upon the creation of the GameState by asking the GameBoard for the availability of adjacent empty squares and store the moves as one or more of N, S, E, or W. Two GameStates are equal if their boards are identical.

10
Each GameState instance has a state ID generated from a class field counter, and a Neighbor counter to record how many times it has been asked to generate a neighbor state. The Neighbor state is generated by stepping through the piece array and making each move in sequence that each piece can make. A GameState constructor creates the Neighbor state as the state existing after the specified move is made. The GameState class also has the boolean methods equals() and isNeighbor(). The GameState class is thus concerned about creating new states by making valid moves, but has no knowledge of how moves are made nor of the fact that different pieces have different rules for making moves. It knows only that in each state a certain number of pieces report that they can make a specified number of moves.

11
The GameBoard class answers questions about the state of a square at a given distance and direction from a reference square. It can also provide square names. It is free to code each square as it chooses. It knows nothing about the nature of the pieces or how they use the codes it returns. Each piece knows how to determine if it can move (how to ask the GameBoard if the requisite squares are free) and stores its move possibilities. It also stores its move history in a stack using the GameState ID that corresponds to that move. When backtracking occurs, each piece can return itself to its earlier position.

12
Decomposing the problem into four classes permitted me to change the board dimensions, the number of pieces, and the initial position of those pieces in the GameState class. I then created a new piece class, Queen, with its own rules of movement. I then changed the registration method in GameBoard so that it coded not only each pieces position on the board but how many shadows crossed each square (each time a piece was registered, the shadow count on row and file and diagonals was incremented). Queens preferred to move from a square with high shadow count to one with a low shadow count. I then had to change the win() routine from testing to see if the RED piece was located in its final position, to determining if each row had only one queen. I did not care about the steps taken to move seven of the Queens from the first row to other rows, but those instructions were available.

13
In the last SIGCSE Bulletin (32,1) Robert Noonan presents a paper entitled An Object-Oriented View of Backtracking. He gives the Java code for using the Backtrack algorithm as an interface and the java.util.Enumeration class to hold the moves to solve both the Eight Queens problem and the Knights tour. I had not seen this paper, but then neither had last summers Java class been introduced to the enumeration class or interfaces. Noonan also intends to illustrate reuse (of the interface) but the two problems both use square boards and consist of placement of pieces of a single type. My illustration solves dramatically different board problems within the same conceptual framework and permits refinement of the solution found via backtracking.

14
Noonan laments that fact that the backtracking algorithm is virtually ignored in popular programming and data structures texts. I agree and have therefore incorporated a prior application of recursive search in my Java as a second language course this semester. This is the solution of the letter arithmetic puzzles. I pose and provide most of the code for addition and ask that the students think about how to implement so as to minimize the changes needed for subtraction. Letter addition is solving WIRE + MORE MONEY by substituting the same digit for each letter so as to produce a valid arithmetic fact.

15
Since there are 8 distinct letters, there are 10!/2! substitution patterns for E,I,M,N,O,R,W,Y. We can find a solution with eight nested for loops that implement a depth-first search of the tree E = 0..9 {I = 0..9 & !(I==E) {M = 0..9 & !(M==E) & !(M==I) {…. {test substitution pattern}…. A more intelligent search incorporates facts about the relationships of the values of the letters that can be deduced from their location in columns. In this case, we know that M is 1 because it is the value of the carry out of the 4th (10 3 ) column. We then know that W + M + Carry in = O + 10. Thus if Carry in is 0, we have W + 1 = O +10, whence W=9 and O= 0, or if Carry in is 1, W + 1 + 1 = O + 10, and W=8 and O=0 or W=9 and O=1. Since we know that M=1, we can deduce that O=0.

16
In general, each column represents four equations determined by the possible values of Carry in and Carry out. The problem can be solved by searching for substitutions which satisfy these equations, simultaneously. A valid problem can have at most 10 distinct letters and may have more than one solution (this example has fie different solutions). I assign the students to write the problem class that inputs the three words and tests to see if they compose a valid problem. This class also provides methods to set a solution (the list of digits that corresponds to the alphabetical list of distinct letters) and to obtain a column of letters from the three words. Since all of the character and string manipulations are concentrated in this class it also provides the methods to display the problem and its solution.

17
I provide the solution class that starts with the highest column, sets the solution string to blanks, and makes a recursive call to a static method that tries to make a valid assignment to the letters in its column. If successful, it updates the solution string and make a call to continue making assignments to letters in the next lower column. Otherwise it returns to its caller to see if an alternative assignment can be made in the previous column. As in the eight queens problem, if assignments can be made in every column down to the units column, then a solution is found. Since the highest column has Carry out of 0, it generates two equations dependent upon its Carry in values. The search for candidate assignments is made by creating new instances of an Equation class, each initialized with a pointer to the problem instance containing the current partial solution, the column number, and the Carry in value. Each instance has an allocate method that returns true if it can find another assignment and update the partial solution string.

18
The problem class knows nothing about the kind of arithmetic that is being solved. The solution class instantiates an instance of a problem and commences the recursive descent to find a complete solution string, and it doesnt know anything about the letters involved or the partial solutions being generated. It knows only that it must create an Equation instance for each of two possible values of Carry in and pass to each as the value of Carry out the value assumed for Carry in by its caller. The Equation instance know what equation (addition or subtraction) it is trying to satisfy, and it must cycle through the permutations of available digits for allocation to the unassigned letters in this column. Thus the Equation class previews the GameState class and its allocate method behaves like the nextNeighbor method. The solution class anticipates the PlayGame class. Letter Arithmetic precedes the game by a month.

19
The essence of good design is that it permits modifications of the kind most likely to be required in the future. However, when learning to program students seldom think about any problem other than the specifics of the one assigned. I (and other instructors) have sought to devise problems that dramatically illustrate the power of good design by quickly and easily adapting one problems solution into the solution of a seemingly dissimilar problem. The designers ability to abstract the characteristics of the initial problem permits the design of its solution to reveal the similarity of the whole class of problems related to the initial one. Conclusion

20
This presentation and the Java code for the implementation of the classes discussed in this talk as well as a recent paper focused on teaching about code reuse when teaching Java can be found on the authors website: 204.196.51.10

Similar presentations

OK

§5 Backtracking Algorithms A sure-fire way to find the answer to a problem is to make a list of all candidate answers, examine each, and following the.

§5 Backtracking Algorithms A sure-fire way to find the answer to a problem is to make a list of all candidate answers, examine each, and following the.

© 2017 SlidePlayer.com Inc.

All rights reserved.

Ads by Google