CS 340 - Software Design

Machine Problem 4, Fall 2005

Sliding Block Puzzles

Due: Thursday, November 3, 2005 at 11:59 pm

A sliding block puzzle consists of a number of pieces that fit into a confined area. The goal is to move one of the pieces to a specific position. This piece will be called the "goal piece". The goal can only be acheived by moving all of the pieces is a certain specified order of moves. Each piece may be restricted in the direction that it can move.

Consider the following puzzle:

3 4
Z 5

The puzzle contains 8 pieces. The piece labeled "Z" is the "goal piece". This piece must be moved to the right hand edge of the puzzle. In this puzzle all pieces can move any direction we wish (left/right or up/down). One solution is to move piece 4 left one space, then move piece 7 up 3 spaces and left 1 space, then move piece 5 right one space then up 2 spaces, then finally move piece Z right 2 spaces. The result looks like this:

12 75
3 4

Your program is to find the shortest solution for these types of puzzles. The solution will always have the goal piece move to the right hand side of the puzzle grid (i.e. once the goal piece moves into the last column). Your program is take a command line argument that will contain the name of a data file containing the needed information about the puzzle. The output of the puzzle will be a sequences of moves that give the shortest solutions.

The solution is to be given as an ordered list of moves. Each move is to show the Piece moved, the direction (up, down, left or right) and the number of spaces moved in that direction. The solution for the above puzzle is as follows:

1.Piece 4left1 space
2.Piece 7up3 spaces
3.Piece 7left1 space
4.Piece 5right1 space
5.Piece 5up2 space
6.Piece Zright2 space

The shortest solution will have the fewest number of moves. Note that there could be multiple shortest solutions for a puzzle. Finding any one of these shortest solutions is good enough for this programming assignment. The above solution could have reversed moves 3 & 4 and still have been the shortest solution. Your program is to treat the following as 1 move:

2.Piece 7up3 spaces

while the following is considered 3 moves:

2.Piece 7up1 space
3.Piece 7up1 space
4.Piece 7up1 space

The input for a puzzle will always come from a file.

