Updated Model, Solver and GameController.
This commit is contained in:
parent
b9dcf4e2d2
commit
c7402d1196
6 changed files with 163 additions and 100 deletions
|
@ -5,7 +5,7 @@
|
||||||
<GradleProjectSettings>
|
<GradleProjectSettings>
|
||||||
<option name="distributionType" value="LOCAL" />
|
<option name="distributionType" value="LOCAL" />
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
<option name="gradleHome" value="D:\Program Files\Android\Android Studio\gradle\gradle-2.4" />
|
<option name="gradleHome" value="C:\Program Files\Android\Android Studio\gradle\gradle-2.4" />
|
||||||
<option name="gradleJvm" value="1.8" />
|
<option name="gradleJvm" value="1.8" />
|
||||||
<option name="modules">
|
<option name="modules">
|
||||||
<set>
|
<set>
|
||||||
|
|
|
@ -17,6 +17,8 @@ import tu_darmstadt.sudoku.game.ICellAction;
|
||||||
public class GameController {
|
public class GameController {
|
||||||
|
|
||||||
private int size;
|
private int size;
|
||||||
|
private int sectionHeight;
|
||||||
|
private int sectionWidth;
|
||||||
private GameField gameField;
|
private GameField gameField;
|
||||||
private CellConflictList errorList = new CellConflictList();
|
private CellConflictList errorList = new CellConflictList();
|
||||||
private GameSettings settings = new GameSettings();
|
private GameSettings settings = new GameSettings();
|
||||||
|
@ -30,8 +32,8 @@ public class GameController {
|
||||||
}
|
}
|
||||||
|
|
||||||
public GameController(GameType type) {
|
public GameController(GameType type) {
|
||||||
gameField = new GameField(type);
|
setGameType(type);
|
||||||
size = gameField.getSize();
|
gameField = new GameField(size, sectionHeight, sectionWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*public boolean loadLevel(GameField level) {
|
/*public boolean loadLevel(GameField level) {
|
||||||
|
@ -40,7 +42,41 @@ public class GameController {
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
private void setGameType(GameType type) {
|
||||||
|
switch(type) {
|
||||||
|
case Default_9x9:
|
||||||
|
this.size = 9;
|
||||||
|
this.sectionHeight = 3;
|
||||||
|
this.sectionWidth = 3;
|
||||||
|
break;
|
||||||
|
case Default_12x12:
|
||||||
|
this.size = 12;
|
||||||
|
this.sectionHeight = 3;
|
||||||
|
this.sectionWidth = 4;
|
||||||
|
break;
|
||||||
|
case Default_6x6:
|
||||||
|
this.size = 6;
|
||||||
|
this.sectionHeight = 2;
|
||||||
|
this.sectionWidth = 3;
|
||||||
|
break;
|
||||||
|
case Unspecified:
|
||||||
|
default:
|
||||||
|
this.size = 1;
|
||||||
|
this.sectionHeight = 1;
|
||||||
|
this.sectionWidth = 1;
|
||||||
|
throw new IllegalArgumentException("GameType can not be unspecified.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Use with care.
|
||||||
|
*/
|
||||||
|
public GameCell getGameCell(int row, int col) {
|
||||||
|
return gameField.getCell(row,col);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSolved() {
|
||||||
|
return gameField.isSolved(new LinkedList<CellConflict>());
|
||||||
|
}
|
||||||
|
|
||||||
public void setValue(int row, int col, int value) {
|
public void setValue(int row, int col, int value) {
|
||||||
GameCell cell = gameField.getCell(row, col);
|
GameCell cell = gameField.getCell(row, col);
|
||||||
|
@ -58,8 +94,6 @@ public class GameController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void deleteNotes(List<GameCell> updateList, int value) {
|
public void deleteNotes(List<GameCell> updateList, int value) {
|
||||||
for(GameCell c : updateList) {
|
for(GameCell c : updateList) {
|
||||||
c.deleteNote(value);
|
c.deleteNote(value);
|
||||||
|
@ -85,49 +119,6 @@ public class GameController {
|
||||||
return 0 < val && val <= size;
|
return 0 < val && val <= size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSolved() {
|
|
||||||
boolean solved = true;
|
|
||||||
|
|
||||||
// this will automatically build the CellConflict list. so we reset it before we call the checks
|
|
||||||
errorList = new CellConflictList();
|
|
||||||
|
|
||||||
for(int i = 0; i < size; i++) {
|
|
||||||
if(!checkList(gameField.getRow(i))) solved = false;
|
|
||||||
if(!checkList(gameField.getColumn(i))) solved = false;
|
|
||||||
if(!checkList(gameField.getSection(i))) solved = false;
|
|
||||||
}
|
|
||||||
return solved;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks the given list if every number occurs only once.
|
|
||||||
* This method will automatically build the errorList.
|
|
||||||
* @param list the list of {@link GameCell}s that is supposed to be tested.
|
|
||||||
* @return true if every cell has a value and every value occurs only once
|
|
||||||
*/
|
|
||||||
private boolean checkList(List<GameCell> list) {
|
|
||||||
boolean isNothingEmpty = true;
|
|
||||||
CellConflict lastFound = null;
|
|
||||||
|
|
||||||
for(int i = 0; i < list.size(); i++) {
|
|
||||||
for(int j = i + 1; j < list.size(); j++) {
|
|
||||||
GameCell c1 = list.get(i);
|
|
||||||
GameCell c2 = list.get(j);
|
|
||||||
|
|
||||||
if(c1.getValue() == 0 || c2.getValue() == 0) {
|
|
||||||
isNothingEmpty = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Same value in one set should not exist
|
|
||||||
if(c1.getValue() != 0 && c1.getValue() == c2.getValue()) {
|
|
||||||
// we found an error..
|
|
||||||
errorList.add(new CellConflict(c1, c2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return isNothingEmpty ? (errorList.size() == 0) : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<CellConflict> getErrorList() {
|
public List<CellConflict> getErrorList() {
|
||||||
return errorList;
|
return errorList;
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,6 +106,10 @@ public class GameCell implements Cloneable {
|
||||||
fixed = b;
|
fixed = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasValue() {
|
||||||
|
return value > 0;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if(!(other instanceof GameCell)) return false;
|
if(!(other instanceof GameCell)) return false;
|
||||||
|
|
|
@ -2,6 +2,7 @@ package tu_darmstadt.sudoku.game;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Christopher Beckmann on 06.11.2015.
|
* Created by Christopher Beckmann on 06.11.2015.
|
||||||
|
@ -12,56 +13,36 @@ public class GameField implements Cloneable {
|
||||||
private int sectionHeight;
|
private int sectionHeight;
|
||||||
private int sectionWidth;
|
private int sectionWidth;
|
||||||
//private List additionalSections
|
//private List additionalSections
|
||||||
|
private CellConflictList errorList = new CellConflictList();
|
||||||
private int size;
|
private int size;
|
||||||
private GameCell[][] field;
|
private GameCell[][] field;
|
||||||
|
|
||||||
public GameField() {
|
public GameField(int size, int sectionHeight, int sectionWidth) {
|
||||||
this(GameType.Default_9x9);
|
this.sectionHeight = sectionHeight;
|
||||||
}
|
this.sectionWidth = sectionWidth;
|
||||||
|
this.size = size;
|
||||||
public GameField(GameType type) {
|
|
||||||
setGameType(type);
|
|
||||||
|
|
||||||
field = new GameCell[size][size];
|
field = new GameCell[size][size];
|
||||||
|
|
||||||
|
|
||||||
// TODO: this is a placeholder, because we don't have real levels yet.
|
|
||||||
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 },
|
|
||||||
|
|
||||||
{ 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 }};
|
|
||||||
|
|
||||||
initCells(level);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setGameType(GameType type) {
|
|
||||||
switch(type) {
|
|
||||||
case Default_9x9:
|
|
||||||
this.size = 9;
|
|
||||||
this.sectionHeight = 3;
|
|
||||||
this.sectionWidth = 3;
|
|
||||||
break;
|
|
||||||
case Unspecified:
|
|
||||||
default:
|
|
||||||
this.size = 1;
|
|
||||||
this.sectionHeight = 1;
|
|
||||||
this.sectionWidth = 1;
|
|
||||||
throw new IllegalArgumentException("GameType can not be unspecified.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initCells(int[][] level) {
|
public void initCells(int[][] level) {
|
||||||
|
// TODO: this is a placeholder, because we don't have real levels yet.
|
||||||
|
int[][] placeholder = {{ 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 }};
|
||||||
|
|
||||||
// Initit the game field
|
// Initit the game field
|
||||||
for(int i = 0; i < size; i++) {
|
for(int i = 0; i < size; i++) {
|
||||||
for(int j = 0; j < size; j++) {
|
for(int j = 0; j < size; j++) {
|
||||||
field[i][j] = new GameCell(i,j,size,level[i][j]);
|
field[i][j] = new GameCell(i,j,size,placeholder[i][j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,11 +79,12 @@ public class GameField implements Cloneable {
|
||||||
return actionOnCells(new ICellAction<LinkedList<GameCell>>() {
|
return actionOnCells(new ICellAction<LinkedList<GameCell>>() {
|
||||||
@Override
|
@Override
|
||||||
public LinkedList<GameCell> action(GameCell gc, LinkedList<GameCell> existing) {
|
public LinkedList<GameCell> action(GameCell gc, LinkedList<GameCell> existing) {
|
||||||
if((int)(Math.floor(gc.getRow()/sectionHeight)*sectionHeight + Math.floor(gc.getCol()/sectionWidth)) == sec) {
|
if ((int) (Math.floor(gc.getRow() / sectionHeight) * sectionHeight + Math.floor(gc.getCol() / sectionWidth)) == sec) {
|
||||||
existing.add(gc);
|
existing.add(gc);
|
||||||
}
|
}
|
||||||
return existing;
|
return existing;
|
||||||
}}, new LinkedList<GameCell>());
|
}
|
||||||
|
}, new LinkedList<GameCell>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public LinkedList<GameCell> getSection(int row, int col) {
|
public LinkedList<GameCell> getSection(int row, int col) {
|
||||||
|
@ -123,6 +105,55 @@ public class GameField implements Cloneable {
|
||||||
return existing;
|
return existing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isSolved(final List<CellConflict> errorList) {
|
||||||
|
boolean solved = true;
|
||||||
|
|
||||||
|
if(errorList == null) {
|
||||||
|
throw new IllegalArgumentException("ErrorList may not be null.");
|
||||||
|
}
|
||||||
|
errorList.clear();
|
||||||
|
|
||||||
|
// this will automatically build the CellConflict list. so we reset it before we call the checks
|
||||||
|
|
||||||
|
for(int i = 0; i < size; i++) {
|
||||||
|
if(!checkList(getRow(i), errorList)) solved = false;
|
||||||
|
if(!checkList(getColumn(i), errorList)) solved = false;
|
||||||
|
if(!checkList(getSection(i), errorList)) solved = false;
|
||||||
|
}
|
||||||
|
return solved;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the given list if every number occurs only once.
|
||||||
|
* This method will automatically build the errorList.
|
||||||
|
* @param list the list of {@link GameCell}s that is supposed to be tested.
|
||||||
|
* @return true if every cell has a value and every value occurs only once
|
||||||
|
*/
|
||||||
|
private boolean checkList(final List<GameCell> list, final List<CellConflict> errorList) {
|
||||||
|
boolean isNothingEmpty = true;
|
||||||
|
CellConflict lastFound = null;
|
||||||
|
|
||||||
|
for(int i = 0; i < list.size(); i++) {
|
||||||
|
for(int j = i + 1; j < list.size(); j++) {
|
||||||
|
GameCell c1 = list.get(i);
|
||||||
|
GameCell c2 = list.get(j);
|
||||||
|
|
||||||
|
if(c1.getValue() == 0 || c2.getValue() == 0) {
|
||||||
|
isNothingEmpty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same value in one set should not exist
|
||||||
|
if(c1.getValue() != 0 && c1.getValue() == c2.getValue()) {
|
||||||
|
// we found an error..
|
||||||
|
if(errorList != null) {
|
||||||
|
errorList.add(new CellConflict(c1, c2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isNothingEmpty ? (errorList.size() == 0) : false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GameField clone() throws CloneNotSupportedException {
|
public GameField clone() throws CloneNotSupportedException {
|
||||||
GameField clone = (GameField) super.clone();
|
GameField clone = (GameField) super.clone();
|
||||||
|
|
|
@ -7,7 +7,7 @@ public enum GameType {
|
||||||
Unspecified,
|
Unspecified,
|
||||||
Default_9x9,
|
Default_9x9,
|
||||||
Default_9x6,
|
Default_9x6,
|
||||||
Default_12x9,
|
Default_12x12,
|
||||||
Default_6x6
|
Default_6x6
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package tu_darmstadt.sudoku.game.solver;
|
package tu_darmstadt.sudoku.game.solver;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
import tu_darmstadt.sudoku.game.CellConflict;
|
||||||
import tu_darmstadt.sudoku.game.GameCell;
|
import tu_darmstadt.sudoku.game.GameCell;
|
||||||
import tu_darmstadt.sudoku.game.GameField;
|
import tu_darmstadt.sudoku.game.GameField;
|
||||||
import tu_darmstadt.sudoku.game.ICellAction;
|
import tu_darmstadt.sudoku.game.ICellAction;
|
||||||
|
@ -25,8 +28,12 @@ public class Default9x9Solver implements ISolver {
|
||||||
|
|
||||||
public boolean solve() {
|
public boolean solve() {
|
||||||
|
|
||||||
|
if(gameField.isSolved(new LinkedList<CellConflict>())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
checkSolvedCells();
|
checkSolvedCells();
|
||||||
/*
|
|
||||||
if(showPossibles()) return solve();
|
if(showPossibles()) return solve();
|
||||||
|
|
||||||
if(searchHiddenSingles()) return solve();
|
if(searchHiddenSingles()) return solve();
|
||||||
|
@ -41,15 +48,7 @@ public class Default9x9Solver implements ISolver {
|
||||||
|
|
||||||
if(searchBoxLineReduction()) return solve();
|
if(searchBoxLineReduction()) return solve();
|
||||||
|
|
||||||
selectBestCell();
|
return false;
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -61,6 +60,44 @@ public class Default9x9Solver implements ISolver {
|
||||||
return gameField;
|
return gameField;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean showPossibles() {
|
||||||
|
LinkedList<GameCell> list = new LinkedList<GameCell>();
|
||||||
|
for(int i = 0; i < gameField.getSize(); i++) {
|
||||||
|
for(int j = 0; j < gameField.getSize(); j++) {
|
||||||
|
GameCell gc = gameField.getCell(i,j);
|
||||||
|
if(!gc.hasValue()) {
|
||||||
|
list.clear();
|
||||||
|
list.addAll(gameField.getRow(i));
|
||||||
|
list.addAll(gameField.getColumn(j));
|
||||||
|
list.addAll(gameField.getSection(i,j));
|
||||||
|
for(int k = 0; k < gameField.getSize(); k++) {
|
||||||
|
for(GameCell c : list) {
|
||||||
|
gc.deleteNote(c.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean searchNakedPairsTriples() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public boolean searchHiddenPairsTriples() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public boolean searchNakedQuads() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public boolean searchPointingPairs() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public boolean searchBoxLineReduction() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean checkSolvedCells() {
|
private boolean checkSolvedCells() {
|
||||||
return gameField.actionOnCells(new ICellAction<Boolean>() {
|
return gameField.actionOnCells(new ICellAction<Boolean>() {
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Reference in a new issue