Updated Model, Solver and GameController.

This commit is contained in:
Christopher Beckmann 2015-11-11 16:02:13 +01:00
parent b9dcf4e2d2
commit c7402d1196
6 changed files with 163 additions and 100 deletions

View file

@ -5,7 +5,7 @@
<GradleProjectSettings>
<option name="distributionType" value="LOCAL" />
<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="modules">
<set>

View file

@ -17,6 +17,8 @@ import tu_darmstadt.sudoku.game.ICellAction;
public class GameController {
private int size;
private int sectionHeight;
private int sectionWidth;
private GameField gameField;
private CellConflictList errorList = new CellConflictList();
private GameSettings settings = new GameSettings();
@ -30,8 +32,8 @@ public class GameController {
}
public GameController(GameType type) {
gameField = new GameField(type);
size = gameField.getSize();
setGameType(type);
gameField = new GameField(size, sectionHeight, sectionWidth);
}
/*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) {
GameCell cell = gameField.getCell(row, col);
@ -58,8 +94,6 @@ public class GameController {
}
}
public void deleteNotes(List<GameCell> updateList, int value) {
for(GameCell c : updateList) {
c.deleteNote(value);
@ -85,49 +119,6 @@ public class GameController {
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() {
return errorList;
}

View file

@ -106,6 +106,10 @@ public class GameCell implements Cloneable {
fixed = b;
}
public boolean hasValue() {
return value > 0;
}
@Override
public boolean equals(Object other) {
if(!(other instanceof GameCell)) return false;

View file

@ -2,6 +2,7 @@ package tu_darmstadt.sudoku.game;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
/**
* Created by Christopher Beckmann on 06.11.2015.
@ -12,56 +13,36 @@ public class GameField implements Cloneable {
private int sectionHeight;
private int sectionWidth;
//private List additionalSections
private CellConflictList errorList = new CellConflictList();
private int size;
private GameCell[][] field;
public GameField() {
this(GameType.Default_9x9);
}
public GameField(GameType type) {
setGameType(type);
public GameField(int size, int sectionHeight, int sectionWidth) {
this.sectionHeight = sectionHeight;
this.sectionWidth = sectionWidth;
this.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) {
// 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
for(int i = 0; i < size; i++) {
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>>() {
@Override
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);
}
return existing;
}}, new LinkedList<GameCell>());
}
}, new LinkedList<GameCell>());
}
public LinkedList<GameCell> getSection(int row, int col) {
@ -123,6 +105,55 @@ public class GameField implements Cloneable {
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
public GameField clone() throws CloneNotSupportedException {
GameField clone = (GameField) super.clone();

View file

@ -7,7 +7,7 @@ public enum GameType {
Unspecified,
Default_9x9,
Default_9x6,
Default_12x9,
Default_12x12,
Default_6x6

View file

@ -1,5 +1,8 @@
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.GameField;
import tu_darmstadt.sudoku.game.ICellAction;
@ -25,8 +28,12 @@ public class Default9x9Solver implements ISolver {
public boolean solve() {
if(gameField.isSolved(new LinkedList<CellConflict>())) {
return true;
}
checkSolvedCells();
/*
if(showPossibles()) return solve();
if(searchHiddenSingles()) return solve();
@ -41,15 +48,7 @@ public class Default9x9Solver implements ISolver {
if(searchBoxLineReduction()) return solve();
selectBestCell();
*/
return true;
return false;
}
@Override
@ -61,6 +60,44 @@ public class Default9x9Solver implements ISolver {
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() {
return gameField.actionOnCells(new ICellAction<Boolean>() {
@Override