## Saturday, 21 January 2017

### Chapter 22 Exercise 25, Introduction to Java Programming, Tenth Edition Y. Daniel LiangY.

22.25 (Game: Sudoku) Revise Programming Exercise 22.21 to display all solutions for the Sudoku game, as shown in Figure  22.17a. When you click the Solve button, the program stores all solutions in an ArrayList . Each element in the list is a two-dimensional 9-by-9 grid. If the program has multiple solutions, the Next button appears as shown in Figure 22.17b. You can click the Next button to display the next solution and also a label to show the solution count. When the Clear button is clicked, the cells are cleared and the Next button is hidden as shown in Figure 22.17c.

import javax.swing.*;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

public class Exercise25 extends JApplet {

private static final long serialVersionUID = 1L;
private JTextField[] jTextFields = new JTextField[81];
private JButton jButton3 = new JButton("Next");
private ArrayList<String> result;
private int currentsolution = 0;
private JPanel jPanel1 = new JPanel();

public Exercise25() {

JButton jButton1 = new JButton("Solve");
JButton jButton2 = new JButton("Clear");
jButton3.setVisible(false);

JPanel jPanel2 = new JPanel(new GridLayout(3, 3, 4, 4));
jPanel2.setBackground(Color.BLACK);
for (int i = 0; i < 9; i++) {
JPanel tmp = new JPanel(new GridLayout(3, 3, 1, 1));
tmp.setBackground(Color.BLACK);
for (int j = 0; j < 9; j++) {
jTextFields[i * 9 + j] = new JTextField(3);
jTextFields[i * 9 + j].setHorizontalAlignment(JTextField.CENTER);
jTextFields[i * 9 + j].setFont(new Font("Monospaced", Font.BOLD, 20));
}
}

@Override
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < jTextFields.length; i++) {
jTextFields[i].setText("");
jTextFields[i].setBackground(Color.WHITE);
}
currentsolution = 0;
Exercise25.this.jButton3.setVisible(false);
}
});

@Override
public void actionPerformed(ActionEvent e) {
currentsolution++;
for (int k = 0; k < 3; k++) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
for (int l = 0; l <= 6; l+=3) {
if (jTextFields[i * 9 + j + l * 6 + 3 * (l + k)].getForeground() != Color.LIGHT_GRAY) {
jTextFields[i * 9 + j + l * 6 + 3 * (l + k)].setText(result.get(currentsolution).charAt((l + k) * 9 + i * 3 + j) + "");
}
}
}
}
}
if(currentsolution + 1 == result.size()) {
Exercise25.this.jButton3.setVisible(false);
}
}
});

@Override
public void actionPerformed(ActionEvent e) {
int[][] grid = new int[9][9];
for (int k = 0; k < 3; k++) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
for (int l = 0; l <= 6; l+=3) {
String value = jTextFields[i * 9 + j + l * 6 + 3 * (l + k)].getText();
if (value.equals("")) {
grid[l + k][i * 3 + j] = 0;
} else {
grid[l + k][i * 3 + j] = Integer.parseInt(value);
}
}
}
}
}
if (!isValid(grid)) {
JOptionPane.showMessageDialog(null, "Invalid input", "Error", JOptionPane.ERROR_MESSAGE);
} else {
result = search(grid);
if (result.size() != 0) {
currentsolution = 0;
JOptionPane.showMessageDialog(null, "The puzzle has " + result.size() + " solution" + (result.size() == 1? "": "s"), "Message", JOptionPane.INFORMATION_MESSAGE);
for (int k = 0; k < 3; k++) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
for (int l = 0; l <= 6; l+=3) {
String value = jTextFields[i * 9 + j + l * 6 + 3 * (l + k)].getText();
if (value.equals("")) {
jTextFields[i * 9 + j + l * 6 + 3 * (l + k)].setText(result.get(currentsolution).charAt((l + k) * 9 + i * 3 + j) + "");
} else {
jTextFields[i * 9 + j + l * 6 + 3 * (l + k)].setBackground(Color.LIGHT_GRAY);
}

}
}
}
}
if(result.size() > 1) {
Exercise25.this.jButton3.setVisible(true);
}
} else {
JOptionPane.showMessageDialog(null, "No solution", "Warning", JOptionPane.WARNING_MESSAGE);
}
}
}
});
}

