Value and Note Highlighting with settings done. Also you can now select values and put them in that way.

This commit is contained in:
Christopher Beckmann 2015-12-19 19:00:41 +01:00
parent f205532ed4
commit 0d4a222cfc
19 changed files with 374 additions and 467 deletions

View file

@ -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<IHighlightChangedListener> highlightListeners = new LinkedList<>();
private LinkedList<IGameSolvedListener> 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<IGameSolvedListener> 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<ITimerListener> 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<ITimerListener> 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 deleteSelectedValue() {
if(isValidCellSelected() && getSelectedValue() != 0) {
public void setNoteStatus(boolean enabled) {
noteStatus = enabled;
}
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<Integer>() {
@Override
public Integer action(GameCell gc, Integer existing) {
return (gc.getValue() == value) ? existing + 1 : existing;
}
}, 0);
}
}

View file

@ -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<GameInfoContainer> sortListByLastPlayedDate(LinkedList<GameInfoContainer> list) {

View file

@ -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<int[]> result = new LinkedList<>();
LinkedList<Integer> 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<int[][], Integer, String> {
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected String doInBackground(int[][] ... params) {
int preSaves = 5;
// init
final LinkedList<GameType> gameTypes = GameType.getValidGameTypes();
final LinkedList<GameDifficulty> gameDifficulties = GameDifficulty.getValidDifficultyList();
final LinkedList<int[]> 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<int[]> 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<int[]> 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<int[]> 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) {
}
}
}

View file

@ -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;
}

View file

@ -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() {

View file

@ -0,0 +1,8 @@
package tu_darmstadt.sudoku.game.listener;
/**
* Created by Chris on 19.12.2015.
*/
public interface IHighlightChangedListener {
public void onHighlightChanged();
}

View file

@ -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);
}
}

View file

@ -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) {

View file

@ -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<SudokuButtonType> getSpecialButtons() {
ArrayList<SudokuButtonType> result = new ArrayList<SudokuButtonType>();
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";
}

View file

@ -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<LinkedList<GameCell>>() {
@Override
public LinkedList<GameCell> action(GameCell gc, LinkedList<GameCell> existing) {
if ((gameController.getHighlightedValue() == gc.getValue() && highlightValues)
|| (gc.getNotes()[gameController.getHighlightedValue() - 1] && highlightNotes)) {
existing.add(gc);
}
return existing;
}
}, new LinkedList<GameCell>())) {
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);
}
}
}
}

View file

@ -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);
}
}
}
}

View file

@ -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; }
}

View file

@ -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++;
}
}

View file

@ -10,9 +10,8 @@
<android.support.design.widget.NavigationView android:id="@+id/nav_view"
android:layout_width="200dp" android:layout_height="match_parent"
android:layout_gravity="start|start" android:fitsSystemWindows="true"
android:layout_marginTop="?attr/actionBarSize"
android:background="@color/lightblue"
android:layout_gravity="start|start"
android:background="@color/white"
app:menu="@menu/menu_drawer" />
<!--app:headerLayout="@layout/nav_header_game_view"-->

View file

@ -212,8 +212,7 @@
<android.support.design.widget.NavigationView android:id="@+id/nav_view_main"
android:layout_width="200dp" android:layout_height="match_parent"
android:layout_gravity="start" android:fitsSystemWindows="true"
android:background="@color/lightblue"
android:layout_marginTop="?attr/actionBarSize"
android:background="@color/white"
app:menu="@menu/menu_drawer_main" />
</android.support.v4.widget.DrawerLayout>

View file

@ -58,7 +58,7 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="00:00:00"
android:text="00:00"
android:layout_weight="2"
android:id="@+id/timerView"
android:gravity="right"

View file

@ -31,10 +31,11 @@
android:columnCount="6"
android:rowCount="2"
android:alwaysDrawnWithCache="true"
android:foregroundGravity="fill_horizontal"
android:layout_marginTop="5dp">
android:foregroundGravity="fill_horizontal">
</tu_darmstadt.sudoku.ui.view.SudokuKeyboardLayout>
<tu_darmstadt.sudoku.ui.view.SudokuSpecialButtonLayout
android:id="@+id/sudokuSpecialLayout"
android:layout_width="fill_parent"

View file

@ -3,7 +3,7 @@
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimary">@color/colorPrimaryDark</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>

View file

@ -27,7 +27,7 @@
<SwitchPreference android:id="@+id/pref_highlight_notes"
android:key="pref_highlight_notes"
android:title="@string/pref_highlight_notes"
android:summary="not implemented yet"
android:summary=""
android:defaultValue="true"/>
</PreferenceCategory>
</PreferenceScreen>