import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;
public class BoardManager {
protected Board board;
protected List sudokuViews;
public BoardManager() {
sudokuViews = new LinkedList();
history = new Stack();
}
public void registerSudokuView(Gui f) {
sudokuViews.add(f);
updateSudokuViews();
}
protected void updateSudokuViews() {
for (int i = 0; i < sudokuViews.size(); i++) {
((Gui) sudokuViews.get(i)).update(getBoard());
}
}
public void loadFile(File f) throws IOException {
preLoadWrapper();
board = new Board();
BufferedReader fileReader = new BufferedReader(new FileReader(f));
int digit = (Field.POSSIBILITIES / 10) + 1;
int row = 0;
while (row < Field.POSSIBILITIES) {
String sudokuLine = fileReader.readLine();
int value;
char c;
int extendedInt;
char extendedC;
if (digit == 1) {
for (int i = 0; i < Field.POSSIBILITIES; i++) {
c = sudokuLine.charAt(i);
if (c != '.') {
value = Integer.parseInt(Character.toString(c));
setFieldPrivate(Structure.ROW, row, i, new Field(value,
true));
}
}
} else if (digit == 2) {
for (int i = 0; i < Field.POSSIBILITIES * digit; i = i + digit) {
c = sudokuLine.charAt(i);
extendedC = sudokuLine.charAt(i + 1);
if (c != '.') {
value = Integer.parseInt(Character.toString(c)) * 10;
extendedInt = Integer.parseInt(Character
.toString(extendedC));
value += extendedInt;
setFieldPrivate(Structure.ROW, row, (i / digit),
new Field(value, true));
}
}
}
row++;
}
updateSudokuViews();
}
protected void setFieldPrivate(Structure structure, int structNr,
int element, Field f) {
board.setField(structure, structNr, element, f);
}
public void preSetFieldWrapper(Structure structure, int structNr,
int element, Field f) {
try {
history.push(board.clone());
} catch (CloneNotSupportedException e) {
}
}
public void preLoadWrapper() {
history.clear();
}
public void setField(Structure structure, int structNr, int element, Field f) {
preSetFieldWrapper(structure, structNr, element, f);
setFieldPrivate(structure, structNr, element, f);
updateSudokuViews();
}
public Field getField(Structure structure, int structNr, int element) {
return getBoard().getField(structure, structNr, element);
}
public Board getBoard() {
return this.board;
}
public void setBoard(Board board) {
this.board = board;
}
protected Stack history;
public void loadState(File f) throws IOException, ClassNotFoundException {
ObjectInput i = new ObjectInputStream(new FileInputStream(f));
board = (Board) i.readObject();
history = (Stack) i.readObject();
updateSudokuViews();
}
public void saveState(File f) throws IOException {
ObjectOutput o = new ObjectOutputStream(new FileOutputStream(f));
o.writeObject(getBoard());
o.writeObject(history);
o.close();
}
public void undo() {
if (!history.empty()) {
board = (Board) history.pop();
updateSudokuViews();
}
}
protected void setBusy(boolean busy) {
for (int i = 0; i < sudokuViews.size(); i++) {
((Gui) sudokuViews.get(i)).setBusy(busy);
}
}
protected boolean busy;
protected boolean trySetFieldPrivate(Structure structure, int structNr,
int element, Field f) {
return board.trySetField(structure, structNr, element, f);
}
public boolean trySetField(Structure structure, int structNr, int element,
Field f) {
preSetFieldWrapper(structure, structNr, element, f);
boolean set = trySetFieldPrivate(structure, structNr, element, f);
if (set) {
updateSudokuViews();
return true;
} else {
undo();
return false;
}
}
public boolean tryLoadFile(File f) throws IOException {
preLoadWrapper();
board = new Board();
BufferedReader fileReader = new BufferedReader(new FileReader(f));
int digit = (Field.POSSIBILITIES / 10) + 1;
int row = 0;
while (row < Field.POSSIBILITIES) {
String sudokuLine = fileReader.readLine();
int value;
char c;
// for (int i = 0; i < Field.POSSIBILITIES; i++) {
// c = sudokuLine.charAt(i);
// if (c != '.') {
// value = Integer.parseInt(Character.toString(c));
// if (!trySetFieldPrivate(Structure.ROW, row, i, new
// Field(value,true))) {
// board = null;
// updateSudokuViews();
// return false;
// }
// }
// }
int extendedInt;
char extendedC;
if (digit == 1) {
for (int i = 0; i < Field.POSSIBILITIES; i++) {
c = sudokuLine.charAt(i);
if (c != '.') {
value = Integer.parseInt(Character.toString(c));
if (!trySetFieldPrivate(Structure.ROW, row, i,
new Field(value, true))) {
board = null;
updateSudokuViews();
return false;
}
}
}
} else if (digit == 2) {
for (int i = 0; i < Field.POSSIBILITIES * digit; i = i + digit) {
c = sudokuLine.charAt(i);
extendedC = sudokuLine.charAt(i + 1);
if (c != '.' && extendedC != '.') {
value = Integer.parseInt(Character.toString(c)) * 10;
extendedInt = Integer.parseInt(Character
.toString(extendedC));
value += extendedInt;
if (!trySetFieldPrivate(Structure.ROW, row,
(i / digit), new Field(value, true))) {
board = null;
updateSudokuViews();
return false;
}
}
}
}
row++;
}
updateSudokuViews();
return true;
}
public boolean solutionHint() {
// new ForcedField().trySolve(board);
// if (true) {
// updateSudokuViews();
// return true;
// }
if (board.isSolved())
return true;
try {
setBusy(true);
List solutions = solve((Board) board.clone());
if (solutions.isEmpty()) {
setBusy(false);
return false;
}
for (int i = 0; i < Field.POSSIBILITIES; i++)
for (int j = 0; j < Field.POSSIBILITIES; j++)
if (!board.getField(Structure.ROW, i, j).isSet()
&& ((Board) solutions.get(0)).getField(
Structure.ROW, i, j).isSet()) {
trySetField(Structure.ROW, i, j, ((Board) solutions
.get(0)).getField(Structure.ROW, i, j));
updateSudokuViews();
return true;
}
setBusy(false);
} catch (CloneNotSupportedException e) {
}
return false;
}
protected List solve(Board board) {
List solutions = new LinkedList();
List solvers = new LinkedList();
solvers.add(new ForcedField());
solvers.add(new ForcedNumber());
Guesser guesser = new Guesser();
for (int i = 0; i < solvers.size(); i++)
if (!((Solver) solvers.get(i)).trySolve(board))
return solutions;
if (!board.isSolved()) {
List guessed = guesser.guess(board);
for (int i = 0; i < guessed.size(); i++)
solutions.addAll(solve(((Board) guessed.get(i))));
} else {
solutions.add(board);
}
return solutions;
}
public void loadSudoku(Board board) {
preLoadWrapper();
this.board = board;
updateSudokuViews();
}
public void setPossibilities(int possibilities) {
Field.POSSIBILITIES = possibilities;
this.board = null;
updateSudokuViews();
}
}