Comp211 HW11  Supporting Code Details

Here is a link to the Java 6 API documentation. Look here for information on any unfamiliar Java class, e.g. HashSet<T> or Vector<T>:

http://download.oracle.com/javase/6/docs/api/

Core Data Structures


 The main data structures are represented by only a few interfaces:

Utility Data Structures

Delegation-model programming and imperative (conditional and loop-based) programming have a fundamental incompatibility:   Delegation works by having code on the inside of an object (i.e. a method of that object) perform the object-specific processes.  On the other hand, imperative programming utilizes program structures (conditionals and loops) which are outside the object to perform object-specific processes.    This can cause major architectural headaches when combining both styles in a program, which is what we are doing here.  For instance, see the programming hints section on the previous wiki page on how to control loops and mutate data while in the middle of a delegation process.

The following utility data structures are designed to handle the situation where an operation has more than 2 or more possible outcomes.  While not entirely optimal, these classes show how clever sub-classing can enable one to re-use classes in multiple situations.

 Typically, a method returns a value of type IUtilHostAB/C/D depending on how many possibilities there are.  For instance, a single reduction pass on the Sudoku board would result in a value of IUtilHostABCD, corresponding to the 4 possible outcomes for the board: being still reducible, irreducible, solved or unsolvable.


 The caller of such a method need only to simply delegate to the returned value by having the returned value accept the proper visitor.   Suppose the method my3OutcomeMethod has three possible outcomes, so it returns an IUtilHostABC object.    All we need to do is to delegate to the returned value of the method:

my3OutcomeMethod().accept(new IUtilVisitorABC() {...})

Model-View-Controller Architecture

 A discussion of the details and implications of the Model-View-Controller Design Pattern  are beyond the scope of this class, so here is but a brief overview:


The point of the MVC is to separate how a program looks to the user from what it does.   In the above UML diagram, you can see that we have two separate packages:  edu.rice.comp211.sudoku.gui and edu.rice.comp211.sukodu.model that hold the "view" and "model" components respectively.

The view, GameFrame communicates with the rest of the system via its IModelAdapter which is also in the gui package.   The ICellView is used to communicate to the view, and so, it is also in the gui package.  The gui package does not define what the IModelAdapter does!    But the GUIFrame does not know this--so far as it can tell, it's entire world is defined by the gui package because there are no references to anything outside of the package.

Likewise, the model, GameModel communicates with the outside world via its IViewAdapter.   The model does use the code in the data and util packages, but only to define data structures and provide utility capabilities.   All communications to the view take place through the IViewAdapter which is in the model pacakge.  Like the view, the model code has no idea what the implementation of IViewAdapter is.

The view and model packages are thus completely isolated and independent from each other.   The job of the Controller class in the edu.rice.comp211.sudoku.controller package is to assemble the complete, operational application by joining the view and model together.   It does so by creating implementations of both IModelAdapter and IViewAdapter that pass their method calls onto the GameFrame and GameModel respectively.   This may involve simply passing the call along to the appropriate method on the receiver, for instance, IModelAdapter.solve() is implemented to simply call GameModel.solve().   But other methods may require more extensive translation, for instance, IviewAdapter.setCellViews() is implemented to take a Vector<ICellSet> object, convert it into a 2-dimensional array of ICelllViews and then make the call to GameFrame.addCells().   

Thus, the Controller is the class that contains the main() method that starts the application.   The constructor of Controller instantiates the model, GameModel, the view, GameFrame, and the adapters that communicate between them, IViewAdapter and IModelAdapter.    The method Controller.start() is then called to actually start the application.

The Controller is the only class that knows which view and which model are used for any given application. 

Key Methods of GameFrame

 Key Methods of IModelAdapter

Most method are self-evident.  See the Javadocs.

Key Methods of GameModel

There are a number of utility methods to perform useful self-evident tasks--see the Javadocs.

 Key Methods of IViewAdapter

Testing the GameModel

For testing purposes, a GameModel can be instantiated using an implementation of IViewAdapter whose method a no-ops.    The methods of the GameModel can then be called. 

Puzzle Generation Utilities

 The supplied code also contains a self-contained package, edu.rice.comp211.sudoku.generate, that is used to read Sudoku puzzles from text files containing a total of over 50,000 solvable puzzles.  These puzzles come from www.printable-sudoku-puzzles.com but are a different format than the Comp211 Sudoku solver uses.   These utilities, which are all contained in the GeneratePuzzle class, can read those data files, pick either a specific puzzle from them, or a random puzzle, display it and save the individual puzzle in a format that the Comp211 Sudoku solver can read.

GeneratePuzzleApp is a a simple GUI interface to GeneratePuzzle that allows the user to easily perform conversions.   Note that the higher numbered data files (located in data\puzzle-src) have more difficult puzzles.   Each data file contains about 10,000 puzzles numbered from 1-10000 (approx.).   An index of zero means to choose a random puzzle from the data file.   

{[GeneratePuzzleApp}} has its own main() method and thus can be run as a separate, stand-alone application apart from the Sudoko solver.

See the Javadocs for more detailed information on the individual methods.