Implemented the backtracking strategy for the Sudoku Solver.

JUnit tests are running. Still need to add more logic strategies.
This commit is contained in:
Christopher Beckmann 2015-11-18 03:54:33 +01:00
parent 6ad5832538
commit cc92454cc6
18 changed files with 307 additions and 104 deletions

View file

@ -8,6 +8,15 @@
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
<activity
android:name="tu_darmstadt.sudoku.ui.MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="tu_darmstadt.sudoku.ui.SettingsActivity"
android:label="@string/title_activity_settings"
@ -21,16 +30,6 @@
</activity>
<activity android:name="tu_darmstadt.sudoku.ui.AboutActivity" >
</activity>
<activity
android:name="tu_darmstadt.sudoku.ui.MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="tu_darmstadt.sudoku.ui.LoadGameActivity" >
</activity>
</application>

View file

@ -10,7 +10,7 @@ import tu_darmstadt.sudoku.game.CellConflict;
import tu_darmstadt.sudoku.game.CellConflictList;
import tu_darmstadt.sudoku.game.GameBoard;
import tu_darmstadt.sudoku.game.GameCell;
import tu_darmstadt.sudoku.game.GameInfoContainer;
import tu_darmstadt.sudoku.controller.helper.GameInfoContainer;
import tu_darmstadt.sudoku.game.GameType;
import tu_darmstadt.sudoku.game.ICellAction;
import tu_darmstadt.sudoku.game.solver.Solver;
@ -25,13 +25,14 @@ public class GameController {
private int sectionHeight;
private int sectionWidth;
private GameBoard gameBoard;
private ISolver solver;
private Solver solver;
private GameType gameType;
private int selectedRow;
private int selectedCol;
private SharedPreferences settings;
private int gameID = 0;
private CellConflictList errorList = new CellConflictList();
private int selectedValue;
//private LinkedList<IModelChangeListener> listeners = new LinkedList<>();
// private Solver solver;
@ -139,7 +140,7 @@ public class GameController {
settings = pref;
}
public GameBoard solve(GameBoard gameBoard) {
public LinkedList<GameBoard> solve() {
switch(gameType) {
case Default_9x9:
case Default_6x6:
@ -150,8 +151,8 @@ public class GameController {
throw new UnsupportedOperationException("No Solver for this GameType defined.");
}
if(solver.solve()) {
return solver.getGameBoard();
if(solver.solve(solver.getGameBoard())) {
return solver.getSolutions();
}
return null;
}
@ -228,6 +229,15 @@ public class GameController {
return gameBoard.actionOnCells(ca,existing);
}
public boolean checkIfBoardIsFilled() {
//if(gameBoard.getEmptyCellCount() == 0) {
// TODO: board is filled. check it for errors.
//return true;
//}
return false;
}
public void saveGame(Context context) {
if(settings == null) {
return;
@ -312,15 +322,34 @@ public class GameController {
return gameBoard.toString();
}
/*
* Controls for the View.
* Select methods for Cells and Values.
* If a value is selected while a cell is selected the value is put into the cell.
* If no cell is selected while a value is being selected, the value gets selected,
* and every cell selection after that will automaticly put that value into the cell.
*
*/
public int getSelectedRow() {
return selectedRow;
}
public int getSelectedCol() {
return selectedCol;
}
public int getSelectedValue() {
return selectedValue;
}
public void selectCell(int row, int col) {
// TODO if there is a value selected
// TODO should we do this in here or rather in the view?
// we set the value directly
//if(selectedValue != 0) {
//}
if(selectedRow == row && selectedCol == col) {
// if we select the same field 2ce -> deselect it
selectedRow = -1;
@ -332,7 +361,7 @@ public class GameController {
}
}
public void setSelectedValue(int value) {
public void selectValue(int value) {
if(isCellSelected()) setValue(selectedRow, selectedCol, value);
}

View file

@ -0,0 +1,8 @@
package tu_darmstadt.sudoku.controller;
/**
* Created by Chris on 17.11.2015.
*/
public class Highscore {
}

View file

@ -11,7 +11,7 @@ import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import tu_darmstadt.sudoku.game.GameInfoContainer;
import tu_darmstadt.sudoku.controller.helper.GameInfoContainer;
/**
* Created by Chris on 16.11.2015.

View file

@ -5,22 +5,24 @@ package tu_darmstadt.sudoku.controller;
*/
public enum Symbol {
Default(new char[] {'1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N'}),
Fancy(new char[] {'♪', '♫', '☼', '♥', '♦', '♣', '♠', '•', '○', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N' });
SaveFormat(new String[] {"1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "O", "P"}),
Default(new String[] {"1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N"}),
Roman(new String[] {"I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII", "XIII", "XIV", "XV", "XVI", "XVII", "XVIII", "XIX", "XX", "XXI", "XXII"}),
Fancy(new String[] {"", "", "", "", "", "", "", "", "", "A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N" });
private char[] map;
private String[] map;
Symbol(char[] map) {
Symbol(String[] map) {
this.map = map;
}
public static String getSymbol(Symbol type, int value) {
return String.valueOf(type.map[value]);
return (type.map[value]);
}
public static int getValue(Symbol type, char c) {
public static int getValue(Symbol type, String c) {
for(int i = 0; i < type.map.length; i++) {
if(type.map[i] == c) return i;
if(type.map[i].equals(c)) return i;
}
return -1;
}

View file

@ -1,9 +1,12 @@
package tu_darmstadt.sudoku.game;
package tu_darmstadt.sudoku.controller.helper;
import android.util.Log;
import tu_darmstadt.sudoku.controller.GameController;
import tu_darmstadt.sudoku.controller.Symbol;
import tu_darmstadt.sudoku.game.GameCell;
import tu_darmstadt.sudoku.game.GameType;
import tu_darmstadt.sudoku.game.ICellAction;
/**
* Created by Chris on 17.11.2015.
@ -46,7 +49,7 @@ public class GameInfoContainer {
}
fixedValues = new int[s.length()];
for(int i = 0; i < s.length(); i++) {
fixedValues[i] = Symbol.getValue(Symbol.Default, s.charAt(i))+1;
fixedValues[i] = Symbol.getValue(Symbol.SaveFormat, String.valueOf(s.charAt(i)))+1;
}
}
@ -61,7 +64,7 @@ public class GameInfoContainer {
}
setValues = new int[s.length()];
for(int i = 0; i < s.length(); i++) {
setValues[i] = Symbol.getValue(Symbol.Default, s.charAt(i))+1;
setValues[i] = Symbol.getValue(Symbol.SaveFormat, String.valueOf(s.charAt(i)))+1;
}
}
@ -133,7 +136,7 @@ public class GameInfoContainer {
@Override
public StringBuilder action(GameCell gc, StringBuilder existing) {
if (gc.isFixed()) {
existing.append(Symbol.getSymbol(Symbol.Default, gc.getValue() - 1));
existing.append(Symbol.getSymbol(Symbol.SaveFormat, gc.getValue() - 1));
} else {
existing.append(0);
}
@ -151,7 +154,7 @@ public class GameInfoContainer {
if (gc.isFixed() || gc.getValue() == 0) {
existing.append(0);
} else {
existing.append(Symbol.getSymbol(Symbol.Default, gc.getValue() - 1));
existing.append(Symbol.getSymbol(Symbol.SaveFormat, gc.getValue() - 1));
}
return existing;
}

View file

@ -69,6 +69,10 @@ public class GameBoard implements Cloneable {
}
public LinkedList<GameCell> getRow(final int row) {
LinkedList<GameCell> result = new LinkedList<GameCell>();
for(int i = 0; i < size; i++) {
}
return actionOnCells(new ICellAction<LinkedList<GameCell>>() {
@Override
public LinkedList<GameCell> action(GameCell gc, LinkedList<GameCell> existing) {

View file

@ -7,7 +7,7 @@ import tu_darmstadt.sudoku.game.GameBoard;
*/
public interface ISolver {
public boolean solve();
public boolean solve(GameBoard gameBoard);
public boolean calculateNextPossibleStep();

View file

@ -1,7 +1,12 @@
package tu_darmstadt.sudoku.game.solver;
import java.util.LinkedList;
import android.graphics.Point;
import android.util.Log;
import java.util.LinkedList;
import java.util.List;
import tu_darmstadt.sudoku.controller.helper.GameInfoContainer;
import tu_darmstadt.sudoku.game.CellConflict;
import tu_darmstadt.sudoku.game.GameBoard;
import tu_darmstadt.sudoku.game.GameCell;
@ -13,6 +18,7 @@ import tu_darmstadt.sudoku.game.ICellAction;
public class Solver implements ISolver {
private GameBoard gameBoard = null;
private LinkedList<GameBoard> solutions = new LinkedList<>();
public Solver(GameBoard gf) {
try {
@ -36,7 +42,7 @@ public class Solver implements ISolver {
public void setNotes(GameBoard gameBoard) {
for(int i = 0; i < gameBoard.getSize(); i++) {
for(int j = 0; j < gameBoard.getSize(); j++) {
for(int k = 0; k < gameBoard.getSize(); k++) {
for(int k = 1; k <= gameBoard.getSize(); k++) {
gameBoard.getCell(i,j).setNote(k);
}
}
@ -58,34 +64,92 @@ public class Solver implements ISolver {
if(checked.contains(c.getValue())) {
return true;
}
checked.add(c.getValue());
if(c.hasValue()) {
checked.add(c.getValue());
}
}
return false;
}
public boolean solve() {
public LinkedList<GameBoard> getSolutions() {
return solutions;
}
if(gameBoard.isSolved(new LinkedList<CellConflict>())) {
public boolean isDone(GameBoard gameBoard) {
for(int i = 0; i < gameBoard.getSize(); i++) {
for(int j = 0; j < gameBoard.getSize(); j++) {
if(!gameBoard.getCell(i,j).hasValue()) return false;
}
}
return true;
}
public boolean solve(final GameBoard gameBoard) {
checkSolvedCells(gameBoard);
String string = gameBoard.toString();
if(isDone(gameBoard)) {
solutions.add(gameBoard);
return true;
}
checkSolvedCells();
if(showPossibles(gameBoard))
return solve(gameBoard);
if(showPossibles()) return solve();
if(searchHiddenSingles(gameBoard))
return solve(gameBoard);
if(searchHiddenSingles()) return solve();
if(searchNakedPairsTriples(gameBoard))
return solve(gameBoard);
if(searchNakedPairsTriples()) return solve();
if(searchHiddenPairsTriples(gameBoard))
return solve(gameBoard);
if(searchHiddenPairsTriples()) return solve();
if(searchNakedQuads(gameBoard))
return solve(gameBoard);
if(searchNakedQuads()) return solve();
if(searchPointingPairs(gameBoard))
return solve(gameBoard);
if(searchPointingPairs()) return solve();
if(searchBoxLineReduction(gameBoard))
return solve(gameBoard);
if(searchBoxLineReduction()) return solve();
return false;
// if every defined strategy fails.. we have to guess
// get the best candidate
Point p = getBestCandidate(gameBoard);
// then we test every possible value for that candidate, but we do it on a cloned gameBoard
boolean result = false;
for(int i = 0; i < gameBoard.getSize(); i++) {
GameCell gc = gameBoard.getCell(p.x,p.y);
try {
if(gc.getNotes()[i]) {
GameBoard gameBoardCopy = gameBoard.clone();
GameCell copyGC = gameBoardCopy.getCell(p.x, p.y);
copyGC.setValue(i);
result = solve(gameBoardCopy);
//if (result) {
// stop after we found 1 solution
//return true;
// or keep going to find multiple solutions
//}
} else {
continue;
}
} catch(CloneNotSupportedException e) {
return false;
}
}
return result;
}
@Override
@ -98,7 +162,28 @@ public class Solver implements ISolver {
return gameBoard;
}
public boolean showPossibles() {
private boolean checkSolvedCells(final GameBoard gameBoard) {
return gameBoard.actionOnCells(new ICellAction<Boolean>() {
@Override
public Boolean action(GameCell gc, Boolean existing) {
int value = -1;
if(!gc.hasValue() && gc.getNoteCount() == 1) {
for(int i = 0; i < gameBoard.getSize(); i++) {
if(gc.getNotes()[i]) {
value = i+1;
break;
}
}
gc.setValue(value);
existing = true;
}
return existing;
}}, false);
}
public boolean showPossibles(final GameBoard gameBoard) {
boolean deletedSomething = false;
LinkedList<GameCell> list = new LinkedList<GameCell>();
for(int i = 0; i < gameBoard.getSize(); i++) {
for(int j = 0; j < gameBoard.getSize(); j++) {
@ -108,19 +193,21 @@ public class Solver implements ISolver {
list.addAll(gameBoard.getRow(i));
list.addAll(gameBoard.getColumn(j));
list.addAll(gameBoard.getSection(i,j));
for(int k = 0; k < gameBoard.getSize(); k++) {
for(GameCell c : list) {
gc.deleteNote(c.getValue());
for(GameCell c : list) {
for(int k = 0; k < gameBoard.getSize(); k++) {
if(gc.getNotes()[k] && c.hasValue() && !c.equals(gc) && k+1 == c.getValue()) {
gc.deleteNote(c.getValue());
deletedSomething = true;
}
}
}
}
}
}
return false;
return deletedSomething;
}
private boolean searchHiddenSingles() {
private boolean searchHiddenSingles(final GameBoard gameBoard) {
boolean foundHiddenSingles = false;
LinkedList<GameCell> list = new LinkedList<>();
@ -183,40 +270,68 @@ public class Solver implements ISolver {
return foundHiddenSingles;
}
public boolean searchNakedPairsTriples() {
public boolean searchNakedPairsTriples(final GameBoard gameBoard) {
return false;
}
public boolean searchHiddenPairsTriples() {
public boolean searchHiddenPairsTriples(final GameBoard gameBoard) {
return false;
}
public boolean searchNakedQuads() {
public boolean searchNakedQuads(final GameBoard gameBoard) {
return false;
}
public boolean searchPointingPairs() {
public boolean searchPointingPairs(final GameBoard gameBoard) {
return false;
}
public boolean searchBoxLineReduction() {
public boolean searchBoxLineReduction(final GameBoard gameBoard) {
return false;
}
private boolean checkSolvedCells() {
return gameBoard.actionOnCells(new ICellAction<Boolean>() {
@Override
public Boolean action(GameCell gc, Boolean existing) {
int value = -1;
if(!gc.hasValue() && gc.getNoteCount() == 1) {
for(int i = 0; i < gameBoard.getSize(); i++) {
if(gc.getNotes()[i]) {
value = i;
break;
}
}
gc.setValue(value);
existing = true;
}
return existing;
}}, false);
public Point getBestCandidate(GameBoard gameBoard) {
Point bestCandidate = new Point();
int minimumCount = gameBoard.getSize();
int count = 0;
Point candidate = new Point();
for(int i = 0; i < gameBoard.getSize(); i++) {
count = countUnsolved(gameBoard.getRow(i),candidate);
if(count < minimumCount) {
minimumCount = count;
bestCandidate.set(candidate.x, candidate.y);
}
count = countUnsolved(gameBoard.getColumn(i),candidate);
if(count < minimumCount) {
minimumCount = count;
bestCandidate.set(candidate.x, candidate.y);
}
count = countUnsolved(gameBoard.getSection(i),candidate);
if(count < minimumCount) {
minimumCount = count;
bestCandidate.set(candidate.x, candidate.y);
}
if(minimumCount == 2) {
return bestCandidate;
}
}
return bestCandidate;
}
public int countUnsolved(final List<GameCell> list, Point p) {
int count = 0;
for(GameCell gc : list) {
if(!gc.hasValue()) {
count++;
p.set(gc.getRow(), gc.getCol());
}
}
return count;
}
}

View file

@ -1,10 +1,13 @@
package tu_darmstadt.sudoku.ui;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MenuItem;
import android.widget.TextView;
import tu_darmstadt.sudoku.ui.view.R;

View file

@ -17,7 +17,7 @@ import java.util.List;
import tu_darmstadt.sudoku.controller.SaveLoadController;
import tu_darmstadt.sudoku.controller.GameController;
import tu_darmstadt.sudoku.game.GameInfoContainer;
import tu_darmstadt.sudoku.controller.helper.GameInfoContainer;
import tu_darmstadt.sudoku.game.GameType;
import tu_darmstadt.sudoku.ui.view.R;
import tu_darmstadt.sudoku.ui.view.SudokuFieldLayout;
@ -91,7 +91,7 @@ public class GameActivity extends AppCompatActivity implements NavigationView.On
//set Special keys
specialButtonLayout = (SudokuSpecialButtonLayout) findViewById(R.id.sudokuSpecialLayout);
specialButtonLayout.setButtons(p.x,gameController,keyboard);
specialButtonLayout.setButtons(p.x, gameController, keyboard);
/*
// DEBUG
String debug = gameController.getFieldAsString();

View file

@ -18,7 +18,7 @@ import android.widget.TextView;
import java.util.List;
import tu_darmstadt.sudoku.controller.SaveLoadController;
import tu_darmstadt.sudoku.game.GameInfoContainer;
import tu_darmstadt.sudoku.controller.helper.GameInfoContainer;
import tu_darmstadt.sudoku.ui.view.R;
public class LoadGameActivity extends AppCompatActivity {

View file

@ -24,7 +24,7 @@ import android.widget.TextView;
import java.util.List;
import tu_darmstadt.sudoku.controller.SaveLoadController;
import tu_darmstadt.sudoku.game.GameInfoContainer;
import tu_darmstadt.sudoku.controller.helper.GameInfoContainer;
import tu_darmstadt.sudoku.game.GameType;
import tu_darmstadt.sudoku.ui.view.R;

View file

@ -130,7 +130,7 @@ public class SudokuCellView extends View {
p.setTextSize(mWidth / 4);
p.setTextAlign(Paint.Align.RIGHT);
// TODO settings: get SymbolEnum from settings
canvas.drawText(String.valueOf(Symbol.getSymbol(symbolsToUse, i)),(mWidth*1/12)*k,(mWidth*1/12)*j,p);
canvas.drawText(Symbol.getSymbol(symbolsToUse, i),(mWidth*1/12)*k,(mWidth*1/12)*j,p);
/*canvas.drawText(String.valueOf(1), (mWidth * 1 / 12)*3, (mWidth* 1 / 12)*3, p);
canvas.drawText(String.valueOf(2),(mWidth*1/12)*7, (mWidth* 1 / 12)*7,p );
canvas.drawText(String.valueOf(3),(mWidth*1/12)*11, (mWidth* 1 / 12)*11,p );*/
@ -152,7 +152,7 @@ public class SudokuCellView extends View {
p.setTextSize(Math.min(mHeight * 3 / 4, mHeight * 3 / 4));
p.setTextAlign(Paint.Align.CENTER);
// TODO settings: get SymbolEnum from settings
canvas.drawText(String.valueOf(Symbol.getSymbol(symbolsToUse, mGameCell.getValue()-1)), mHeight / 2, mHeight / 2 + mHeight / 4, p);
canvas.drawText(Symbol.getSymbol(symbolsToUse, mGameCell.getValue()-1), mHeight / 2, mHeight / 2 + mHeight / 4, p);
}
public int getRow() {

View file

@ -2,7 +2,6 @@ package tu_darmstadt.sudoku.ui.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
@ -32,7 +31,7 @@ public class SudokuKeyboardLayout extends GridLayout {
if(notesEnabled) {
gameController.toggleSelectedNote(btn.getValue());
} else {
gameController.setSelectedValue(btn.getValue());
gameController.selectValue(btn.getValue());
}
gameController.saveGame(getContext());
}

View file

@ -82,6 +82,7 @@
android:text="@string/more_info"/>
<TextView
android:id="@+id/linkID"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/url"

View file

@ -3,7 +3,7 @@ package tu_darmstadt.sudoku.controller;
import org.junit.Before;
import org.junit.Test;
import tu_darmstadt.sudoku.game.GameInfoContainer;
import tu_darmstadt.sudoku.controller.helper.GameInfoContainer;
import tu_darmstadt.sudoku.game.GameType;
import static org.junit.Assert.*;

View file

@ -1,11 +1,19 @@
package tu_darmstadt.sudoku.game.solver;
import android.util.Log;
import org.junit.Before;
import org.junit.Test;
import java.util.LinkedList;
import tu_darmstadt.sudoku.controller.GameController;
import tu_darmstadt.sudoku.controller.helper.GameInfoContainer;
import tu_darmstadt.sudoku.game.GameBoard;
import tu_darmstadt.sudoku.game.GameType;
import static junit.framework.Assert.assertEquals;
/**
* Created by Chris on 12.11.2015.
*/
@ -15,31 +23,63 @@ public class SolverTest {
@Before
public void init() {
/*controller = new GameController();
int[][] level = {{ 5, 0, 1, 9, 0, 0, 0, 0, 0 },
{ 2, 0, 0, 0, 0, 4, 9, 5, 0 },
{ 3, 9, 0, 7, 0, 0, 0, 2, 6 },
controller = new GameController();
controller.loadLevel(new GameInfoContainer(0, GameType.Default_9x9,
new int[]{5, 0, 1, 9, 0, 0, 0, 0, 0,
2, 0, 0, 0, 0, 4, 9, 5, 0,
3, 9, 0, 7, 0, 0, 0, 2, 6,
0, 3, 0, 0, 0, 1, 0, 7, 2,
0, 0, 6, 0, 5, 7, 0, 0, 0,
0, 7, 2, 0, 0, 9, 0, 4, 1,
0, 0, 0, 0, 7, 0, 4, 0, 9,
6, 4, 0, 0, 0, 0, 0, 0, 0,
7, 0, 0, 0, 1, 0, 3, 0, 5}
, null, null));
{ 0, 3, 0, 0, 0, 1, 0, 7, 2 },
{ 0, 0, 6, 0, 5, 7, 0, 0, 0 },
{ 0, 7, 2, 0, 0, 9, 0, 4, 1 },
{ 0, 0, 0, 0, 7, 0, 4, 0, 9 },
{ 6, 4, 0, 0, 0, 0, 0, 0, 0 },
{ 7, 0, 0, 0, 1, 0, 3, 0, 5 }};
controller.loadLevel(GameType.icon_default_9x9,
new int[]{0,0,0,0,4,1,0,0,0,0,6,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,3,2,0,6,0,0,0,0,0,0,0,0,0,5,0,0,4,1,7,0,0,0,0,0,0,0,0,0,0,0,2,0,0,3,0,0,0,4,8,0,0,0,0,0,0,5,0,1,0,0,0,0,0,0},
null,
null);*/
/*controller.loadLevel(new GameInfoContainer(3, GameType.Default_9x9,
new int[]{0,0,0,0,4,1,0,0,0,0,6,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,3,2,0,6,0,0,0,0,0,0,0,0,0,5,0,0,4,1,7,0,0,0,0,0,0,0,0,0,0,0,2,0,0,3,0,0,0,4,8,0,0,0,0,0,0,5,0,1,0,0,0,0,0,0}
, null, null));*/
}
//000041000060000200000000000320600000000050041700000000000200300048000000501000000
//501900000200004950390700026030001072006057000072009041000070409640000000700010305
@Test
public void solveTest() {
public void solveTest1() {
LinkedList<GameBoard> result = controller.solve();
for(GameBoard gb : result) {
assertEquals("[GameBoard: \n" +
"\t[5 (0|0)] [8 (0|1)] [1 (0|2)] \t[9 (0|3)] [2 (0|4)] [6 (0|5)] \t[7 (0|6)] [3 (0|7)] [4 (0|8)] ]" +
"\t[2 (1|0)] [6 (1|1)] [7 (1|2)] \t[1 (1|3)] [3 (1|4)] [4 (1|5)] \t[9 (1|6)] [5 (1|7)] [8 (1|8)] ]" +
"\t[3 (2|0)] [9 (2|1)] [4 (2|2)] \t[7 (2|3)] [8 (2|4)] [5 (2|5)] \t[1 (2|6)] [2 (2|7)] [6 (2|8)] ]" +
"\t[9 (3|0)] [3 (3|1)] [5 (3|2)] \t[8 (3|3)] [4 (3|4)] [1 (3|5)] \t[6 (3|6)] [7 (3|7)] [2 (3|8)] ]" +
"\t[4 (4|0)] [1 (4|1)] [6 (4|2)] \t[2 (4|3)] [5 (4|4)] [7 (4|5)] \t[8 (4|6)] [9 (4|7)] [3 (4|8)] ]" +
"\t[8 (5|0)] [7 (5|1)] [2 (5|2)] \t[3 (5|3)] [6 (5|4)] [9 (5|5)] \t[5 (5|6)] [4 (5|7)] [1 (5|8)] ]" +
"\t[1 (6|0)] [5 (6|1)] [3 (6|2)] \t[6 (6|3)] [7 (6|4)] [2 (6|5)] \t[4 (6|6)] [8 (6|7)] [9 (6|8)] ]" +
"\t[6 (7|0)] [4 (7|1)] [8 (7|2)] \t[5 (7|3)] [9 (7|4)] [3 (7|5)] \t[2 (7|6)] [1 (7|7)] [7 (7|8)] ]" +
"\t[7 (8|0)] [2 (8|1)] [9 (8|2)] \t[4 (8|3)] [1 (8|4)] [8 (8|5)] \t[3 (8|6)] [6 (8|7)] [5 (8|8)] ]",
gb.toString());
}
}
@Test
public void solveTest2() {
controller.loadLevel(new GameInfoContainer(0, GameType.Default_9x9,
new int[]{0,0,0,0,4,1,0,0,0,0,6,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,3,2,0,6,0,0,0,0,0,0,0,0,0,5,0,0,4,1,7,0,0,0,0,0,0,0,0,0,0,0,2,0,0,3,0,0,0,4,8,0,0,0,0,0,0,5,0,1,0,0,0,0,0,0}
, null, null));
LinkedList<GameBoard> result = controller.solve();
for(GameBoard gb : result) {
assertEquals("[GameBoard: \n" +
"\t[8 (0|0)] [7 (0|1)] [2 (0|2)] \t[9 (0|3)] [4 (0|4)] [1 (0|5)] \t[5 (0|6)] [6 (0|7)] [3 (0|8)] ]"+
"\t[1 (1|0)] [6 (1|1)] [9 (1|2)] \t[5 (1|3)] [7 (1|4)] [3 (1|5)] \t[2 (1|6)] [8 (1|7)] [4 (1|8)] ]"+
"\t[4 (2|0)] [5 (2|1)] [3 (2|2)] \t[8 (2|3)] [2 (2|4)] [6 (2|5)] \t[1 (2|6)] [9 (2|7)] [7 (2|8)] ]" +
"\t[3 (3|0)] [2 (3|1)] [4 (3|2)] \t[6 (3|3)] [1 (3|4)] [7 (3|5)] \t[8 (3|6)] [5 (3|7)] [9 (3|8)] ]" +
"\t[9 (4|0)] [8 (4|1)] [6 (4|2)] \t[3 (4|3)] [5 (4|4)] [2 (4|5)] \t[7 (4|6)] [4 (4|7)] [1 (4|8)] ]" +
"\t[7 (5|0)] [1 (5|1)] [5 (5|2)] \t[4 (5|3)] [9 (5|4)] [8 (5|5)] \t[6 (5|6)] [3 (5|7)] [2 (5|8)] ]" +
"\t[6 (6|0)] [9 (6|1)] [7 (6|2)] \t[2 (6|3)] [8 (6|4)] [4 (6|5)] \t[3 (6|6)] [1 (6|7)] [5 (6|8)] ]" +
"\t[2 (7|0)] [4 (7|1)] [8 (7|2)] \t[1 (7|3)] [3 (7|4)] [5 (7|5)] \t[9 (7|6)] [7 (7|7)] [6 (7|8)] ]" +
"\t[5 (8|0)] [3 (8|1)] [1 (8|2)] \t[7 (8|3)] [6 (8|4)] [9 (8|5)] \t[4 (8|6)] [2 (8|7)] [8 (8|8)] ]",
gb.toString());
}
}
}