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 bec9851..b529954 100644 --- a/app/src/main/java/tu_darmstadt/sudoku/controller/GameController.java +++ b/app/src/main/java/tu_darmstadt/sudoku/controller/GameController.java @@ -2,21 +2,23 @@ package tu_darmstadt.sudoku.controller; import android.content.Context; import android.content.SharedPreferences; +import android.os.Handler; import java.util.LinkedList; import java.util.List; import java.util.Timer; import java.util.TimerTask; +import tu_darmstadt.sudoku.controller.helper.GameInfoContainer; 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.controller.helper.GameInfoContainer; import tu_darmstadt.sudoku.game.GameDifficulty; import tu_darmstadt.sudoku.game.GameType; import tu_darmstadt.sudoku.game.ICellAction; import tu_darmstadt.sudoku.game.listener.IGameSolvedListener; +import tu_darmstadt.sudoku.game.listener.IHighlightChangedListener; import tu_darmstadt.sudoku.game.listener.IModelChangedListener; import tu_darmstadt.sudoku.game.listener.ITimerListener; @@ -25,48 +27,61 @@ import tu_darmstadt.sudoku.game.listener.ITimerListener; */ public class GameController implements IModelChangedListener { + // General + private SharedPreferences settings; + + // View + private Context context; + private int selectedRow = -1; + private int selectedCol = -1; + private int selectedValue = 0; + private int highlightValue = 0; + + private LinkedList highlightListeners = new LinkedList<>(); + private LinkedList solvedListeners = new LinkedList<>(); + private boolean notifiedOnSolvedListeners = false; + + // Game + private int gameID = 0; // 0 = empty id => will be assigned a free ID when saving private int size; private int sectionHeight; private int sectionWidth; - private int numbOfHints=0; + private int usedHints = 0; private GameBoard gameBoard; private int[] solution; private GameType gameType; - private int selectedRow; - private int selectedCol; - private SharedPreferences settings; - private int gameID = 0; private GameDifficulty difficulty; private CellConflictList errorList = new CellConflictList(); + + // Undo Redo private UndoRedoManager undoRedoManager; - private int selectedValue; - private LinkedList solvedListeners = new LinkedList<>(); - private boolean notifiedOnSolvedListeners = false; - private Timer timer; - private android.os.Handler handler = new android.os.Handler(); - private TimerTask timerTask; - private int time = 0; - private LinkedList timerListeners = new LinkedList<>(); - private boolean timerRunning = false; + + // Solver / Generator private QQWingController qqWingController = new QQWingController(); - private Context context; -// private Solver solver; -// private SudokuGenerator generator; - - public GameController(SharedPreferences pref, Context context) { - this(GameType.Default_9x9, pref, context); - } + // Timer + private int time = 0; + private boolean timerRunning = false; + private LinkedList timerListeners = new LinkedList<>(); + private Handler timerHandler = new Handler(); + private Timer timer = new Timer(); + private TimerTask timerTask; + private boolean noteStatus = false; + // Constructors public GameController() { this(null, null); } - + public GameController(SharedPreferences pref, Context context) { + this(GameType.Default_9x9, pref, context); + } public GameController(GameType type, SharedPreferences pref, Context context) { - setGameType(type); this.context = context; + this.gameBoard = new GameBoard(type); + + setGameType(type); setSettings(pref); - gameBoard = new GameBoard(type); + initTimer(); } @@ -156,7 +171,7 @@ public class GameController implements IModelChangedListener { // TODO test every placed value so far // and reveal the selected value. selectValue(solved[selectedRow * getSize() + selectedCol]); - numbOfHints++; + usedHints++; } private void setGameType(GameType type) { @@ -252,6 +267,20 @@ public class GameController implements IModelChangedListener { fm.saveGameState(this); } + public void deleteGame(Context context) { + if(gameID == 0) { + throw new IllegalArgumentException("GameID may not be 0."); + } + GameStateManager fm = new GameStateManager(context, settings); + fm.deleteGameStateFile(getInfoContainer()); + } + + public GameInfoContainer getInfoContainer() { + // this functionality is not needed as of yet. this is not correctly implemented + // but its sufficient to our needs + return new GameInfoContainer(gameID, difficulty, gameType, null, null, null); + } + public int getSize() { return size; } @@ -343,49 +372,99 @@ public class GameController implements IModelChangedListener { public int getSelectedCol() { return selectedCol; } + public int getSelectedCellsValue() { + return isValidCellSelected() ? getGameCell(selectedRow, selectedCol).getValue() : 0; + } + public int getSelectedValue() { - if(isValidCellSelected()){ - return getValue(getSelectedRow(),getSelectedCol()); //selectedValue; - } else return 0; + 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(selectedValue != 0) { + // we have a value selected. + // we need to set the value directly now / toggle notes. + if(noteStatus) { + toggleNote(row, col, selectedValue); + } else { + setValue(row, col, selectedValue); + } + undoRedoManager.addState(gameBoard); - if(selectedRow == row && selectedCol == col) { + } else if(selectedRow == row && selectedCol == col) { // if we select the same field 2ce -> deselect it selectedRow = -1; selectedCol = -1; + highlightValue = 0; } else { // else we set it to the new selected field selectedRow = row; selectedCol = col; + // highlight the selected value only if its not 0. + int v = getGameCell(row, col).getValue(); + if(v != 0) { + highlightValue = v; + } } + notifyHighlightChangedListeners(); + } + + public int getHighlightedValue() { + return highlightValue; + } + + public boolean isValueHighlighted() { + return highlightValue > 0 && highlightValue <= size; } public void selectValue(int value) { - if(isValidCellSelected() && getSelectedValue() != value) { - setValue(selectedRow, selectedCol, value); - // add state to undo - undoRedoManager.addState(gameBoard); + if(isValidCellSelected()) { + if(noteStatus) { + toggleNote(selectedRow, selectedCol, value); + undoRedoManager.addState(gameBoard); + + highlightValue = value; + } else { + if(getSelectedCellsValue() != value) { + setValue(selectedRow, selectedCol, value); + // add state to undo + undoRedoManager.addState(gameBoard); + + highlightValue = value; + } + } + } else { + if(value == selectedValue) { + // if the value we are selecting is the one we already have selected... deselect it + selectedValue = 0; + } else { + selectedValue = value; + highlightValue = value; + } } + notifyHighlightChangedListeners(); + } + + public void setNoteStatus(boolean enabled) { + noteStatus = enabled; } - public void deleteSelectedValue() { - if(isValidCellSelected() && getSelectedValue() != 0) { + public boolean getNoteStatus() { + return noteStatus; + } + + public void deleteSelectedCellsValue() { + if(isValidCellSelected() && getSelectedCellsValue() != 0) { deleteValue(selectedRow, selectedCol); // add state to undo undoRedoManager.addState(gameBoard); + notifyHighlightChangedListeners(); } } - public void toggleSelectedNote(int value) { + public void toggleSelectedCellsNote(int value) { if(isValidCellSelected()) { toggleNote(selectedRow, selectedCol, value); // add state to undo @@ -419,10 +498,9 @@ public class GameController implements IModelChangedListener { if(!notifiedOnSolvedListeners) { notifiedOnSolvedListeners = true; notifySolvedListeners(); - //TODO disable controls and play animation in view. onSolved method is called. } } else { - + // notifyErrorListener(); // TODO: errorList now holds all the errors // TODO: display errors .. notify some view? } @@ -437,12 +515,24 @@ public class GameController implements IModelChangedListener { } } + public void registerHighlightChangedListener(IHighlightChangedListener l) { + if(!highlightListeners.contains(l)) { + highlightListeners.add(l); + } + } + public void removeGameSolvedListener(IGameSolvedListener l) { if(solvedListeners.contains(l)) { solvedListeners.remove(l); } } + public void notifyHighlightChangedListeners() { + for(IHighlightChangedListener l : highlightListeners) { + l.onHighlightChanged(); + } + } + public void notifySolvedListeners() { for(IGameSolvedListener l : solvedListeners) { l.onSolved(); @@ -459,23 +549,22 @@ public class GameController implements IModelChangedListener { timerListeners.add(listener); } } - public int getNumbOfHints(){ - return numbOfHints; + public int getUsedHints(){ + return usedHints; } private void initTimer() { timerTask = new TimerTask() { @Override public void run() { - handler.post(new Runnable() { - @Override - public void run() { - if(timerRunning) { - notifyTimerListener(time++); + timerHandler.post(new Runnable() { + @Override + public void run() { + if(timerRunning) { + notifyTimerListener(time++); + } } - } - }); - + }); } }; timer = new Timer(); @@ -483,15 +572,12 @@ public class GameController implements IModelChangedListener { } public void startTimer() { - if(!timerRunning) { - timerRunning = true; - } + timerRunning = true; + notifyHighlightChangedListeners(); } public void pauseTimer(){ - if(timerRunning) { - timerRunning = false; - } + timerRunning = false; } public void ReDo() { @@ -534,8 +620,16 @@ public class GameController implements IModelChangedListener { } } } - return; } + public int getValueCount(final int value) { + return actionOnCells(new ICellAction() { + @Override + public Integer action(GameCell gc, Integer existing) { + return (gc.getValue() == value) ? existing + 1 : existing; + } + }, 0); + } + } diff --git a/app/src/main/java/tu_darmstadt/sudoku/controller/GameStateManager.java b/app/src/main/java/tu_darmstadt/sudoku/controller/GameStateManager.java index 6b41d41..20f2284 100644 --- a/app/src/main/java/tu_darmstadt/sudoku/controller/GameStateManager.java +++ b/app/src/main/java/tu_darmstadt/sudoku/controller/GameStateManager.java @@ -123,6 +123,11 @@ public class GameStateManager { File file = new File(dir, SAVE_PREFIX+gic.getID()+FILE_EXTENSION); file.delete(); + + SharedPreferences.Editor editor = settings.edit(); + editor.putBoolean("savesChanged", true); + editor.commit(); + } public LinkedList sortListByLastPlayedDate(LinkedList list) { diff --git a/app/src/main/java/tu_darmstadt/sudoku/controller/SaveLoadLevelManager.java b/app/src/main/java/tu_darmstadt/sudoku/controller/SaveLoadLevelManager.java deleted file mode 100644 index b7fb1e6..0000000 --- a/app/src/main/java/tu_darmstadt/sudoku/controller/SaveLoadLevelManager.java +++ /dev/null @@ -1,281 +0,0 @@ -package tu_darmstadt.sudoku.controller; - -import android.content.Context; -import android.content.SharedPreferences; -import android.os.AsyncTask; -import android.util.Log; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.LinkedList; -import java.util.List; - -import tu_darmstadt.sudoku.game.GameDifficulty; -import tu_darmstadt.sudoku.game.GameType; - -/** - * Created by Chris on 23.11.2015. - */ -public class SaveLoadLevelManager { - - Context context; - private SharedPreferences settings; - - private static SaveLoadLevelManager instance; - - private static String FILE_EXTENSION = ".txt"; - private static String LEVEL_PREFIX = "level_"; - private static String LEVELS_DIR = "level"; - private static File DIR; - - public static SaveLoadLevelManager getInstance() { - return instance; - } - public static SaveLoadLevelManager init(Context context, SharedPreferences settings) { - if(instance == null) { - instance = new SaveLoadLevelManager(context, settings); - } - return instance; - } - - private SaveLoadLevelManager(Context context, SharedPreferences settings) { - this.context = context; - this.settings = settings; - DIR = context.getDir(LEVELS_DIR, 0); - } - - public boolean isLevelLoadable(GameType type, GameDifficulty diff) { - for(File file : DIR.listFiles()) { - if (file.isFile()) { - String name = file.getName().substring(0, file.getName().lastIndexOf("_")); - - StringBuilder sb = new StringBuilder(); - sb.append(LEVEL_PREFIX); - sb.append(type.name()); - sb.append("_"); - sb.append(diff.name()); - - if(name.equals(sb.toString())) { - return true; - } - } - } - return false; - } - - public int[] loadLevel(GameType type, GameDifficulty diff) { - List result = new LinkedList<>(); - LinkedList availableFiles = new LinkedList<>(); - - // go through every file - for(File file : DIR.listFiles()) { - - // filter so we only work with actual files - if (file.isFile()) { - String name = file.getName().substring(0, file.getName().lastIndexOf("_")); - String number = file.getName().substring(file.getName().lastIndexOf("_")+1, file.getName().lastIndexOf(".")); - - StringBuilder sb = new StringBuilder(); - sb.append(LEVEL_PREFIX); - sb.append(type.name()); - sb.append("_"); - sb.append(diff.name()); - - // if file is a level for our gametype and difficulty .. load it - if(name.equals(sb.toString())) { - - // load file - byte[] bytes = new byte[(int)file.length()]; - try { - FileInputStream stream = new FileInputStream(file); - try { - stream.read(bytes); - } finally { - stream.close(); - } - } catch(IOException e) { - Log.e("File Manager", "Could not load game. IOException occured."); - } - - // start parsing - String gameString = new String(bytes); - - int[] puzzle = new int[type.getSize()*type.getSize()]; - - if(puzzle.length != gameString.length()) { - throw new IllegalArgumentException("Saved level is does not have the correct size."); - } - - for(int i = 0; i < gameString.length(); i++) { - puzzle[i] = Symbol.getValue(Symbol.SaveFormat, String.valueOf(gameString.charAt(i)))+1; - } - availableFiles.add(Integer.valueOf(number)); - result.add(puzzle); - } - } - } - - if(result.size() > 0) { - int chosen = availableFiles.get(0); - int[] resultPuzzle = result.get(0); - - StringBuilder sb = new StringBuilder(); - sb.append(LEVEL_PREFIX); - sb.append(type.name()); - sb.append("_"); - sb.append(diff.name()); - sb.append("_"); - sb.append(chosen); - sb.append(FILE_EXTENSION); - String filename = sb.toString(); - - // select and delete the file - File file = new File(DIR, filename); - file.delete(); - - // then return the puzzle to load it - return resultPuzzle; - } - - // TODO: make the UI wait. Or just generate a level now. - return null; - } - - public void checkAndRestock() { - new AsyncGenerationTask().execute(); - } - - private class AsyncGenerationTask extends AsyncTask { - @Override - protected void onPreExecute() { - super.onPreExecute(); - } - - @Override - protected String doInBackground(int[][] ... params) { - int preSaves = 5; - // init - final LinkedList gameTypes = GameType.getValidGameTypes(); - final LinkedList gameDifficulties = GameDifficulty.getValidDifficultyList(); - final LinkedList missing = new LinkedList<>(); - for(int i = 0; i < gameTypes.size(); i++) { - for(int j = 0; j < gameDifficulties.size(); j++) { - for(int k = 0; k < preSaves ; k++) { - int[] m = new int[preSaves]; - m[0] = i; // gametype - m[1] = j; // difficulty - m[2] = k; // preSaves Puzzles per difficulty and gametype - missing.add(m); - } - } - } - - LinkedList removeList = new LinkedList<>(); - // go through every file - for (File file : DIR.listFiles()) { - // filter so we only work with actual files - if (file.isFile()) { - String filename = file.getName(); - for(int i = 0; i < missing.size(); i++) { - StringBuilder sb = new StringBuilder(); - sb.append(LEVEL_PREFIX); - sb.append(gameTypes.get(missing.get(i)[0]).name()); - sb.append("_"); - sb.append(gameDifficulties.get(missing.get(i)[1]).name()); - sb.append("_"); - sb.append(missing.get(i)[2]); - sb.append(FILE_EXTENSION); - if(filename.equals(sb.toString())) { - removeList.add(missing.get(i)); - } - } - } - } - for(int[] i : removeList) { - missing.remove(i); - } - - int[][] missingArray = new int[missing.size()][3]; - missing.toArray(missingArray); - - // now generate all the missing puzzles. - int[] m; - while ((m = missing.poll()) != null) { - LinkedList deleteList = new LinkedList<>(); - final GameType gameType = gameTypes.get(m[0]); - final GameDifficulty gameDifficulty = gameDifficulties.get(m[1]); - - int[] missingNumbers = new int[preSaves]; - int c = 0; - missingNumbers[c++] = m[2]; - - for (int j = 0; j < missing.size(); j++) { - if (gameType == gameTypes.get(missing.get(j)[0]) - && gameDifficulty == gameDifficulties.get(missing.get(j)[1])) { - missingNumbers[c++] = missing.get(j)[2]; - deleteList.add(m); - } - } - - int amount = c; - QQWingController qqWingController = new QQWingController(); - LinkedList puzzleList = qqWingController.generateMultiple(gameType, gameDifficulty, amount); - - for (int p = 0; p < puzzleList.size(); p++) { - StringBuilder sb = new StringBuilder(); - sb.append(LEVEL_PREFIX); - sb.append(gameType.name()); - sb.append("_"); - sb.append(gameDifficulty.name()); - sb.append("_"); - sb.append(missingNumbers[p]); - sb.append(FILE_EXTENSION); - String filename = sb.toString(); - - - // create the file - File file = new File(DIR, filename); - - // convert the puzzle to a string - StringBuilder puzzleString = new StringBuilder(); - for (int digit : puzzleList.get(p)) { - if (digit == 0) { - puzzleString.append(0); - } else { - puzzleString.append(Symbol.getSymbol(Symbol.SaveFormat, digit - 1)); - } - } - - // save the file - try { - FileOutputStream stream = new FileOutputStream(file); - - try { - stream.write(puzzleString.toString().getBytes()); - } finally { - stream.close(); - } - } catch (IOException e) { - Log.e("File Manager", "Could not save game. IOException occured."); - } - } - for (int[] d : deleteList) { - missing.remove(d); - } - } - return null; - } - - @Override - protected void onProgressUpdate(Integer... values) { - } - - @Override - protected void onPostExecute(String result) { - } - } - -} - diff --git a/app/src/main/java/tu_darmstadt/sudoku/controller/helper/HighscoreInfoContainer.java b/app/src/main/java/tu_darmstadt/sudoku/controller/helper/HighscoreInfoContainer.java index aa27ea6..e18d468 100644 --- a/app/src/main/java/tu_darmstadt/sudoku/controller/helper/HighscoreInfoContainer.java +++ b/app/src/main/java/tu_darmstadt/sudoku/controller/helper/HighscoreInfoContainer.java @@ -26,20 +26,20 @@ public class HighscoreInfoContainer { } public HighscoreInfoContainer(GameType t, GameDifficulty diff){ type =(type == null)?t:type; - difficulty = (difficulty == null)?diff: difficulty; + difficulty = (difficulty == null) ? diff : difficulty; } public void add(GameController gc){ //add all wanted Game Stats - difficulty = (difficulty== null)?gc.getDifficulty():difficulty; - type = (type == null)?gc.getGameType():type; + difficulty = (difficulty== null) ? gc.getDifficulty() : difficulty; + type = (type == null) ? gc.getGameType() : type; time += gc.getTime(); - numberOfHintsUsed += gc.getNumbOfHints(); + numberOfHintsUsed += gc.getUsedHints(); numberOfGames++; // min time is only minTime of games without hints used - minTime = (gc.getNumbOfHints() == 0 && gc.getTime()< minTime) ? gc.getTime() : minTime; - numberOfGamesNoHints = (gc.getNumbOfHints()==0)?numberOfGamesNoHints+1:numberOfGamesNoHints; - timeNoHints = (gc.getNumbOfHints()==0)?timeNoHints+gc.getTime():timeNoHints; + minTime = (gc.getUsedHints() == 0 && gc.getTime()< minTime) ? gc.getTime() : minTime; + numberOfGamesNoHints = (gc.getUsedHints() == 0) ? numberOfGamesNoHints + 1 : numberOfGamesNoHints; + timeNoHints = (gc.getUsedHints() == 0) ? timeNoHints + gc.getTime() : timeNoHints; } diff --git a/app/src/main/java/tu_darmstadt/sudoku/game/GameCell.java b/app/src/main/java/tu_darmstadt/sudoku/game/GameCell.java index 5943ccf..2087524 100644 --- a/app/src/main/java/tu_darmstadt/sudoku/game/GameCell.java +++ b/app/src/main/java/tu_darmstadt/sudoku/game/GameCell.java @@ -46,9 +46,11 @@ public class GameCell implements Cloneable { * @param val the value to be assigned to the cell. */ public void setValue(int val) { - deleteNotes(); - value = val; - notifyListeners(); + if(!isFixed()) { + deleteNotes(); + value = val; + notifyListeners(); + } } public int getValue() { diff --git a/app/src/main/java/tu_darmstadt/sudoku/game/listener/IHighlightChangedListener.java b/app/src/main/java/tu_darmstadt/sudoku/game/listener/IHighlightChangedListener.java new file mode 100644 index 0000000..9fb9043 --- /dev/null +++ b/app/src/main/java/tu_darmstadt/sudoku/game/listener/IHighlightChangedListener.java @@ -0,0 +1,8 @@ +package tu_darmstadt.sudoku.game.listener; + +/** + * Created by Chris on 19.12.2015. + */ +public interface IHighlightChangedListener { + public void onHighlightChanged(); +} diff --git a/app/src/main/java/tu_darmstadt/sudoku/ui/GameActivity.java b/app/src/main/java/tu_darmstadt/sudoku/ui/GameActivity.java index e27363d..70907c0 100644 --- a/app/src/main/java/tu_darmstadt/sudoku/ui/GameActivity.java +++ b/app/src/main/java/tu_darmstadt/sudoku/ui/GameActivity.java @@ -42,6 +42,7 @@ public class GameActivity extends AppCompatActivity implements NavigationView.On TextView timerView; TextView viewName ; RatingBar ratingBar; + private boolean gameSolved = false; @Override protected void onCreate(Bundle savedInstanceState) { @@ -88,8 +89,7 @@ public class GameActivity extends AppCompatActivity implements NavigationView.On gameController.loadNewLevel(gameType, gameDifficulty); } - layout.setGame(gameController); - layout.setSettings(sharedPref); + layout.setSettingsAndGame(sharedPref, gameController); //set KeyBoard keyboard = (SudokuKeyboardLayout) findViewById(R.id.sudokuKeyboardLayout); @@ -143,13 +143,17 @@ public class GameActivity extends AppCompatActivity implements NavigationView.On @Override public void onPause(){ super.onPause(); - gameController.saveGame(this); - gameController.pauseTimer(); + if(!gameSolved) { + gameController.saveGame(this); + gameController.pauseTimer(); + } } @Override public void onResume(){ super.onResume(); - gameController.startTimer(); + if(!gameSolved) { + gameController.startTimer(); + } } @@ -228,21 +232,30 @@ public class GameActivity extends AppCompatActivity implements NavigationView.On @Override public void onSolved() { + gameSolved = true; + + gameController.pauseTimer(); + gameController.deleteGame(this); + Toast t = Toast.makeText(this,"Congratulations you have solved the puzzle!", Toast.LENGTH_SHORT); t.show(); + SaveLoadStatistics s = new SaveLoadStatistics(this); s.saveGameStats(gameController); - DialogWinScreen win = new DialogWinScreen(); - win.setProps(gameController); + FragmentManager fr = getSupportFragmentManager(); + DialogWinScreen win = new DialogWinScreen(); + win.setProps(gameController, this); win.show(fr, "win_screen_layout"); - // TODO: WE WON.. do something awesome :) - gameController.pauseTimer(); + keyboard.setButtonsEnabled(false); + specialButtonLayout.setButtonsEnabled(false); } @Override public void onTick(int time) { + if(gameSolved) return; + //do something not so awesome int seconds = time % 60; int minutes = ((time -seconds)/60)%60 ; @@ -252,5 +265,8 @@ public class GameActivity extends AppCompatActivity implements NavigationView.On m = (minutes< 10)? "0"+String.valueOf(minutes):String.valueOf(minutes); h = (hours< 10)? "0"+String.valueOf(hours):String.valueOf(hours); timerView.setText(h + ":" + m + ":" + s); + + // save time + gameController.saveGame(this); } } diff --git a/app/src/main/java/tu_darmstadt/sudoku/ui/view/DialogWinScreen.java b/app/src/main/java/tu_darmstadt/sudoku/ui/view/DialogWinScreen.java index 91f595d..a112854 100644 --- a/app/src/main/java/tu_darmstadt/sudoku/ui/view/DialogWinScreen.java +++ b/app/src/main/java/tu_darmstadt/sudoku/ui/view/DialogWinScreen.java @@ -14,6 +14,9 @@ import android.view.animation.RotateAnimation; import android.widget.ImageView; import tu_darmstadt.sudoku.controller.GameController; +import tu_darmstadt.sudoku.game.GameDifficulty; +import tu_darmstadt.sudoku.game.GameType; +import tu_darmstadt.sudoku.ui.GameActivity; /** * Created by TMZ_LToP on 11.12.2015. @@ -21,17 +24,26 @@ import tu_darmstadt.sudoku.controller.GameController; public class DialogWinScreen extends android.support.v4.app.DialogFragment { - ImageView upperView, lowerView; + private ImageView upperView, lowerView; + private int time = 0; + private int hints = 0; + private GameDifficulty difficulty = GameDifficulty.Unspecified; + private GameType gameType = GameType.Unspecified; + private GameController gameController = null; + private GameActivity gameActivity = null; public DialogWinScreen(){ } - public void setProps(GameController gc){ - - //no second Conjstrutor with argument allowed - //save everything that should be sown in winscreeen and set in the text etc - + public void setProps(GameController gc, GameActivity a){ + gameActivity = a; + gameController = gc; + gameType = gc.getGameType(); + difficulty = gc.getDifficulty(); + hints = gc.getUsedHints(); + time = gc.getTime(); } + @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { diff --git a/app/src/main/java/tu_darmstadt/sudoku/ui/view/SudokuButtonType.java b/app/src/main/java/tu_darmstadt/sudoku/ui/view/SudokuButtonType.java index 4c51bb1..173057c 100644 --- a/app/src/main/java/tu_darmstadt/sudoku/ui/view/SudokuButtonType.java +++ b/app/src/main/java/tu_darmstadt/sudoku/ui/view/SudokuButtonType.java @@ -16,7 +16,7 @@ public enum SudokuButtonType { Undo(R.drawable.ic_undo_black_48dp), Hint(R.drawable.ic_lightbulb_outline_black_48dp), NoteToggle(R.drawable.ic_create_black_48dp), - NumberOrCellFirst(R.drawable.ic_accessibility_black_48dp),//placeholder + Spacer(R.drawable.ic_accessibility_black_48dp),//placeholder Delete(R.drawable.ic_delete_black_48dp), Reset(R.drawable.ic_settings_backup_restore_black_48dp); @@ -32,12 +32,12 @@ public enum SudokuButtonType { public static List getSpecialButtons() { ArrayList result = new ArrayList(); - result.add(Do); result.add(Undo); + result.add(Do); result.add(Hint); - result.add(NoteToggle); - result.add(NumberOrCellFirst); + //result.add(Spacer); result.add(Delete); + result.add(NoteToggle); return result; } public static String getName(SudokuButtonType type) { @@ -46,7 +46,7 @@ public enum SudokuButtonType { case Undo: return "Un"; case Hint: return "Hnt"; case NoteToggle: return "On"; - case NumberOrCellFirst: return "Cel"; + case Spacer: return ""; case Delete: return "Del"; default:return "NotSet"; } diff --git a/app/src/main/java/tu_darmstadt/sudoku/ui/view/SudokuFieldLayout.java b/app/src/main/java/tu_darmstadt/sudoku/ui/view/SudokuFieldLayout.java index 9c6ace1..7795df5 100644 --- a/app/src/main/java/tu_darmstadt/sudoku/ui/view/SudokuFieldLayout.java +++ b/app/src/main/java/tu_darmstadt/sudoku/ui/view/SudokuFieldLayout.java @@ -5,18 +5,23 @@ import android.content.SharedPreferences; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; +import android.graphics.Point; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.widget.RelativeLayout; +import java.util.LinkedList; + import tu_darmstadt.sudoku.controller.GameController; import tu_darmstadt.sudoku.game.GameCell; +import tu_darmstadt.sudoku.game.ICellAction; +import tu_darmstadt.sudoku.game.listener.IHighlightChangedListener; /** * Created by Timm Lippert on 11.11.2015. */ -public class SudokuFieldLayout extends RelativeLayout { +public class SudokuFieldLayout extends RelativeLayout implements IHighlightChangedListener { private GameController gameController; private int sectionHeight; @@ -25,6 +30,8 @@ public class SudokuFieldLayout extends RelativeLayout { private int gameCellHeight; private SharedPreferences settings; + private Paint p = new Paint(); + public SudokuCellView [][] gamecells; AttributeSet attrs; @@ -34,13 +41,15 @@ public class SudokuFieldLayout extends RelativeLayout { setBackgroundColor(Color.argb(255, 200, 200, 200)); } - public void setSettings(SharedPreferences sharedPref) { - settings = sharedPref; - } + public void setSettingsAndGame(SharedPreferences sharedPref, GameController gc) { - public void setGame(GameController gc) { + if (sharedPref == null) throw new IllegalArgumentException("SharedPreferences may not be null."); if (gc == null) throw new IllegalArgumentException("GameController may not be null."); + + settings = sharedPref; gameController = gc; + gameController.registerHighlightChangedListener(this); + gamecells = new SudokuCellView[gc.getSize()][gc.getSize()]; OnTouchListener listener = new OnTouchListener() { @@ -54,36 +63,6 @@ public class SudokuFieldLayout extends RelativeLayout { int col = scv.getCol(); gameController.selectCell(row, col); - row = gameController.getSelectedRow(); - col = gameController.getSelectedCol(); - - // Reset everything - for(int i = 0; i < gameController.getSize(); i++) { - for(int j = 0; j < gameController.getSize(); j++) { - gamecells[i][j].setHighlightType(CellHighlightTypes.Default); - } - } - - if(row == -1 || col == -1) { - // we clicked on the same cell 2 times. - // means it got deselected and we dont highlight any cells. - return false; - } - // Set connected Fields - if(gameController.isValidCellSelected()) { - //String syncConnPref = sharedPref.getString(SettingsActivity., ""); - boolean highlightConnectedRow = settings.getBoolean("pref_highlight_rows", true); - boolean highlightConnectedColumn = settings.getBoolean("pref_highlight_cols", true); - boolean highlightConnectedSection = settings.getBoolean("pref_highlight_secs", true); - - for (GameCell c : gameController.getConnectedCells(row, col, highlightConnectedRow, highlightConnectedColumn, highlightConnectedSection)) { - gamecells[c.getRow()][c.getCol()].setHighlightType(CellHighlightTypes.Connected); - } - // Select touched Cell - scv.setHighlightType(CellHighlightTypes.Selected); - } else { - scv.setHighlightType(CellHighlightTypes.Value_Highlighted_Selected); - } } return false; } @@ -107,7 +86,6 @@ public class SudokuFieldLayout extends RelativeLayout { if(gameController == null) return; - Paint p = new Paint(); p.setColor(Color.BLACK); p.setStrokeWidth(2); @@ -141,4 +119,58 @@ public class SudokuFieldLayout extends RelativeLayout { } } + @Override + public void onHighlightChanged() { + + final int row = gameController.getSelectedRow(); + final int col = gameController.getSelectedCol(); + + // 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 + if(gameController.isValidCellSelected()) { + //String syncConnPref = sharedPref.getString(SettingsActivity., ""); + final boolean highlightConnectedRow = settings.getBoolean("pref_highlight_rows", true); + final boolean highlightConnectedColumn = settings.getBoolean("pref_highlight_cols", true); + final boolean highlightConnectedSection = settings.getBoolean("pref_highlight_secs", true); + + for (GameCell c : gameController.getConnectedCells(row, col, highlightConnectedRow, highlightConnectedColumn, highlightConnectedSection)) { + gamecells[c.getRow()][c.getCol()].setHighlightType(CellHighlightTypes.Connected); + } + } + + // highlight values + final boolean highlightValues = settings.getBoolean("pref_highlight_vals", true); + final boolean highlightNotes = settings.getBoolean("pref_highlight_notes", true); + + if(gameController.isValueHighlighted()) { + for(GameCell c : gameController.actionOnCells(new ICellAction>() { + @Override + public LinkedList action(GameCell gc, LinkedList existing) { + if ((gameController.getHighlightedValue() == gc.getValue() && highlightValues) + || (gc.getNotes()[gameController.getHighlightedValue() - 1] && highlightNotes)) { + existing.add(gc); + } + return existing; + } + }, new LinkedList())) { + gamecells[c.getRow()][c.getCol()].setHighlightType(CellHighlightTypes.Value_Highlighted); + } + } + + // Highlight selected/ current cell either green or red + if(row != -1 && col != -1) { + GameCell gc = gameController.getGameCell(row, col); + if (gc.isFixed()) { + gamecells[gc.getRow()][gc.getCol()].setHighlightType(CellHighlightTypes.Error); + } else { + gamecells[gc.getRow()][gc.getCol()].setHighlightType(CellHighlightTypes.Selected); + } + } + } } diff --git a/app/src/main/java/tu_darmstadt/sudoku/ui/view/SudokuKeyboardLayout.java b/app/src/main/java/tu_darmstadt/sudoku/ui/view/SudokuKeyboardLayout.java index 93b79d5..becbaf0 100644 --- a/app/src/main/java/tu_darmstadt/sudoku/ui/view/SudokuKeyboardLayout.java +++ b/app/src/main/java/tu_darmstadt/sudoku/ui/view/SudokuKeyboardLayout.java @@ -6,22 +6,21 @@ import android.util.AttributeSet; import android.util.TypedValue; import android.view.View; import android.widget.GridLayout; -import android.support.v7.widget.GridLayoutManager; import tu_darmstadt.sudoku.controller.GameController; import tu_darmstadt.sudoku.controller.Symbol; +import tu_darmstadt.sudoku.game.listener.IHighlightChangedListener; /** * Created by TMZ_LToP on 12.11.2015. */ -public class SudokuKeyboardLayout extends GridLayout { +public class SudokuKeyboardLayout extends GridLayout implements IHighlightChangedListener { AttributeSet attrs; SudokuButton [] buttons; GameController gameController; - boolean notesEnabled=false; Symbol symbolsToUse = Symbol.Default; float normalTextSize = 0; @@ -30,26 +29,21 @@ public class SudokuKeyboardLayout extends GridLayout { public void onClick(View v) { if(v instanceof SudokuButton) { SudokuButton btn = (SudokuButton)v; - if(notesEnabled) { - gameController.toggleSelectedNote(btn.getValue()); - } else { - gameController.selectValue(btn.getValue()); - } + + gameController.selectValue(btn.getValue()); + gameController.saveGame(getContext()); } } }; - - public SudokuKeyboardLayout(Context context, AttributeSet attrs) { super(context, attrs); this.attrs = attrs; } - public void setKeyBoard(int size,int width, int height) { LayoutParams p ; buttons = new SudokuButton[size]; @@ -69,10 +63,8 @@ public class SudokuKeyboardLayout extends GridLayout { p = (new LayoutParams(rowSpec,colSpec)); - - //p = new LayoutParams(rowSpec,colSpec); - p.setMargins((i == 0)?0:5,5,5,5); + p.setMargins((i == 0) ? 0 : 5,5,5,5); p.width= (width-(int)((getResources().getDimension(R.dimen.activity_horizontal_margin))*2))/realSize; p.width= p.width-10; p.setGravity(LayoutParams.WRAP_CONTENT); @@ -91,15 +83,24 @@ public class SudokuKeyboardLayout extends GridLayout { } } - public void setGameController(GameController gc){ - gameController=gc; - + public void setButtonsEnabled(boolean enabled) { + for(SudokuButton b : buttons) { + b.setEnabled(enabled); + } } - public void toggleNotesEnabled() { - notesEnabled = !notesEnabled; + public void setGameController(GameController gc){ + if(gc == null) { + throw new IllegalArgumentException("GameController may not be null."); + } + + gameController = gc; + gameController.registerHighlightChangedListener(this); + } + + public void updateNotesEnabled() { if (normalTextSize == 0) {normalTextSize = buttons[0].getTextSize();} - if(notesEnabled) { + if(gameController.getNoteStatus()) { setTextSize(normalTextSize*0.6f); }else { setTextSize(normalTextSize); @@ -120,4 +121,21 @@ public class SudokuKeyboardLayout extends GridLayout { super.onDraw(canvas); } + + @Override + public void onHighlightChanged() { + for(SudokuButton i_btn : buttons) { + i_btn.setBackgroundResource(R.drawable.mnenomic_numpad_button); + + // Highlight Yellow if we are done with that number + if(gameController.getValueCount(i_btn.getValue()) == gameController.getSize()) { + i_btn.setBackgroundResource(R.drawable.numpad_highlighted_three); + } + + if(gameController.getSelectedValue() == i_btn.getValue()) { + // highlight button to indicate that the value is selected + i_btn.setBackgroundResource(R.drawable.numpad_highlighted); + } + } + } } diff --git a/app/src/main/java/tu_darmstadt/sudoku/ui/view/SudokuSpecialButton.java b/app/src/main/java/tu_darmstadt/sudoku/ui/view/SudokuSpecialButton.java index b490de3..e4c0498 100644 --- a/app/src/main/java/tu_darmstadt/sudoku/ui/view/SudokuSpecialButton.java +++ b/app/src/main/java/tu_darmstadt/sudoku/ui/view/SudokuSpecialButton.java @@ -1,13 +1,14 @@ package tu_darmstadt.sudoku.ui.view; import android.content.Context; +import android.graphics.Canvas; import android.util.AttributeSet; import android.widget.ImageButton; /** * Created by TMZ_LToP on 07.12.2015. */ -public class SudokuSpecialButton extends ImageButton{ +public class SudokuSpecialButton extends ImageButton { private int value = -1; private SudokuButtonType type = SudokuButtonType.Unspecified; @@ -19,4 +20,5 @@ public class SudokuSpecialButton extends ImageButton{ public void setType(SudokuButtonType type) { this.type = type; } public int getValue () { return value; } public SudokuButtonType getType() { return type; } + } diff --git a/app/src/main/java/tu_darmstadt/sudoku/ui/view/SudokuSpecialButtonLayout.java b/app/src/main/java/tu_darmstadt/sudoku/ui/view/SudokuSpecialButtonLayout.java index c4df777..d448775 100644 --- a/app/src/main/java/tu_darmstadt/sudoku/ui/view/SudokuSpecialButtonLayout.java +++ b/app/src/main/java/tu_darmstadt/sudoku/ui/view/SudokuSpecialButtonLayout.java @@ -31,39 +31,28 @@ public class SudokuSpecialButtonLayout extends LinearLayout { if(v instanceof SudokuSpecialButton) { SudokuSpecialButton btn = (SudokuSpecialButton)v; - int row = gameController.getSelectedRow(); - int col = gameController.getSelectedCol(); + //int row = gameController.getSelectedRow(); + //int col = gameController.getSelectedCol(); switch(btn.getType()) { case Delete: - gameController.deleteSelectedValue(); + gameController.deleteSelectedCellsValue(); break; case NoteToggle: - //btn.setText(keyboard.notesEnabled ? "ON" : "OFF"); - //Animation rotates whole button - /*AnimationSet aniset = new AnimationSet(true); - aniset.setInterpolator(new DecelerateInterpolator()); - aniset.setFillAfter(true); - aniset.setFillEnabled(true); + // rotates the Drawable + gameController.setNoteStatus(!gameController.getNoteStatus()); + keyboard.updateNotesEnabled(); - RotateAnimation rotate = new RotateAnimation(0.0f,(keyboard.notesEnabled ? 90.0f:0.0f), - RotateAnimation.RELATIVE_TO_SELF,0.5f, - Animation.RELATIVE_TO_SELF,0.5f); - rotate.setDuration(1500); - rotate.setFillAfter(true); - aniset.addAnimation(rotate); - - btn.startAnimation(aniset);*/ - - // rotates now only the Drawable bitMap = BitmapFactory.decodeResource(getResources(), btn.getType().getResID()); bitResult = Bitmap.createBitmap(bitMap.getWidth(), bitMap.getHeight(), Bitmap.Config.ARGB_8888); canvas = new Canvas(bitResult); - canvas.rotate(keyboard.notesEnabled?0.0f:90.0f,bitMap.getWidth()/2,bitMap.getHeight()/2); - canvas.drawBitmap(bitMap,0,0,null); + canvas.rotate(gameController.getNoteStatus() ? 45.0f : 0.0f, bitMap.getWidth()/2, bitMap.getHeight()/2); + canvas.drawBitmap(bitMap, 0, 0, null); + btn.setImageBitmap(bitResult); - keyboard.toggleNotesEnabled(); + btn.setBackgroundResource(gameController.getNoteStatus() ? R.drawable.numpad_highlighted_three : R.drawable.numpad_highlighted_four); + break; case Do: gameController.ReDo(); @@ -76,11 +65,10 @@ public class SudokuSpecialButtonLayout extends LinearLayout { case Hint: if(gameController.isValidCellSelected()) { gameController.hint(); + } else { + // TODO: Display a Toast that explains how to use the Hint function. } break; - case NumberOrCellFirst: - // TODO: not implemented - break; default: break; } @@ -94,8 +82,13 @@ public class SudokuSpecialButtonLayout extends LinearLayout { setWeightSum(fixedButtonsCount); } + public void setButtonsEnabled(boolean enabled) { + for(SudokuSpecialButton b : fixedButtons) { + b.setEnabled(enabled); + } + } - public void setButtons(int width, GameController gc,SudokuKeyboardLayout key) { + public void setButtons(int width, GameController gc, SudokuKeyboardLayout key) { keyboard=key; gameController = gc; fixedButtons = new SudokuSpecialButton[fixedButtonsCount]; @@ -109,6 +102,15 @@ public class SudokuSpecialButtonLayout extends LinearLayout { //int width2 =width/(fixedButtonsCount); //p.width= width2-15; + if(t == SudokuButtonType.Spacer) { + fixedButtons[i].setVisibility(View.INVISIBLE); + } + /*if(t == SudokuButtonType.Do && !gameController.isRedoAvailable()) { + fixedButtons[i].setEnabled(false); + } + if(t == SudokuButtonType.Undo && !gameController.isUndoAvailable()) { + fixedButtons[i].setEnabled(false); + }*/ fixedButtons[i].setLayoutParams(p); fixedButtons[i].setType(t); fixedButtons[i].setImageDrawable(getResources().getDrawable(t.getResID())); @@ -119,8 +121,6 @@ public class SudokuSpecialButtonLayout extends LinearLayout { fixedButtons[i].setBackgroundResource(R.drawable.numpad_highlighted_four); addView(fixedButtons[i]); i++; - - } } diff --git a/app/src/main/res/layout/activity_game_view.xml b/app/src/main/res/layout/activity_game_view.xml index 64bd721..b68c58c 100644 --- a/app/src/main/res/layout/activity_game_view.xml +++ b/app/src/main/res/layout/activity_game_view.xml @@ -10,9 +10,8 @@ diff --git a/app/src/main/res/layout/activity_main_menu.xml b/app/src/main/res/layout/activity_main_menu.xml index d574b2a..26e6430 100644 --- a/app/src/main/res/layout/activity_main_menu.xml +++ b/app/src/main/res/layout/activity_main_menu.xml @@ -212,8 +212,7 @@ \ No newline at end of file diff --git a/app/src/main/res/layout/app_bar_game_view.xml b/app/src/main/res/layout/app_bar_game_view.xml index fa6e54a..2626479 100644 --- a/app/src/main/res/layout/app_bar_game_view.xml +++ b/app/src/main/res/layout/app_bar_game_view.xml @@ -58,7 +58,7 @@ + android:foregroundGravity="fill_horizontal"> + + diff --git a/app/src/main/res/xml/pref_highlighting.xml b/app/src/main/res/xml/pref_highlighting.xml index 14f8851..ca3301b 100644 --- a/app/src/main/res/xml/pref_highlighting.xml +++ b/app/src/main/res/xml/pref_highlighting.xml @@ -27,7 +27,7 @@ \ No newline at end of file