13
Sudoku Application

“The attempt to combine wisdom and power has only rarely been successful and then only for a short while.”

—Albert Einstein

Until now, most of the concepts discussed throughout the course of this book were either described abstractly or, for the sake of simplicity, demonstrated with small blocks of code or trivial programs. For this final chapter, we’ll apply what we’ve learned to create something with a bit more substance. Our sample application utilizes and combines many more of the techniques and mechanisms elaborated upon, more closely resembling how JavaFX might be employed in the real world.

The application we’ve chosen to implement is the game of Sudoku. As Sudoku has gained considerable worldwide popularity recently, it is likely to have been encountered by many reading this book. To the uninitiated, you’ll find that Sudoku is easy to learn, and furthermore easy to become addicted to playing. From a JavaFX perspective, Sudoku represents a reasonable example of how the logic required for the rules of the game and the presentation of that game can be nicely delineated.

For those unfamiliar with the game, a standard Sudoku board has nine rows and nine columns of spaces. The board is also grouped into nine boxes or regions. To solve a Sudoku puzzle, the numbers 1 through 9 must appear in each row, column, and box—but only once—and not in any particular order. New Sudoku puzzles start out with a certain number of spaces already filled in. In general, the fewer the number of pre-defined spaces, the more difficult the puzzle. The job of the person playing the game is to use logic to fill in the rest of the spaces.

How to Access the JavaFX Sudoku Application

The Sudoku application is available online and can be accessed by pointing your browser to the following URL:

http://jfxbook.com/Sudoku/

Upon reaching this page, you have the option of running Java FX Sudoku in one of two ways:

•   As a standalone application. This option utilizes Java Web Start technology to start the JavaFX Sudoku application as a separate process, independent from the browser.

•   As an applet. This option allows you to run JavaFX Sudoku inside the browser as a traditional applet. Depending upon your system configuration (operating system, Java Runtime Environment, browser, etc.), you may be able to take advantage of the draggable applet feature, in effect giving you the ability to undock the applet from the browser.

The Interface

Figure 13.1 depicts and describes the onscreen interface of the Sudoku program. Logically, the interface can be divided into three areas:

•   The top section of the interface serves as a window frame. If you drag your mouse within this area, you’ll be able to reposition the Sudoku application on the screen. If you are running Sudoku as an applet within a browser, dragging your mouse in this area will enable you to undock the applet from the browser if your overall environment supports the draggable applet feature.

•   The middle section, which encompasses a majority of the interface, contains the Sudoku board. By hovering your mouse over a space on the board, you can modify its contents by either clicking the mouse to enter in a new number or by typing a number from 1 to 9. If you want to clear a space, you can type either 0 or <space>. When a new puzzle is generated, a certain number of spaces will be filled in for you to aid in solving the puzzle. These spaces cannot be modified.

•   The bottom section of the interface contains menu buttons needed to interact with the application. They include buttons to create a new game, instruct the user as to how to play, set the level of difficulty of the puzzle, reset the game to its original state, solve the puzzle, and quit the game.

Figure 13.1 The Sudoku Application Interface

Image

Source for the Sudoku Application

The source code for JavaFX Sudoku can also be found at http://jfxbook.com/Sudoku/. Developed with the NetBeans Integrated Development Environment, the source comes bundled with project metadata to facilitate seamless integration into NetBeans.

Packages

Table 13.1 lists and briefly describes the packages that make up the JavaFX Sudoku application. It incorporates both JavaFX and Java source, plus images that are used as part of the overall presentation.

Table 13.1 Packages in the Sudoku Application

Image

JavaFX Source Files

The JavaFX source files that comprise the sudoku package (referenced in Table 13.1) are, in general, divided into two types of files. Those directly involved with the application interface have public classes that extend the CustomNode class and are suffixed with Node (e.g., BoardNode.fx, IconButtonNode.fx). Source files without the Node suffix do not extend the CustomNode class and are involved more with the logic behind running the Sudoku application. Table 13.2 lists and describes the sudoku package files.