static class LinearSearchPanel extends JPanel {
private static final long serialVersionUID = 1L;

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawString("asd", 10, 10);
}

}

public static void main(String[] args) {
JFrame frame = new JFrame("Exercise25");
Exercise25 applet = new Exercise25();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setMinimumSize(new Dimension(frame.getWidth(), frame.getHeight()));
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}

/** Obtain a list of free cells from the puzzle */
public static int[][] getFreeCellList(int[][] grid) {
// Determine the number of free cells
int numberOfFreeCells = 0;
for (int i = 0; i < 9; i++)
for (int j = 0; j < 9; j++)
if (grid[i][j] == 0)
numberOfFreeCells++;
// Store free cell positions into freeCellList
int[][] freeCellList = new int[numberOfFreeCells][2];
int count = 0;
for (int i = 0; i < 9; i++)
for (int j = 0; j < 9; j++)
if (grid[i][j] == 0) {
freeCellList[count][0] = i;
freeCellList[count++][1] = j;
}
return freeCellList;
}

/** Search for a solution */
public static ArrayList<String> search(int[][] grid) {
ArrayList<String> result = new ArrayList<>();
int[][] freeCellList = getFreeCellList(grid); // Free cells
if (freeCellList.length == 0) {
return result;
}
int k = 0; // Start from the first free cell
while (true) {
int i = freeCellList[k][0];
int j = freeCellList[k][1];
if (grid[i][j] == 0) {
grid[i][j] = 1;
}

boolean valid = false;
if (isValid(i, j, grid)) {
valid = true;
if (k + 1 == freeCellList.length) { // No more free cells
valid = false;
} else { // Move to the next free cell
k++;
}
}
if (!valid) {
if (grid[i][j] < 9) {
// Fill the free cell with the next possible value
grid[i][j] = grid[i][j] + 1;
} else { // free cell grid[i][j] is 9, backtrack
while (grid[i][j] == 9) {
if (k == 0) {
return result;
}
grid[i][j] = 0; // Reset to free cell
k--; // Backtrack to the preceding free cell
i = freeCellList[k][0];
j = freeCellList[k][1];
}
// Fill the free cell with the next possible value,
// search continues from this free cell at k
grid[i][j] = grid[i][j] + 1;
}
}
}
}

/** Check whether grid[i][j] is valid in the grid */
public static boolean isValid(int i, int j, int[][] grid) {
// Check whether grid[i][j] is valid at the i's row
for (int column = 0; column < 9; column++)
if (column != j && grid[i][column] == grid[i][j])
return false;
// Check whether grid[i][j] is valid at the j's column
for (int row = 0; row < 9; row++)
if (row != i && grid[row][j] == grid[i][j])
return false;
// Check whether grid[i][j] is valid in the 3 by 3 box
for (int row = (i / 3) * 3; row < (i / 3) * 3 + 3; row++)
for (int col = (j / 3) * 3; col < (j / 3) * 3 + 3; col++)
if (row != i && col != j && grid[row][col] == grid[i][j])
return false;

return true; // The current value at grid[i][j] is valid
}

/** Print the values in the grid */
public static String gridToString(int[][] grid) {
StringBuilder result = new StringBuilder();
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
result.append(grid[i][j]);
}
}
return result.toString();
}

/** Check whether the fixed cells are valid in the grid */
public static boolean isValid(int[][] grid) {
for (int i = 0; i < 9; i++)
for (int j = 0; j < 9; j++)
if (grid[i][j] < 0 || grid[i][j] > 9
|| (grid[i][j] != 0 && !isValid(i, j, grid)))
return false;
return true; // The fixed cells are valid
}
}