import java.util.ArrayList; import jvstm.*; public class SudokuSolver { private Cell[][] cells = new Cell[9][9]; SudokuSolver() { initializeCells(); } void initializeCells() { // create all cells for (int r = 0; r < 9; r++) { for (int c = 0; c < 9; c++) { cells[r][c] = new Cell(r,c); } } // connect neighbors for (int r = 0; r < 9; r++) { for (int c = 0; c < 9; c++) { connectNeighborsFor(r, c); } } } void connectNeighborsFor(int row, int col) { int regionRow = row / 3; int regionCol = col / 3; for (int r = 0; r < 9; r++) { for (int c = 0; c < 9; c++) { if (! ((row == r) && (col == c))) { if ((row == r) || (col == c) || ((regionRow == (r / 3)) && (regionCol == (c / 3)))) { cells[row][col].addNeighbor(cells[r][c]); } } } } } void setGivens(String givens) { int pos = 0; for (Cell[] row : cells) { for (Cell cell : row) { char given = givens.charAt(pos); pos++; if (given != '?') { cell.setNum(Character.digit(given, 10)); } } } } void print() { for (Cell[] row : cells) { System.out.println(); for (Cell cell : row) { cell.print(); } System.out.println(); } } void solve() { Cell mostConstrained = findMostConstrainedCell(); if (mostConstrained.countPossibleValues() > 1) { tryValuesFor(mostConstrained); } } void tryValuesFor(Cell cell) { int[] values = cell.getPossibleValues(); int pos = 0; while (pos < values.length) { //System.out.println("Will try value " + values[pos] + " for cell at (" + cell.row + ", " + cell.col + ")"); Transaction.begin(); try { cell.setNum(values[pos]); solve(); Transaction.commit(); //System.out.println("Succeed"); return; } catch (Fail f) { //System.out.println("Failed"); Transaction.abort(); pos++; } } throw new Fail(); } Cell findMostConstrainedCell() { Cell best = cells[0][0]; int lessPossibilities = 10; for (Cell[] row : cells) { for (Cell c : row) { int possibilities = c.countPossibleValues(); if ((possibilities > 1) && (possibilities < lessPossibilities)) { best = c; lessPossibilities = possibilities; } } } return best; } public static void main(String[] args) { Transaction.begin(); SudokuSolver solver = new SudokuSolver(); solver.setGivens(args[0]); solver.solve(); solver.print(); Transaction.commit(); } static class Cell { private static final int ALL = (1 << 9) - 1; private int row, col; private VBox<Integer> nums = new VBox<Integer>(); private ArrayList<Cell> neighbors = new ArrayList<Cell>(); Cell(int row, int col) { this.row = row; this.col = col; nums.put(ALL); } void addNeighbor(Cell neighbor) { //System.out.println("Adding cell at (" + neighbor.row + ", " + neighbor.col + ") as neighbor of (" + this.row + ", " + this.col + ")"); neighbors.add(neighbor); } void remove(int num) { int oldValue = this.nums.get(); int newValue = (oldValue & (~ (1 << (num - 1)))); //System.out.println("Removing " + num + " from (" + this.row + ", " + this.col + "): " + oldValue + " -> " + newValue); if (oldValue == newValue) { return; } if (newValue == 0) { throw new Fail(); } setValue(newValue); } void setNum(int num) { setValue(1 << (num - 1)); } void setValue(int newValue) { this.nums.put(newValue); if (Integer.bitCount(newValue) == 1) { for (Cell c : neighbors) { c.remove(Integer.numberOfTrailingZeros(newValue) + 1); } } } int[] getPossibleValues() { int[] vals = new int[countPossibleValues()]; int value = this.nums.get(); int pos = 0; int num = 1; while (value != 0) { if ((value & 1) != 0) { vals[pos++] = num; } num++; value = (value >> 1); } return vals; } int countPossibleValues() { return Integer.bitCount(this.nums.get()); } int getCurrentSingleValue() { return Integer.numberOfTrailingZeros(this.nums.get()) + 1; } void print() { int value = this.nums.get(); if (Integer.bitCount(value) == 1) { System.out.print(" " + getCurrentSingleValue() + " "); } else { System.out.print(" ? "); } } } static class Fail extends RuntimeException {} }