Each piece will always have a rectangular shape (while such puzzles with non-rectangular shape do exist, it adds a complexity we don't need to deal with here). Each piece's starting position is given by 4 integer values and one character value. These values will be separated by one or more white space characters.

If a piece would fall outside of the puzzle grid, have an invalid direction of movement, or overlap with another piece, an appropriate error message should be printed and the piece should be discarded from the puzzle (i.e. don't quit the program). If the goal piece is listed incorrectly, the first correctly listed piece becomes the goal piece. The upper left corner of the grid has row = 1 and column = 1. The input for the above puzzle would be as follows:

	4  4
	3  1  2  1  b
	1  1  1  1  b
	1  2  1  1  b
	2  1  1  1  b
	2  3  2  1  b
	3  3  1  2  b
	4  1  2  1  b
	4  4  1  1  b
Note that the names of the pieces are not specied in the input file. The goal piece will always have the name of "Z". The next nine pieces will have the names from "1" to "9". The next 26 pieces will be given names using the lower case letters from "a" to "z". The next 25 pieces will be given names using the upper case letters from "A" to "Y" (since "Z" is already in use). If the file has more than 61 pieces, come up with some additional naming scheme. You can assume a puzzle will have less than 128 pieces. The actual file is here in the file "mp4a.data". Other data files are:

It is possible that a puzzle may have no solution. Your output from the program should be written to standard output and should consist of four parts:

  1. Any error messages generated by invalid input.

  2. A listing of the grid as the start of the puzzle. This can be a simple ASCII graphic as shown below:
    *12  *
    *3 44*
    *ZZ5 *
    Perhaps using periods instead of spaces makes this a bit more readable:
    Of course, this grid is less readable if the grid so large that it causes line wrap (but this is not the programmer's problem).

  3. Then list out the moves that solve the puzzle or a message stating the puzzle is not solvable.

  4. A list of the grid showing the solution, if one exists. For example:

For 10 points extra credit, allow an optional flag to be read in from the command line. The flag is "-h". This flag will cause output to be placed in an html file as well as to the normal output to standard output. The html filename will be the same as the input data filename with the file extension of ".html". The output in the html file should contain the same information as the standard ouput, but it should be formatted better. The grid(s) in this html file should use html tag of <table> as was shown in the write-up of this assignment. The list of moves should show the information is some neat arrangement. How you do this is left completely up to you (do not expect hints from either the instructor or the TA).

For 15 points extra credit, you can have your solution be displayed in a Java GUI window in addition to displaying the output to standard output. You should display the initial layout of the puzzle, the steps for the solution and the final solution of the puzzle.

Your program is to take full advantage of the Java Collection Classes. This library contains classes for a number of data structures that can be used in solving this problem. The idea is "why write your own code if someone else already has done it". This is not to be taken to the extreme of "borrowing code" from fellow class members.

To store your data, you will need to create a class to hold each piece. The puzzle will be a collection of these pieces. Since the number of pieces is unknown, this should be dynamic. The use of the Collection classes of Vector or ArrayList would be a good choice here. When trying to find the shortest number of moves, the breadth-first search algorithm will work. Since the breadth-first search uses a queue, the use of the Queue Interface of the LinkedList class is good choice when implementing a breadth-first search.

A good algorithm to solve this problem is to create a class that will hold a "snapshot" of the puzzle. A snapshot is to contain all needed information about the "current" state of the puzzle. The current state is the current position of all pieces in the puzzle and what moves it took to reach the current state from the initial state. So the snapshot needs two main sets of data: the pieces with their positions and a list of moves. The initial state/snapshot is the position of the pieces as given in the input file and zero moves (an empty move list). Then all of the snapshots that could be created from moving a single piece from the initial snapshot are added onto a queue (be sure to add the move information to the list of moves). If moving the piece causes piece Z to move to the right-most column of the puzzle, the puzzle is solved and the move list which contains the solution is printed. Then the first snapshot is removed from the queue and all of the snapshots that could be created from moving a single piece from this snapshot are added onto the queue. If we attempt to remove a snapshot from the queue and the queue is empty, the puzzle has no solution.

Of course, we have to make sure that arrangement of pieces only is added onto the queue one time; otherwise, we may get into an infinite loop. One way you do this is to create a simplified version of the current layout of the pieces and to store and compare this simplified version using an Implementation of the Set interface like HashSet or TreeSet. One way to create a simplied version is to create a string from the puzzle. The string would have (# of rows)x(# of column) characters and the first (row-length)-th character would have the piece names from the first row (using a space character for an empty position in the puzzle. , the second (row-length)-th characters would have the piece names from the second row... For example the initial puzzle from above would have the following 16 character string:

	"12  3 44ZZ5 6657"
and the solution of the puzzle would have the following 16 character string:
	"12753445  ZZ66  "
This idea is nice, since comparisons are already defined for strings, we don't have to make up some complicated algorithm to determine if two snapshots have all of their pieces in the same positions.

What are the possible first moves from the initial puzzle shown above? The first piece I would check would be the Z piece, since moving that piece determines if the puzzle is solved and if a solution is found, the remaining pieces don't have to be moved. The following is a piece by piece listing of the first moves from the inital puzzle:

Therefore, after the first initial snapshot is taken care of, the queue should have 7 snapshots on it. One for each of the moves mentioned above.

Programming Style Grading Criteria

The programming style grade is worth 1% of the final grade for each assignment. Thus the functionality of each assignment is only worth 4% of the final grade. The programming style grade will have a maximum score of 45 and will be graded based on the following criteria.

5 Title page short header: The front page of your program must have a header with your name, course, TA, data, system, and a short description of the program, such as:
     /** ---------------------------------------------------------
     * This program implements a calculator that does addition subtraction,
     * multiplication, and division.
     * Class: CS 340, Spring 2005
     * System: NetBeans IDE, jsdk 1.4.2, Windows XP
     * @author Dale Reed
     * @version January 16, 2004
10 Title page(s) complete description: Following the above short header, you should give a detailed description of what this program does (2 paragraphs minimum). This should be followed by an intuitive description of how you implement your solution, including a description of principal data structures and modules or sections of code. Any extra credit work should be explicitly documented. This section should also include directions on the compilation and execution of your program.

This should include a section called Status: Elements of the assignment that do not work should be well documented here. If some assigned element of your program does not work and you fail to document this, you could lose double the points for this than you would have otherwise.

You may wish to write all this information into a separate README file. This should be done especially when the program has multiple source code files.

5 Meaningful Identifier Names: Identifier names should indicate their purpose. Names should be words separated using capitalization, such as gradesSum. Short loops of ~ 5 lines can use loop counter variables such as i or j.
10 Comments. Every function must have a short description stating the purpose of the function, what it receives, and what it returns. Comments should be easily identifiable. I should be able to understand your program by reading only the comments. Also include a header at the top of your program (see example below) that must include lab day and TA name.
5 Decomposition: A segment of code that appears more than once should be extracted to form a separate method (in Java) or function (in C). Methods/Functions should be no longer than around 50 lines. Objects are used appropriately.
5 Appropriate data and control structures: Global variables should be avoided and used only when necessary. Method/Function parameters should be used instead. Appropriate looping and decision structures used.
5 Code Layout: Different nested levels should have different indentation, where statements at the same level should have the same indentation. Indent at least 3 spaces. Use either spaces or tabs consistently.

How to turn in your work

Your program is to be submitted electronically via the turnin command on the LINUX machines. The project name for this is mp4. All programs are expected to be written in good programming style.

Turnin your program electronically using the "turnin" command from your CS account as follows:

turnin -c cs340 -p mp4  [your project directory]
where the [your project directory] is the directory name under which you have all your files related to this programming problem. The turnin command will automatically compress the data under your directory, so there is no need to do the compression by yourself.

Notice you can only invoke turnin command on the Linux machines in the lab or after logging into the server machine oscar.cs.uic.edu.

If you want to verify that your project was turned in, look in the turnin directory for a file with your userid. For instance for this project, from your CS account you would type:

    turnin -c cs340 -p mp4 -v