Game
public class Cell {
private int value;
private boolean isFixed;
public Cell() {
this(0, false);
}
public Cell(int value) {
this(value, value != 0);
}
public Cell(int value, boolean isFixed) {
validateValue(value);
this.value = value;
this.isFixed = isFixed;
}
public int getValue() {
return value;
}
public int get() {
return getValue();
}
public boolean isFixed() {
return isFixed;
}
public boolean getIsFixed() {
return isFixed();
}
public void setFixed(boolean fixed) {
isFixed = fixed;
}
public boolean setValue(int value) {
validateValue(value);
if (isFixed) {
return false;
}
this.value = value;
return true;
}
public boolean set(int value) {
return setValue(value);
}
public boolean forceSetValue(int value) {
validateValue(value);
this.value = value;
return true;
}
public boolean clear() {
return setValue(0);
}
private void validateValue(int value) {
if (value < 0 || value > 9) {
throw new IllegalArgumentException(
"A Sudoku cell value must be between 0 and 9."
);
}
}
@Override
public String toString() {
return Integer.toString(value);
}
}
=====================================================================
public class Row {
private final Cell[] cells;
public Row() {
this(createEmptyCells());
}
public Row(Cell[] cells) {
validateCells(cells);
this.cells = cells;
}
public Cell getCell(int column) {
validateIndex(column);
return cells[column];
}
public int get(int column) {
return getCell(column).getValue();
}
public boolean set(int column, int value) {
validateIndex(column);
return cells[column].setValue(value);
}
public boolean clear(int column) {
validateIndex(column);
return cells[column].clear();
}
public boolean contains(int value) {
if (value == 0) {
return false;
}
for (Cell cell : cells) {
if (cell.getValue() == value) {
return true;
}
}
return false;
}
public boolean isValid() {
boolean[] seen = new boolean[10];
for (Cell cell : cells) {
int value = cell.getValue();
if (value == 0) {
continue;
}
if (seen[value]) {
return false;
}
seen[value] = true;
}
return true;
}
public Cell[] getCells() {
return cells.clone();
}
private static Cell[] createEmptyCells() {
Cell[] cells = new Cell[9];
for (int i = 0; i < cells.length; i++) {
cells[i] = new Cell();
}
return cells;
}
private void validateIndex(int index) {
if (index < 0 || index >= 9) {
throw new IndexOutOfBoundsException(
"Column index must be between 0 and 8."
);
}
}
private void validateCells(Cell[] cells) {
if (cells == null || cells.length != 9) {
throw new IllegalArgumentException(
"A Sudoku row must contain exactly 9 cells."
);
}
for (Cell cell : cells) {
if (cell == null) {
throw new IllegalArgumentException(
"A Sudoku row cannot contain null cells."
);
}
}
}
}
================================================================
public class Column {
private final Cell[] cells;
public Column(Cell[] cells) {
validateCells(cells);
this.cells = cells;
}
public Cell getCell(int row) {
validateIndex(row);
return cells[row];
}
public int get(int row) {
return getCell(row).getValue();
}
public boolean set(int row, int value) {
validateIndex(row);
return cells[row].setValue(value);
}
public boolean clear(int row) {
validateIndex(row);
return cells[row].clear();
}
public boolean contains(int value) {
if (value == 0) {
return false;
}
for (Cell cell : cells) {
if (cell.getValue() == value) {
return true;
}
}
return false;
}
public boolean isValid() {
boolean[] seen = new boolean[10];
for (Cell cell : cells) {
int value = cell.getValue();
if (value == 0) {
continue;
}
if (seen[value]) {
return false;
}
seen[value] = true;
}
return true;
}
public Cell[] getCells() {
return cells.clone();
}
private void validateIndex(int index) {
if (index < 0 || index >= 9) {
throw new IndexOutOfBoundsException(
"Row index must be between 0 and 8."
);
}
}
private void validateCells(Cell[] cells) {
if (cells == null || cells.length != 9) {
throw new IllegalArgumentException(
"A Sudoku column must contain exactly 9 cells."
);
}
for (Cell cell : cells) {
if (cell == null) {
throw new IllegalArgumentException(
"A Sudoku column cannot contain null cells."
);
}
}
}
}
=============================================================
public class Block {
private final Cell[] cells;
public Block(Cell[] cells) {
validateCells(cells);
this.cells = cells;
}
public Cell getCell(int index) {
validateIndex(index);
return cells[index];
}
public int get(int index) {
return getCell(index).getValue();
}
public boolean set(int index, int value) {
validateIndex(index);
return cells[index].setValue(value);
}
public boolean clear(int index) {
validateIndex(index);
return cells[index].clear();
}
public boolean contains(int value) {
if (value == 0) {
return false;
}
for (Cell cell : cells) {
if (cell.getValue() == value) {
return true;
}
}
return false;
}
public boolean isValid() {
boolean[] seen = new boolean[10];
for (Cell cell : cells) {
int value = cell.getValue();
if (value == 0) {
continue;
}
if (seen[value]) {
return false;
}
seen[value] = true;
}
return true;
}
public Cell[] getCells() {
return cells.clone();
}
private void validateIndex(int index) {
if (index < 0 || index >= 9) {
throw new IndexOutOfBoundsException(
"Block-cell index must be between 0 and 8."
);
}
}
private void validateCells(Cell[] cells) {
if (cells == null || cells.length != 9) {
throw new IllegalArgumentException(
"A Sudoku block must contain exactly 9 cells."
);
}
for (Cell cell : cells) {
if (cell == null) {
throw new IllegalArgumentException(
"A Sudoku block cannot contain null cells."
);
}
}
}
}
===========================================================
public class Board {
private final Cell[][] cells;
private final Row[] rows;
private final Column[] columns;
private final Block[] blocks;
public Board() {
this(new int[9][9]);
}
public Board(int[][] puzzle) {
validatePuzzle(puzzle);
cells = new Cell[9][9];
rows = new Row[9];
columns = new Column[9];
blocks = new Block[9];
createCells(puzzle);
createRows();
createColumns();
createBlocks();
}
public Cell getCell(int row, int column) {
validatePosition(row, column);
return cells[row][column];
}
public int get(int row, int column) {
return getCell(row, column).getValue();
}
public boolean set(int row, int column, int value) {
validatePosition(row, column);
return cells[row][column].setValue(value);
}
public boolean clear(int row, int column) {
validatePosition(row, column);
return cells[row][column].clear();
}
public boolean safeSet(int row, int column, int value) {
validatePosition(row, column);
validateValue(value);
Cell target = cells[row][column];
if (target.isFixed()) {
return false;
}
if (value == 0) {
return target.clear();
}
target.forceSetValue(0);
int blockIndex = getBlockIndex(row, column);
boolean legal =
!rows[row].contains(value)
&& !columns[column].contains(value)
&& !blocks[blockIndex].contains(value);
if (legal) {
target.forceSetValue(value);
return true;
}
target.forceSetValue(0);
return false;
}
public Row getRow(int index) {
validateIndex(index, "Row");
return rows[index];
}
public Column getColumn(int index) {
validateIndex(index, "Column");
return columns[index];
}
public Block getBlock(int index) {
validateIndex(index, "Block");
return blocks[index];
}
public boolean isValid() {
for (int i = 0; i < 9; i++) {
if (!rows[i].isValid()
|| !columns[i].isValid()
|| !blocks[i].isValid()) {
return false;
}
}
return true;
}
public boolean isComplete() {
if (!isValid()) {
return false;
}
for (int row = 0; row < 9; row++) {
for (int column = 0; column < 9; column++) {
if (cells[row][column].getValue() == 0) {
return false;
}
}
}
return true;
}
public int getBlockIndex(int row, int column) {
validatePosition(row, column);
return (row / 3) * 3 + (column / 3);
}
private void createCells(int[][] puzzle) {
for (int row = 0; row < 9; row++) {
for (int column = 0; column < 9; column++) {
int value = puzzle[row][column];
cells[row][column] =
new Cell(value, value != 0);
}
}
}
private void createRows() {
for (int row = 0; row < 9; row++) {
rows[row] = new Row(cells[row]);
}
}
private void createColumns() {
for (int column = 0; column < 9; column++) {
Cell[] columnCells = new Cell[9];
for (int row = 0; row < 9; row++) {
columnCells[row] = cells[row][column];
}
columns[column] = new Column(columnCells);
}
}
private void createBlocks() {
for (int block = 0; block < 9; block++) {
Cell[] blockCells = new Cell[9];
int startingRow = (block / 3) * 3;
int startingColumn = (block % 3) * 3;
int index = 0;
for (int row = startingRow;
row < startingRow + 3;
row++) {
for (int column = startingColumn;
column < startingColumn + 3;
column++) {
blockCells[index] = cells[row][column];
index++;
}
}
blocks[block] = new Block(blockCells);
}
}
private void validatePuzzle(int[][] puzzle) {
if (puzzle == null || puzzle.length != 9) {
throw new IllegalArgumentException(
"The puzzle must contain exactly 9 rows."
);
}
for (int row = 0; row < 9; row++) {
if (puzzle[row] == null
|| puzzle[row].length != 9) {
throw new IllegalArgumentException(
"Every puzzle row must contain exactly 9 values."
);
}
for (int column = 0; column < 9; column++) {
validateValue(puzzle[row][column]);
}
}
}
private void validatePosition(int row, int column) {
validateIndex(row, "Row");
validateIndex(column, "Column");
}
private void validateIndex(int index, String name) {
if (index < 0 || index >= 9) {
throw new IndexOutOfBoundsException(
name + " index must be between 0 and 8."
);
}
}
private void validateValue(int value) {
if (value < 0 || value > 9) {
throw new IllegalArgumentException(
"A Sudoku value must be between 0 and 9."
);
}
}
@Override
public String toString() {
StringBuilder result = new StringBuilder();
for (int row = 0; row < 9; row++) {
if (row % 3 == 0) {
result.append("-----------------------\n");
}
for (int column = 0; column < 9; column++) {
result.append(
cells[row][column].getValue()
).append(' ');
if (column % 3 == 2) {
result.append("| ");
}
}
result.append('\n');
}
result.append("-----------------------");
return result.toString();
}
}