Table 13.2 JavaFX Source Files in the sudoku Package

Image

Image

The Overall Design

Briefly mentioned earlier, the application has been architected such that the overall game logic and the user interface have been cleanly separated in a relatively straightforward fashion. As a rule of thumb, source files suffixed with Node are presentation or interface files, whereas those without the Node moniker are dedicated to providing the logic necessary to play the Sudoku game.

The Logic

The game logic for the Sudoku application is primarily supplied by two JavaFX classes: Board and Space. The Board class represents a Sudoku board. It has code to interpret the rules of the game and is ultimately responsible for starting a new game, determining if an individual move is valid, maintaining the state of the game, and providing a solution to the puzzle.

The Board class includes a sequence of 81 Spaces representing the 9×9 grid of spaces that make up a standard Sudoku puzzle. At initialization, the Board class identifies which row, column, and region (or box) each of the 81 Spaces belong to and groups them accordingly. Each Space has instance variables that identify its row/column/region, and most importantly, a number variable holding the value that is currently assigned to this space. The value of number is used to interpret the current state of the Space. Externally, Sudoku spaces can only have a numeric value ranging from 1–9, or be blank. Internally, the number value for a Space instance has a larger range. Table 13.3 explains the possible values that can be assigned to a Space’s number instance variable, and how they affect what is ultimately displayed to the user.

Table 13.3 Range of Internal Values a number Instance Variable Can Be Assigned and How They Are Ultimately Displayed Externally

Image

The Interface

The Board and Space classes have interface counterparts, named BoardNode and SpaceNode respectively, which handle the task of presenting the Sudoku game to the user. The BoardNode class is responsible for the overall layout of the application; for each Space, there is a corresponding SpaceNode, which manages the input and display of that space on the puzzle. When the BoardNode instance is initialized, it includes an instance variable called board, which is a reference to the Board instance. Likewise, each SpaceNode instance contains an instance variable called space, which points to its Space counterpart. Figure 13.2 shows the relationship between Board/Space and BoardNode/SpaceNode.

Figure 13.2 Relationship Between Board/Spaces and BoardNode/SpaceNodes

Image

With these classes in place, you might be asking the question, how is the internal state of the Spaces picked up by the corresponding SpaceNodes and displayed on the interface? The short answer is through binding. Let’s run through how this takes place.

At startup, a series of URLs (filenames) are statically loaded into a String sequence called imageFiles. The initialization of imageFiles looks like this:

Image

As you may have surmised, the image files coincide with the layout of a Space’s number instance variable as described in Table 13.3. For example, imageFiles[0] contains the URL "{__DIR__}images/blank.png"—a blank space—whereas imageFiles[19] points to "{__DIR__}images/9-bold.png"—an image of the number 9 in bold, representing a non-editable space. The imageFiles sequence, however, only contains strings that refer to URLs. What we actually need here is a sequence of type Image to serve as an Image cache. This is achieved by using imageFiles with the following code:

Image

Next, each SpaceNode defines two instance variables, one called spaceImage, which holds the current image displayed for each instance, and number, which contains the value of the corresponding Space’s number instance variable. Using a combination of binding and triggers, we can achieve the effect of updating a SpaceNode’s current image whenever its corresponding Space has a change in its number variable. This is accomplished with the following code:

Image

The definition of the preceding number variable performs two things:

1.   It binds number to space.number. Whenever the value of space.number changes, number will automatically change accordingly.

2.   The number variable uses a trigger to force an update to the value of spaceImage whenever number changes too. In this case, spaceImage points to a sequence (a cache) of Images indexed by the value of number.

Finally, each SpaceNode defines an instance of ImageView, which is ultimately how the image is displayed. It looks something like this:

Image

Now, the image for a SpaceNode will dynamically change whenever space.number changes. Here’s the chain of events:

•   The user enters a number into an editable space.

•   The space.number instance variable is assigned a new value.

