import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class Sudoku {
final static List<Integer> digits = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8, 9);
final private int[][] grid;
public HashMap<String, ArrayList<Integer>> possibilities;
private Sudoku(int[][] grid) {
this.grid = grid;
possibilities = Maps.newHashMap();
for (int row = 0; row < grid.length; row++) {
for (int column = 0; column < grid[0].length; column++) {
if (grid[row][column] == 0) {
possibilities.put(row + "," + column, new ArrayList<Integer>(digits));
}
}
}
}
public static Sudoku sudoku(int[][] grid) {
return new Sudoku(grid);
}
public int[][] solve() {
while (!solvedGrid()) {
for (int row = 0; row < grid.length; row++) {
for (int column = 0; column < grid[row].length; column++) {
if (grid[row][column] == 0) {
computePossibilities(row, column);
}
}
}
}
return grid;
}
private void computePossibilities(int row, int column) {
Set<Integer> horizontalValues = horizontalPossibilities(row);
updateGrid(row, column, horizontalValues);
Set<Integer> verticalValues = verticalPossibilities(column);
updateGrid(row, column, verticalValues);
Set<Integer> squareValues = squarePossibilities(row, column);
updateGrid(row, column, squareValues);
}
private void updateGrid(int row, int column, Set<Integer> horizontalValues) {
possibilities.get(row + "," + column).removeAll(horizontalValues);
if(possibilities.get(row + "," + column).size()==1){
grid[row][column] = possibilities.get(row + "," + column).get(0);
}
}
private Set<Integer> squarePossibilities(int row, int column) {
Set<Integer> squarePossibilities = new HashSet<Integer>();
int rowStartIndex = row - (row % 3);
int columnStartIndex = column - (column % 3);
for (int rowIndex = rowStartIndex; rowIndex <rowStartIndex+3 ; rowIndex++) {
for (int columnIndex = columnStartIndex; columnIndex <columnStartIndex+3 ; columnIndex++) {
squarePossibilities.add(grid[rowIndex][columnIndex]);
}
}
return squarePossibilities;
}
private Set<Integer> horizontalPossibilities(int row) {
Set<Integer> horizontalValues = new HashSet<Integer>();
for (int i = 0; i < grid.length; i++) {
horizontalValues.add(grid[row][i]);
}
return horizontalValues;
}
private Set<Integer> verticalPossibilities(int column) {
Set<Integer> verticalValues = new HashSet<Integer>();
for (int i = 0; i < grid.length; i++) {
verticalValues.add(grid[i][column]);
}
return verticalValues;
}
private boolean solvedGrid() {
for (int[] rows : grid) {
for (int cell : rows) {
if (cell == 0) {
return false;
}
}
}
return true;
}
}