diff --git a/app/src/main/java/tu_darmstadt/sudoku/controller/GameController.java b/app/src/main/java/tu_darmstadt/sudoku/controller/GameController.java index 00188fb..6ff3c05 100644 --- a/app/src/main/java/tu_darmstadt/sudoku/controller/GameController.java +++ b/app/src/main/java/tu_darmstadt/sudoku/controller/GameController.java @@ -10,6 +10,8 @@ import tu_darmstadt.sudoku.game.GameField; import tu_darmstadt.sudoku.game.GameSettings; import tu_darmstadt.sudoku.game.GameType; import tu_darmstadt.sudoku.game.ICellAction; +import tu_darmstadt.sudoku.game.solver.Default9x9Solver; +import tu_darmstadt.sudoku.game.solver.ISolver; /** * Created by Chris on 06.11.2015. @@ -20,9 +22,13 @@ public class GameController { private int sectionHeight; private int sectionWidth; private GameField gameField; + private ISolver solver; + private GameType gameType; + private int selectedRow; + private int selectedCol; private CellConflictList errorList = new CellConflictList(); private GameSettings settings = new GameSettings(); - private LinkedList listeners = new LinkedList<>(); + //private LinkedList listeners = new LinkedList<>(); // private Default9x9Solver solver; // private SudokuGenerator generator; @@ -32,16 +38,24 @@ public class GameController { } public GameController(GameType type) { + this.gameType = type; setGameType(type); gameField = new GameField(size, sectionHeight, sectionWidth); - setValue(0, 1, 8); setValue(0, 4, 2); - setValue(1, 1, 6); setValue(1, 2, 7); - setValue(2, 4, 8); setValue(2, 5, 5); - setValue(3, 4, 4); setValue(3, 6, 6); - setValue(4, 7, 9); setValue(4, 8, 3); - setValue(6, 0, 1); setValue(6, 1, 5); - setValue(7, 2, 8); setValue(7, 3, 5); - setValue(8, 2, 9); setValue(8, 3, 4); + } + + private GameField solve(GameField gameField) { + switch(gameType) { + case Default_9x9: + solver = new Default9x9Solver(gameField); + break; + default: + throw new UnsupportedOperationException("No Solver for this GameType defined."); + } + + if(solver.solve()) { + return solver.getGameField(); + } + return null; } /*public boolean loadLevel(GameField level) { @@ -102,6 +116,19 @@ public class GameController { } } + public LinkedList getConnectedCells(int row, int col, boolean connectedSec, boolean connectedRow, boolean connectedCol) { + LinkedList list = new LinkedList<>(); + + if(connectedRow) list.addAll(gameField.getRow(row)); + list.remove(gameField.getCell(row, col)); + if(connectedCol) list.addAll(gameField.getColumn(col)); + list.remove(gameField.getCell(row, col)); + if(connectedSec) list.addAll(gameField.getSection(row, col)); + list.remove(gameField.getCell(row, col)); + + return list; + } + public void deleteNotes(List updateList, int value) { for(GameCell c : updateList) { c.deleteNote(value); @@ -132,21 +159,15 @@ public class GameController { } public void resetLevel() { - gameField.actionOnCells(new ICellAction() { - @Override - public Boolean action(GameCell gc, Boolean existing) { - gc.reset(); - return true; - } - }, true); - notifyListeners(); + gameField.reset(); + //notifyListeners(); } public boolean deleteValue(int row, int col) { GameCell c = gameField.getCell(row,col); if(!c.isFixed()) { c.setValue(0); - notifyListeners(); + //notifyListeners(); return true; } return false; @@ -155,7 +176,7 @@ public class GameController { public void setNote(int row, int col, int value) { GameCell c = gameField.getCell(row,col); c.setNote(value); - notifyListeners(); + //notifyListeners(); } public boolean[] getNotes(int row, int col) { @@ -166,13 +187,13 @@ public class GameController { public void deleteNote(int row, int col, int value) { GameCell c = gameField.getCell(row,col); c.deleteNote(value); - notifyListeners(); + //notifyListeners(); } public void toggleNote(int row, int col, int value) { GameCell c = gameField.getCell(row,col); c.toggleNote(value); - notifyListeners(); + //notifyListeners(); } /** Debug only method @@ -183,12 +204,21 @@ public class GameController { return gameField.toString(); } - public void registerListener(IModelChangeListener l) { - if(!listeners.contains(l)) { - listeners.add(l); - } + public void selectCell(int row, int col) { + this.selectedRow = row; + this.selectedCol = col; } + public void setSelectedValue(int value) { + setValue(selectedRow, selectedCol, value); + } + +// public void registerListener(IModelChangeListener l) { +// if(!listeners.contains(l)) { +// listeners.add(l); +// } +// } + public int getSectionHeight() { return sectionHeight; } @@ -197,10 +227,10 @@ public class GameController { return sectionWidth; } - public void notifyListeners() { - for(IModelChangeListener l : listeners) { - l.onModelChanged(); - } - } +// public void notifyListeners() { +// for(IModelChangeListener l : listeners) { +// l.onModelChanged(); +// } +// } } diff --git a/app/src/main/java/tu_darmstadt/sudoku/controller/IModelChangeListener.java b/app/src/main/java/tu_darmstadt/sudoku/controller/IModelChangeListener.java deleted file mode 100644 index f551e96..0000000 --- a/app/src/main/java/tu_darmstadt/sudoku/controller/IModelChangeListener.java +++ /dev/null @@ -1,8 +0,0 @@ -package tu_darmstadt.sudoku.controller; - -/** - * Created by Chris on 11.11.2015. - */ -public interface IModelChangeListener { - public void onModelChanged(); -} diff --git a/app/src/main/java/tu_darmstadt/sudoku/game/GameField.java b/app/src/main/java/tu_darmstadt/sudoku/game/GameField.java index 4d8bf9c..43a4ef3 100644 --- a/app/src/main/java/tu_darmstadt/sudoku/game/GameField.java +++ b/app/src/main/java/tu_darmstadt/sudoku/game/GameField.java @@ -26,6 +26,16 @@ public class GameField implements Cloneable { initCells(null); } + public void reset() { + actionOnCells(new ICellAction() { + @Override + public Boolean action(GameCell gc, Boolean existing) { + gc.reset(); + return true; + } + }, true); + } + 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 }, @@ -56,24 +66,28 @@ public class GameField implements Cloneable { return field; } - public LinkedList getRow(int row) { - LinkedList result = new LinkedList(); - for(GameCell c : field[row]) { - result.add(c); - } - return result; + public LinkedList getRow(final int row) { + return actionOnCells(new ICellAction>() { + @Override + public LinkedList action(GameCell gc, LinkedList existing) { + if(gc.getRow() == row) { + existing.add(gc); + } + return existing; + } + }, new LinkedList()); } - public LinkedList getColumn(int col) { - LinkedList result = new LinkedList(); - for(int i = 0; i < size ; i++) { // row - for(int j = 0 ; j < size ; j++) { // col - if(j == col) { - result.add(field[i][j]); + public LinkedList getColumn(final int col) { + return actionOnCells(new ICellAction>() { + @Override + public LinkedList action(GameCell gc, LinkedList existing) { + if(gc.getCol() == col) { + existing.add(gc); } + return existing; } - } - return result; + }, new LinkedList()); } public LinkedList getSection(final int sec) { diff --git a/app/src/main/java/tu_darmstadt/sudoku/game/GameSettings.java b/app/src/main/java/tu_darmstadt/sudoku/game/GameSettings.java index c43033a..04ffcd3 100644 --- a/app/src/main/java/tu_darmstadt/sudoku/game/GameSettings.java +++ b/app/src/main/java/tu_darmstadt/sudoku/game/GameSettings.java @@ -4,9 +4,22 @@ package tu_darmstadt.sudoku.game; * Created by Chris on 09.11.2015. */ public class GameSettings { - private boolean enableAutomaticNoteDeletion = true; + private static boolean enableAutomaticNoteDeletion = true; + private static boolean highlightConnectedRow = true; + private static boolean highlightConnectedColumn = true; + private static boolean highlightConnectedSection = true; - public boolean getEnableAutomaticNoteDeletion() { + + public static boolean getEnableAutomaticNoteDeletion() { return enableAutomaticNoteDeletion; } + public static boolean getHighlightConnectedRow() { + return highlightConnectedRow; + } + public static boolean getHighlightConnectedColumn() { + return highlightConnectedColumn; + } + public static boolean getHighlightConnectedSection() { + return highlightConnectedSection; + } } diff --git a/app/src/main/java/tu_darmstadt/sudoku/game/solver/Default9x9Solver.java b/app/src/main/java/tu_darmstadt/sudoku/game/solver/Default9x9Solver.java index a82218e..668783c 100644 --- a/app/src/main/java/tu_darmstadt/sudoku/game/solver/Default9x9Solver.java +++ b/app/src/main/java/tu_darmstadt/sudoku/game/solver/Default9x9Solver.java @@ -1,6 +1,7 @@ package tu_darmstadt.sudoku.game.solver; import java.util.LinkedList; +import java.util.List; import tu_darmstadt.sudoku.game.CellConflict; import tu_darmstadt.sudoku.game.GameCell; @@ -14,16 +15,42 @@ public class Default9x9Solver implements ISolver { private GameField gameField = null; - Default9x9Solver(GameField gameField) { + public Default9x9Solver(GameField gf) { try { - if(gameField == null) { + if(gf == null) { throw new IllegalArgumentException("GameField may not be null."); } - this.gameField = gameField.clone(); + gameField = gf.clone(); } catch(CloneNotSupportedException e) { throw new IllegalArgumentException("This GameField is not cloneable.", e); } + + gameField.reset(); + if(!isSolvable(gameField)) { + throw new IllegalArgumentException("This GameField is not solveable."); + } + + } + + public boolean isSolvable(GameField gameField) { + for(int i = 0; i < gameField.getSize(); i++) { + if(hasErrors(gameField.getRow(i))) return false; + if(hasErrors(gameField.getColumn(i))) return false; + if(hasErrors(gameField.getSection(i))) return false; + } + return true; + } + + public boolean hasErrors(LinkedList list) { + LinkedList checked = new LinkedList(); + for(GameCell c : list) { + if(checked.contains(c.getValue())) { + return true; + } + checked.add(c.getValue()); + } + return false; } public boolean solve() { @@ -53,6 +80,7 @@ public class Default9x9Solver implements ISolver { @Override public boolean calculateNextPossibleStep() { + return false; } @@ -102,9 +130,8 @@ public class Default9x9Solver implements ISolver { return gameField.actionOnCells(new ICellAction() { @Override public Boolean action(GameCell gc, Boolean existing) { - boolean oneNote = false; int value = -1; - if(gc.getNoteCount() == 1) { + if(!gc.hasValue() && gc.getNoteCount() == 1) { for(int i = 0; i < gameField.getSize(); i++) { if(gc.getNotes()[i]) { value = i; diff --git a/app/src/main/java/tu_darmstadt/sudoku/view/SudokuCellView.java b/app/src/main/java/tu_darmstadt/sudoku/view/SudokuCellView.java index 5087949..da00664 100644 --- a/app/src/main/java/tu_darmstadt/sudoku/view/SudokuCellView.java +++ b/app/src/main/java/tu_darmstadt/sudoku/view/SudokuCellView.java @@ -15,6 +15,7 @@ import android.widget.Toast; import java.util.jar.Attributes; import tu_darmstadt.sudoku.game.GameCell; +import tu_darmstadt.sudoku.view.highlighting.CellHighlightTypes; /** * Created by TMZ_LToP on 10.11.2015. @@ -23,12 +24,13 @@ public class SudokuCellView extends View { GameCell mGameCell; int mWidth; + int mHeight; int mSectionHeight; int mSectionWidth; int mRow; int mCol; - boolean touched; boolean selected; + CellHighlightTypes highlightType = CellHighlightTypes.Default; public SudokuCellView(Context context) { @@ -43,51 +45,78 @@ public class SudokuCellView extends View { this.selected = b; } - public void setValues (int width, int sectionHeight, int sectionWidth, GameCell gameCell) { + public void setValues (int width, int height, int sectionHeight, int sectionWidth, GameCell gameCell) { mSectionHeight = sectionHeight; mSectionWidth = sectionWidth; mGameCell = gameCell; mWidth = width; + mHeight = height; mRow = gameCell.getRow(); mCol = gameCell.getCol(); } - @Override + public void setHighlightType(CellHighlightTypes highlightType) { + this.highlightType = highlightType; + } + + /*@Override public boolean onTouchEvent(MotionEvent motionEvent) { if(mGameCell == null) return false; - touched = true; + if(motionEvent.getAction() == motionEvent.ACTION_DOWN) { + highlightType = CellHighlightTypes.Selected; + } return true; - } + }*/ @Override public void onDraw(Canvas canvas) { super.onDraw(canvas); - RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(mWidth, mWidth); - params.topMargin = mRow*mWidth; + // Set Layout + RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(mWidth, mHeight); + params.topMargin = mRow*mHeight; params.leftMargin = mCol*mWidth; this.setLayoutParams(params); - if(mGameCell == null) { - return; - } - drawBackground(canvas); - drawValue(canvas); + // Draw single Field + drawInfo(canvas); } - public void drawBackground(Canvas canvas) { + private void drawInfo(Canvas canvas) { Paint p = new Paint(); - p.setColor(Color.WHITE); - RectF rect = new RectF(3, 3, mWidth-3, mWidth-3); - canvas.drawRect(rect, p); - - if(touched) { - p.setColor(Color.GREEN); - RectF rectTouched = new RectF(3, 3, mWidth-3, mWidth-3); - canvas.drawRect(rectTouched, p); + switch(highlightType) { + case Default: + p.setColor(Color.WHITE); + break; + case Error: + p.setColor(Color.RED); + break; + case Selected: + p.setColor(Color.GREEN); + break; + case Connected: + p.setColor(Color.argb(55, 255, 255, 0)); + break; + case Highlighted: + p.setColor(Color.YELLOW); + break; + default: + p.setColor(Color.WHITE); } + + + drawBackground(canvas, 3, 3, mWidth - 3, mHeight - 3, p); + // if there is no mGameCell .. we can not retrieve the information to draw + if(mGameCell != null) { + drawValue(canvas); + } + } + + public void drawBackground(Canvas canvas, int left, int top, int right, int bottom, Paint p) { + RectF rect = new RectF(left, top, right, bottom); + canvas.drawRect(rect, p); } public void drawValue(Canvas canvas) { @@ -98,18 +127,15 @@ public class SudokuCellView extends View { p.setTypeface(Typeface.DEFAULT_BOLD); } p.setAntiAlias(true); - p.setTextSize(Math.min(mWidth * 3 / 4, mWidth * 3 / 4)); + p.setTextSize(Math.min(mHeight * 3 / 4, mHeight * 3 / 4)); p.setTextAlign(Paint.Align.CENTER); - canvas.drawText(String.valueOf(mGameCell.getValue()), mWidth/2, mWidth/2 + mWidth/4, p); - } - - public int getColumn() { - return mCol; + canvas.drawText(String.valueOf(mGameCell.getValue()), mHeight/2, mHeight/2 + mHeight/4, p); } public int getRow() { return mRow; } - - + public int getCol() { + return mCol; + } } diff --git a/app/src/main/java/tu_darmstadt/sudoku/view/SudokuFieldLayout.java b/app/src/main/java/tu_darmstadt/sudoku/view/SudokuFieldLayout.java index c3c5b83..a6de84b 100644 --- a/app/src/main/java/tu_darmstadt/sudoku/view/SudokuFieldLayout.java +++ b/app/src/main/java/tu_darmstadt/sudoku/view/SudokuFieldLayout.java @@ -5,10 +5,16 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; +import android.view.MotionEvent; import android.view.View; import android.widget.RelativeLayout; +import java.util.List; + import tu_darmstadt.sudoku.controller.GameController; +import tu_darmstadt.sudoku.game.GameCell; +import tu_darmstadt.sudoku.game.GameSettings; +import tu_darmstadt.sudoku.view.highlighting.CellHighlightTypes; /** * Created by Timm Lippert on 11.11.2015. @@ -19,6 +25,7 @@ public class SudokuFieldLayout extends RelativeLayout { private int sectionHeight; private int sectionWidth; private int gameCellWidth; + private int gameCellHeight; public SudokuCellView [][] gamecells; AttributeSet attrs; @@ -34,12 +41,33 @@ public class SudokuFieldLayout extends RelativeLayout { gameController = gc; gamecells = new SudokuCellView[gc.getSize()][gc.getSize()]; - OnClickListener listener = new OnClickListener() { + OnTouchListener listener = new OnTouchListener() { @Override - public void onClick(View v) { - if (v instanceof SudokuCellView) { - SudokuCellView view = (SudokuCellView) v; + public boolean onTouch(View v, MotionEvent event) { + if(v instanceof SudokuCellView) { + + SudokuCellView scv = ((SudokuCellView) v); + + int row = scv.getRow(); + int col = scv.getCol(); + + // Reset everything + for(int i = 0; i < gameController.getSize(); i++) { + for(int j = 0; j < gameController.getSize(); j++) { + gamecells[i][j].setHighlightType(CellHighlightTypes.Default); + } + } + // Set connected Fields + for(GameCell c : gameController.getConnectedCells(row,col, GameSettings.getHighlightConnectedRow(), GameSettings.getHighlightConnectedColumn(), GameSettings.getHighlightConnectedSection())) { + gamecells[c.getRow()][c.getCol()].setHighlightType(CellHighlightTypes.Connected); + } + // Select touched Cell + gameController.selectCell(row, col); + scv.setHighlightType(CellHighlightTypes.Selected); + + } + return false; } }; @@ -49,6 +77,7 @@ public class SudokuFieldLayout extends RelativeLayout { for (int i = 0; i < gameController.getSize(); i++) { for (int j = 0; j < gameController.getSize(); j++) { gamecells[i][j] = new SudokuCellView(getContext(), attrs); + gamecells[i][j].setOnTouchListener(listener); addView(gamecells[i][j]); } } @@ -58,19 +87,22 @@ public class SudokuFieldLayout extends RelativeLayout { public void onDraw(Canvas canvas) { super.onDraw(canvas); + if(gameController == null) return; + Paint p = new Paint(); p.setColor(Color.BLACK); p.setStrokeWidth(2); // TODO: Draw Borders - //canvas.drawLine(0, 0, 0, getHeight(), p); for(int i = 0; i <= (gameController.getSize()/sectionWidth); i++) { for(int j = -2; j < 2; j++) { canvas.drawLine((i * getWidth() / sectionWidth) + j, 0, (i * getWidth() / sectionWidth) + j, getHeight(), p); } } for(int i = 0; i <= (gameController.getSize()/sectionHeight); i++) { - canvas.drawLine(0, i*getHeight() / sectionHeight, getHeight(), i*getHeight() / sectionHeight, p); + for(int j = -2; j < 2; j++) { + canvas.drawLine(0, (i * getHeight() / sectionHeight) + j, getHeight(), (i * getHeight() / sectionHeight) + j, p); + } } } @@ -80,10 +112,11 @@ public class SudokuFieldLayout extends RelativeLayout { if(changed && gameController != null) { gameCellWidth = (Math.min(r-l, b-t)) / gameController.getSize(); + gameCellHeight = (Math.min(r-l, b-t)) / gameController.getSize(); for (int i = 0; i < gameController.getSize(); i++) { for (int j = 0; j < gameController.getSize(); j++) { - gamecells[i][j].setValues(gameCellWidth, sectionHeight, sectionWidth, gameController.getGameCell(i, j)); + gamecells[i][j].setValues(gameCellWidth, gameCellHeight, sectionHeight, sectionWidth, gameController.getGameCell(i, j)); } } } diff --git a/app/src/main/java/tu_darmstadt/sudoku/view/highlighting/CellHighlightTypes.java b/app/src/main/java/tu_darmstadt/sudoku/view/highlighting/CellHighlightTypes.java new file mode 100644 index 0000000..0fbd9fa --- /dev/null +++ b/app/src/main/java/tu_darmstadt/sudoku/view/highlighting/CellHighlightTypes.java @@ -0,0 +1,12 @@ +package tu_darmstadt.sudoku.view.highlighting; + +/** + * Created by Chris on 12.11.2015. + */ +public enum CellHighlightTypes { + Default, + Selected, + Error, + Connected, + Highlighted // Same Numbers are not connected but might be highlighted. +} diff --git a/app/src/main/res/layout/content_game_view.xml b/app/src/main/res/layout/content_game_view.xml index 597b26c..fc2461d 100644 --- a/app/src/main/res/layout/content_game_view.xml +++ b/app/src/main/res/layout/content_game_view.xml @@ -1,7 +1,8 @@ diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index a275172..60cf80b 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -1,7 +1,23 @@ + + Sudoku + + Neues Spiel Einstellungen Bestenliste Hauptmenü + Gruppe + Hilfe + Über + + + Einstellungen + Einstellungen + + + Auswahl + Werte + \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 5cf49e9..6a96cda 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -1,9 +1,9 @@ - 16dp - 16dp - 16dp + 13dp + 13dp + 13dp - 16dp + 13dp 160dp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a4fee65..0ec2a5a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,6 +1,5 @@ Sudoku - Settings Sudoku @@ -14,9 +13,11 @@ Open navigation drawer Close navigation drawer - Settings + + Settings + Settings Selection diff --git a/app/src/test/java/tu_darmstadt/sudoku/game/solver/SolverTest.java b/app/src/test/java/tu_darmstadt/sudoku/game/solver/SolverTest.java new file mode 100644 index 0000000..f2c3a46 --- /dev/null +++ b/app/src/test/java/tu_darmstadt/sudoku/game/solver/SolverTest.java @@ -0,0 +1,35 @@ +package tu_darmstadt.sudoku.game.solver; + +import org.junit.Before; +import org.junit.Test; + +import tu_darmstadt.sudoku.controller.GameController; + +/** + * Created by Chris on 12.11.2015. + */ +public class SolverTest { + + GameController controller; + + @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 }, + + { 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 }}; + } + + @Test + public void solveTest() { + } + +}