•   The corresponding SpaceNode has a number instance variable that is bound to space.number. Whenever space.number changes, so does this number variable.

•   There is a trigger associated with the number instance variable such that whenever it is modified, it causes the spaceImage variable to be recalculated. In this case, spaceImage uses number as an index into a sequence of cached Images.

•   Each SpaceNode instantiates ImageView. Its image instance variable is bound to spaceImage. Whenever spaceImage changes, the image will change too.

This all comes about because of the capabilities of binding and triggers.

Interfacing with Java Components

So far, we’ve covered the logic and presentation of our Sudoku application, and how these two worlds relate to one another. The components comprising this portion of our application were written in JavaFX and represent the main effort in creating JavaFX Sudoku. There is a third element, however, which needs to be implemented to complete the Sudoku game. It revolves around the ability to randomly create new Sudoku puzzles and to provide solutions for them.

In conjunction with the popularity of Sudoku, many have put forth algorithms for creating and solving Sudoku puzzles. With this in mind, we had the option of either reinventing the wheel or leveraging the work that’s been done already in puzzle generation. In all honesty, there’s no real advantage to writing a Sudoku puzzle generator in JavaFX. It could have just as easily and effectively been written in any of the myriad of available high-level programming languages. So why not find what’s out there, and see how easily it could be integrated into our application? Code reuse and, in particular, integration with Java, arguably the largest development community on the planet, are key design characteristics of JavaFX.

Sourceforge.net is a well-known centralized repository for open source software projects. At that location, we found a Sudoku application located under the following URL:

http://sourceforge.net/projects/playsudoku/

This project is a complete program written in Java, including a Swing-based user interface. Our interest was solely in its capability to create new Sudoku puzzles, so we took a subset of the source code, specifically the classes found under the net.sourceforge.playsudoku package, and integrated them into our application.

The integration effort was straightforward and involved two primary tasks:

1.   Figuring out what methods need to be called to generate a new Sudoku puzzle.

2.   Determining if the data structures used by the Java application can be directly used with JavaFX.

We’ll handle the second task first and use our solution there as part of the overall process needed to generate a new puzzle.

Delving into the net.sourceforge.playsudoku package, you’ll find that the contents of the puzzle are maintained in a multi-dimensional array called grid. The Java declaration for this array is found in the SudokuGrid.java file and looks like this:

private int[][] grid;

Unfortunately, JavaFX currently has no support for multi-dimensional arrays. So, the first order of business is to convert grid into something JavaFX understands. Listing 13.1 shows an additional Java method, called returnGridSequence(), that was added to the SudokuGrid.java source file. The purpose of this method is to convert the two-dimensional grid array into a one-dimensional array of type int. This then maps directly to a JavaFX Integer[] sequence.

Listing 13.1 Java Method to Convert a Two-Dimensional Array into a One-Dimensional JavaFX Sequence

Image

Using this method, we can now tackle the first task, constructing the necessary JavaFX code to generate a new JavaFX puzzle using the net.sourceforge.playsudoku package. Listing 13.2 shows the complete newPuzzle() function, which is contained within the Board.fx source file. Let’s first take a look at a few of the parts of this function to see what’s going on. The first lines of newPuzzle() call the necessary Java methods inside net.sourceforge.playsudoku to generate a new puzzle:

Image

Next comes the call to the returnGridSequence() function, which converts the grid into a JavaFX Integer sequence:

Image

The rest of the function contains code necessary to translate the contents of each cell. Inside grid, the way in which state is stored is fairly similar to the way it’s done with JavaFX Sudoku. Instead of using number values that are multiples of 10, the author(s) used bitmasks to store multiple values in each cell. Listing 13.2 shows the newPuzzle() function.

Listing 13.2 The newPuzzle() Function

Image

Image

Chapter Summary

We’ve spent some time dissecting our sample Sudoku application including describing the user interface, the organization of the source, the overall architecture, and the interaction with components written elsewhere in Java. Feel free to take a look at the source and utilize it in any fashion you wish.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset