Homework #6 CMSC 131
Due March 16th, 2003 Object-Oriented Programming I
  Spring 2004

1D Puzzle

This homework will give you practice working with arrays, and writing a program that responds to user events. You will be graded as follows:

You will write a program that lets a user play a simple one-dimensional puzzle (see figures below).  The puzzle consists of a sequence of cells, each with a string of text.  The user can move the cells according to the following two rules:

  1. Clicking on any non-blank cell will shift that cell and all cells between that cell and the blank cell towards the blank cell.  This will result in the cell you clicked on becoming blank.
  2. Clicking on a blank cell will swap the two cells on either side of the blank cell (assuming the blank cell wasn't at either end of the puzzle in which case nothing happens).

The player's goal is to arrange the text in to it's natural order (i.e., in increasing order - "0, 1, 2, 3, 4, ...").  The puzzle should start with a sequence of randomly generated unique numbers out of [0, n-2], assuming n cells.  The following sequence of images shows what happens when the user clicks on the highlighted cell (i.e., each screenshot shows the state of the puzzle after clicking on the highlighted cell of the screenshot above it. The real puzzle does not have a highlighted cell.)

This is an event-driven program.  That means that once the program is initialized, the puzzle is displayed and nothing else happens until a user clicks on it.  Then, on each interaction (mouse clicks in this case), a "callback" method within the application is called.  This callback method (called an event listener) must respond to the interaction by modifying the puzzle appropriately.

The event listener is one part of an overall design pattern called "Model View Controller".  The model specifies the internal data structures that represent the state of the system.  The view represents the visual presentation of the model.  The controller (implemented through the event listener) specifies how the user interacts with the view in order to change the model.  You must fill in the details of the supplied Puzzle class which implements the PuzzleMVC interface which requires four methods (corresponding to the three components of MVC and one method to test if the puzzle has been solved).  To help you get started, the supplied Puzzle.java sets up the basic structure of your solution.  This is included along with the PuzzleMVC interface and the PuzzleFrame class which implements a window frame that accepts your MVC (through the setPuzzleMVC() method) and calls your methods appropriately. 

In particular, PuzzleFrame guarantees that it will initially call generatePuzzle() once.  After that, it will call cellClicked() whenever the user clicks on the puzzle, and getContents() whenever the contents could have changed. 

Getting the Code Distribution

We will be using CVS with AutoCVS as we have for previous assignments.  You can access the assignment code by checking it out from CVS with Eclipse (it is called 'hw6'). You can read the API documentation here

Your Assignment

You must implement the following three methods defined in Puzzle.java. Note that the supplied Puzzle constructor and getContents() method are already complete.

public void generatePuzzle(int numCells);

generatePuzzle() creates the initial "model" of the puzzle.  Given the number of cells the puzzle should have, it must initialize the "cells" instance variable to an array of "numCells" strings where one of the strings is blank ("") and the others are unique random numbers in the range [0, numCells-2].  You should use the code "(int)(Math.random() * maxValue)" to generate a random number in the range [0, maxValue-1]  (3/11 10am: This is corrected, it originally said [0, maxValue] which is incorrect).  However, you must think about how to generate the sequence of random numbers so that none are repeated.

3/11 10am addition: You will also need to convert the integer you generate into a string to be stored in an element of cells.  This can be done with the Integer.toString() method which takes an integer as a parameter and returns a string.  An example is:

String s;
int i = 5;
s = Integer.toString(5);

Here is a (substantial) hint: Put the blank at the end of the array.  Then, for each other cell, generate a random number and check if you have already used it (by comparing against previously filled cells).  If you have already used it, generate another.  Keep generating and checking until you have generated a unique number.

public void cellClicked(int cellNum);

cellClicked() specifies the puzzle "controller", that is, it is an event listener that gets called whenever the user clicks on a piece.  This method must modify the array of cells to reflect the game interaction logic described at the beginning of this assignment.  It does not have to worry about updating the board as PuzzleFrame takes care of that.

public boolean isSolutionCorrect();

isSolutionCorrect() determines if the current puzzle is in a correct solution state and returns true if the puzzle is correct.  It is your job to determine if the puzzle is currently correct (that is, if the cells are in order and the blank cell is all the way on the right.)

Submitting Your Assignment

Submit your program by right-clicking on your project and select "Submit Project". Note that this option will only appear if you have successfully installed AutoCVS as described previously.  If you decide that you would like to make a change after you have submitted your project, you can resubmit as many times as you like before the extended deadline.  We will grade the last project submitted.

/* Name
 * Student ID
 * Homework #6
 */

<your code goes here>

Closed Assignment

This is an "closed" assignment.  You must do this assignment entirely by yourself.  You may not look at other people's code or show your code to others (except for the class instructors and TAs).  Any violations will be considered academic dishonesty and will be handled as such.

Challenge Problems

Write a method called "solve()" to solve the puzzle.  There are three classes of solutions you might try.  In each case, solve should repeatedly call cellClicked() within a while loop, and continue until isSolutionCorrect() returns true.  You should test your solution for increasing puzzle sizes (starting at size 3), and for size, count how many times cellClicked was called.  Then print a table showing the number of clicks for each puzzle size.  The three approaches you might try are:

  1. Random.  Just click on random squares until you get the correct solution.  You may find that this solution gets slow very quickly as the size of your puzzle increases.
  2. At each step, calculate a "fitness function" for each potential click based on some metric of fitness that you devise.  Then, actually click on the cell with the highest fitness.
  3. Think about how you as a human solve the problem, and isolate the algorithm you use to solve it efficiently.  Implement that algorithm.

Ideally, you would implement all 3 approaches and compare the efficiency of each approach (by looking at the results you printed in your table).