Let's build a GUI for the Tower of Hanoi:
Here's how we'll rewrite the main Tower-of-Hanoi solution:
(source file)
import java.util.*;
public class TowerOfHanoi4 {
// stacks[0], stacks[1] and stacks[2] are the three stacks.
static Stack<Integer>[] towers;
static HanoiGUI hanoiGUI;
public static void main (String[] argv)
{
// A 4-disk puzzle:
System.out.println ("4-Disk solution: ");
solveHanoi (3, 0, 1);
}
static void solveHanoi (int n, int i, int j)
{
// Create the three stacks and initialize ... this code is the same ...
// GUI. Note: n+1 = # disks. We will pass in the stacks.
hanoiGUI = new HanoiGUI (towers, n+1);
// Now solve recursively as before.
solveHanoiRecursive (n, i, j);
}
static void solveHanoiRecursive (int n, int i, int j)
{
// ...
}
static void move (int n, int i, int j)
{
// Pull out the top disk on stack i and move to j ... same as before ...
// This method will handle re-drawing the towers/disks.
hanoiGUI.updateGUI ();
// Pause execution for animation effect.
try {
Thread.sleep (1000);
}
catch (InterruptedException e) {
}
}
static int other (int i, int j)
{
// ...
}
}
Let us examine the class ChessBoard:
(source file)
The class ChessBoard has the code for
displaying the board in a GUI. Let's examine some of this code:
An alternative data structure:
public class ChessBoard {
// Constructor.
public ChessBoard (int size)
{
// Build the board ...
}
public int size ()
{
// Return the size ...
}
public void addQueen (int row, int col)
{
// Add a queen to the square [row,col] ...
}
public void removeQueen (int row, int col)
{
// Remove a queen from the square [row,col] ...
}
public boolean isForbidden (int row, int col)
{
// Check whether [row,col] is attacked ...
}
}
public class ChessBoard {
// Instance variables.
int size;
char[][] board; // board[i][j] == 'X' if there's a queen on it.
// Constructor.
public ChessBoard (int size)
{
}
// ...
}
public class ChessBoard {
// Instance variables.
int size;
char[][] board; // board[i][j] == 'X' if there's a queen on it.
// Constructor.
public ChessBoard (int size)
{
// Build the board. Initially empty: board[i][j] == 'O'.
this.size = size;
board = new char [size][size];
for (int i=0; i < size; i++) {
for (int j=0; j < size; j++) {
board[i][j] = 'O';
}
}
}
public int size ()
{
return size;
}
// ...
}
Thus, we use the character 'X' to represent the presence
of a queen and 'O' to represent an empty square.
public class ChessBoard {
// ...
public void addQueen (int row, int col)
{
board[row][col] = 'X';
}
public void removeQueen (int row, int col)
{
board[row][col] = 'O';
}
// ...
}
Here's the code:
public boolean isForbidden (int row, int col)
{
// First, try the row.
for (int c=0; c < size; c++) {
if (board[row][c] == 'X') {
return true;
}
}
// Now try the column
for (int r=0; r < size; r++) {
if (board[r][col] == 'X') {
return true;
}
}
// Now the diagonals.
for (int r=0; r < size; r++) {
for (int c=0; c < size; c++) {
if ( (r != row) && (c != col) && (board[r][c] == 'X') ) {
// See if (r,c) can be attacked by (row,col).
if (Math.abs(r-row) == Math.abs(c-col)) {
return true;
}
}
}
}
// If we reach here, there's no queen attacking [row,col]
return false;
}
For the diagonal:
=>
The row difference and column difference are the same for two
squares on a diagonal.
public void display ()
{
// Make the frame and set some of its parameters:
JFrame f = new JFrame ();
f.setSize (300,300);
f.setTitle ("N Queens problem");
// Create our extension of the JPanel:
ChessPanel drawPanel = new ChessPanel ();
// We'll need to pass on the data:
drawPanel.size = size;
drawPanel.board = board;
// Add this to the frame. Notice the strange syntax.
f.getContentPane().add (drawPanel);
// Bring up the frame.
f.setVisible (true);
}
class ChessPanel extends JPanel {
int size;
char[][] board;
public void paintComponent (Graphics g)
{
// ... This is where all the drawing is done ...
}
}
public class ChessBoard2 {
int size;
int[] columns; // column[r] = which column in row r has a queen, if any
// column[r] = -1, if this row has no queen
// ...
}
public void addQueen (int row, int col)
{
columns[row] = col;
}
public void removeQueen (int row, int col)
{
columns[row] = -1;
}
public boolean isForbidden (int row, int col)
{
// First, try the row.
if (columns[row] >= 0) {
return true;
}
// Now try the columns.
for (int c=0; c < size; c++) {
if (columns[row] == col) {
return true;
}
}
// Now the diagonals.
for (int r=0; r < size; r++) {
if (columns[r] >= 0) {
if (Math.abs(columns[r]-col) == Math.abs(row-r)) {
return true;
}
}
}
return false;
}