using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Windows.Controls.Primitives; namespace SudokuWeek4.Models { public partial class BoardModel { // Define an array to hold the bigCells private LargeCell[,] bigCells; // Define an array to hold the smallCells private LittleCell[,] smallCells; // Define the current X position private int currentX = 0; // Define the current Y position private int currentY = 0; // This property will get or set the cheatmode public static Boolean CheatMode { get; set; } // Define the gameFieldSize public static int GameFieldSize; // Define the gameFieldCount public static int GameFieldCount; // Define the GameField private UniformGrid _gameField = new UniformGrid(); // Define the sodukuGame (if the DLL is enabled) private Sudoku.IGame _sudokuGame; // Create a dictionary that holds the cheatDicisions private readonly Dictionary _cheatDictionary = new Dictionary(); // Define if the sudokuDLL is used private Boolean _sudokuDLL = true; // Define a gameFinished boolean private Boolean _gameFinished = false; private int _inputCount; public BoardModel() { // Just keep smiling ^_^ } // This property will get the gameField public UniformGrid GameField { get { return _gameField; } } // This method will set the cheatmode public void Cheat(Boolean cheatMode = false) { CheatMode = cheatMode; RefreshAllCells(); } // Refresh all the cells on the gameField public void RefreshAllCells() { for (int x = 0; x < GameFieldSize; x++) { for (int y = 0; y < GameFieldSize; y++) { smallCells[x, y].Refresh(); } } } public void Reset(int gameFieldSize = 3) { // Clear the gameField GameField.Children.Clear(); // Reset the inputCount _inputCount = 0; // Reset the game Finished Boolean _gameFinished = false; // Set the boardCount GameFieldCount = gameFieldSize; // Set the boardSize GameFieldSize = GameFieldCount * GameFieldCount; // Create all the gameField columns (depending on GameFieldSize) GameField.Columns = GameField.Rows = GameFieldCount; // Create all the big cells (2D array of gamefield size) bigCells = new LargeCell[GameFieldCount, GameFieldCount]; // Create the gameField for (int i = 0; i < GameFieldSize; i++) { // Create a new border Border border = new Border(); // Set the border thickness border.BorderThickness = new Thickness(1); // Set the borderBrush color border.BorderBrush = Brushes.Blue; // Add the border to the gameField GameField.Children.Add(border); // Create a bigCell LargeCell bigCell = new LargeCell(); // Add the bigCell as a child to the created border border.Child = bigCell; // Set the bigcells relative to the gameField size bigCells[i % GameFieldCount, i / GameFieldCount] = bigCell; } // Load all the small cells LoadAllSmallCells(); // Clear all the filled in values _cheatDictionary.Clear(); } // Load all the smallCells private void LoadAllSmallCells() { // Check if the selected gameMode is for 3 x 3 (if not we need to disable the sudoku DLL) if (GameFieldCount != 3) { _sudokuDLL = false; MessageBox.Show("This gamemode cannot be played with the sudoku DLL. SudokuDLL unloaded"); } // If the sudoDLL is used we need to create a game if (SudokuDLL) { try { _sudokuGame = new Sudoku.Game(); _sudokuGame.create(); Console.WriteLine("Sudoku DLL loaded successfully"); } catch (Exception ex) { Console.WriteLine("Error while loading sudoku DLL: \n\n" + ex.Message + "\n\n"); SudokuDLL = false; } } // Create the new smallCells smallCells = new LittleCell[GameFieldSize, GameFieldSize]; // Reset the current X and Y position (Selected cell) currentX = 0; currentY = 0; for (int x = 0; x < GameFieldSize; x++) { for (int y = 0; y < GameFieldSize; y++) { smallCells[x, y] = bigCells[x / GameFieldCount, y / GameFieldCount][x % GameFieldCount, y % GameFieldCount]; smallCells[x, y].X = x; smallCells[x, y].Y = y; } } // If the sudoku DLL is loaded we need to fill in the gameField if (SudokuDLL) { FillSudokuFields(); } /* // Check array contents Console.WriteLine("Soduku DLL contents: \n\n -------------------------------\n\n"); for (int x = 1; x <= GameFieldSize; x++) { for (int y = 1; y <= GameFieldSize; y++) { int sudokuValue; _sudokuGame.get(x, y, out sudokuValue); Console.Write(sudokuValue); if (sudokuValue == -1) { Console.WriteLine(); } } } */ smallCells[0, 0].Selected = true; } // This method will fill in all the sudokuFields private void FillSudokuFields() { for (int x = 0; x < GameFieldSize; x++) { for (int y = 0; y < GameFieldSize; y++) { try { int sudokuValue; _sudokuGame.get(x + 1, y + 1, out sudokuValue); // Check if the sudoku value is not an empty (0) value if (sudokuValue > 0) { // Set the specified value SetNumber(x, y, sudokuValue, false, true); _cheatDictionary[new IntegerPoint(x, y)] = sudokuValue; } } catch (Exception ex) { Console.WriteLine("Error while generating the sudoku field when using the Sudoku DLL: \n\n" + ex.Message + "\n\n"); break; } } } } // This method will solve the sudoku puzzle (partially) public void solvePuzzle(int cellsOver = 0) { for (int i = _inputCount; i < smallCells.Length - cellsOver; i++) { ShowHint(); System.Console.WriteLine(i); } } // This method will get the current clicked cell public void MouseClicked(object sender, MouseEventArgs click) { /* if (sender != null) { UniformGrid _grid = sender as UniformGrid; int _row = (int)_grid.GetValue(Grid.RowProperty); int _column = (int)_grid.GetValue(Grid.ColumnProperty); MessageBox.Show(string.Format("Grid clicked at column {0}, row {1}", _column, _row)); } */ } // This method will check what to do if a key is pressed public void KeyPressed(KeyEventArgs e) { // Check if the keys left, right, up or down are pressed if (e.Key == Key.Left || e.Key == Key.Right || e.Key == Key.Up || e.Key == Key.Down) { // Disable the current selected cell smallCells[currentX, currentY].Selected = false; // Check which key is pressed and do the appropriate action switch (e.Key) { case Key.Left: currentX = (currentX + GameFieldSize - 1) % GameFieldSize; break; case Key.Right: currentX = (currentX + 1) % GameFieldSize; break; case Key.Up: currentY = (currentY + GameFieldSize - 1) % GameFieldSize; break; case Key.Down: currentY = (currentY + 1) % GameFieldSize; break; } // Set the current (new) cell to be selected smallCells[currentX, currentY].Selected = true; } // Check if the numberkeys where pressed if ((e.Key >= Key.D1 && e.Key <= Key.D9) || (e.Key >= Key.NumPad1 && e.Key <= Key.NumPad9)) { int number = 0; if (e.Key >= Key.D1 && e.Key <= Key.D9) { number = e.Key - Key.D0; } else { number = e.Key - Key.NumPad0; } IntegerPoint cellPoint = new IntegerPoint(currentX, currentY); // Check if the cheatmode contains the key to be pressed if (_cheatDictionary.ContainsKey(cellPoint)) { // Remove the userinput at the specified location _cheatDictionary.Remove(cellPoint); } // Check if the cheatMode does not contains the pressed numberKey and if the current has a candidate that can be selected if (!_cheatDictionary.ContainsKey(cellPoint) && smallCells[currentX, currentY].CanSet(number)) { if (SetNumber(currentX, currentY, number)) { _cheatDictionary[cellPoint] = number; } } } if (e.Key == Key.Delete && !smallCells[currentX, currentY].ReadOnly) { // Add the option at the specified column foreach (IntegerPoint cellPoint in GetPointsInColumn(currentX)) { smallCells[cellPoint.X, cellPoint.Y].AddOption(smallCells[currentX, currentY].Determined); } // Add the option at the specified row foreach (IntegerPoint cellPoint in GetPointsInRow(currentY)) { smallCells[cellPoint.X, cellPoint.Y].AddOption(smallCells[currentX, currentY].Determined); } // Add the option at the specified BigCell foreach (IntegerPoint cellPoint in GetPointsInParentBigCell(currentX, currentY)) { smallCells[cellPoint.X, cellPoint.Y].AddOption(smallCells[currentX, currentY].Determined); } smallCells[currentX, currentY].RemoveNumber(smallCells[currentX, currentY].Determined); } } // Set the specified number private Boolean SetNumber(int x, int y, int number, Boolean hint = false, Boolean readOnly = false) { if (!_gameFinished) { if (number < 1 || number > GameFieldSize || smallCells[x, y].ReadOnly) { Console.WriteLine("Cannot set the value: The value is less or greater than the GameField size. (Or the cell is readOnly)\nActual Value: " + number + "\n"); return false; } // Remove the option at the specified column foreach (IntegerPoint cellPoint in GetPointsInColumn(x)) { smallCells[cellPoint.X, cellPoint.Y].RemoveOption(number); } // Remove the option at the specified row foreach (IntegerPoint cellPoint in GetPointsInRow(y)) { smallCells[cellPoint.X, cellPoint.Y].RemoveOption(number); } // Remove the option at the specified BigCell foreach (IntegerPoint cellPoint in GetPointsInParentBigCell(x, y)) { smallCells[cellPoint.X, cellPoint.Y].RemoveOption(number); } // Set the userInput on the specified cell smallCells[x, y].MakeDecision(number, hint, readOnly); _inputCount++; if (_sudokuDLL) { int canAdapt; _sudokuGame.set(x + 1, y + 1, number, out canAdapt); } if (CheatMode) { // Check which numbers are still posible to set FindCheatNumbers(GetPointsInColumn(x)); FindCheatNumbers(GetPointsInRow(y)); FindCheatNumbers(GetPointsInParentBigCell(x, y)); } // Check if we got a winner if (_inputCount == smallCells.Length) { if (CheckWinner()) { _gameFinished = true; MessageBox.Show("Game finished!"); return false; } } return true; } return false; } // Show a hint public void ShowHint() { if (_sudokuDLL) { int hintPossible, value, x, y; _sudokuGame.hint(out hintPossible, out x, out y, out value); if (hintPossible == 1) { // Todo: We need to decrease the inputCount if the hint overrides a value that was already set SetNumber(--x, --y , value, true); } } } // Save the game public void Save() { if (_sudokuDLL) { int write; _sudokuGame.write(out write); if (write == 1) { MessageBox.Show("File has been saved succesfully"); RefreshAllCells(); } } } // Load the game public void Load() { if (_sudokuDLL) { int read; _sudokuGame.read(out read); if (read == 1) { MessageBox.Show("File has been loaded succesfully"); RefreshAllCells(); } } } public Boolean CheckWinner() { int endGame; _sudokuGame.isValid(out endGame); return endGame == 1; } // Find the numbers that can be set (Cheat mode) private void FindCheatNumbers(List optionPoints) { try { Dictionary dictionaryCount = new Dictionary(); for (int i = 1; i <= GameFieldSize; i++) { dictionaryCount[i] = 0; } foreach (IntegerPoint optionPoint in optionPoints) { foreach (int option in smallCells[optionPoint.X, optionPoint.Y].Options) { dictionaryCount[option]++; } } foreach (int cell in (from keys in dictionaryCount.Keys where dictionaryCount[keys] == 1 select keys).ToArray()) { foreach (IntegerPoint cellPoint in optionPoints) { if (smallCells[cellPoint.X, cellPoint.Y].CanSet(cell)) smallCells[cellPoint.X, cellPoint.Y].SetPossible(cell); } } } catch (Exception ex) { Console.WriteLine(ex.Message); } } // Get the current points that where set in the bigCell private static List GetPointsInParentBigCell(int x, int y) { int x0 = x - x % GameFieldCount; int y0 = y - y % GameFieldCount; List cellPoints = new List(); for (int i = 0; i < GameFieldSize; i++) { cellPoints.Add(new IntegerPoint(x0 + i % GameFieldCount, y0 + i / GameFieldCount)); } return cellPoints; } // Get the current points that where set in the current row private static List GetPointsInRow(int y) { List cellPoints = new List(); for (int i = 0; i < GameFieldSize; i++) { cellPoints.Add(new IntegerPoint(i, y)); } return cellPoints; } // Create a property to check if the sudokuDLL is used public Boolean SudokuDLL { get { return _sudokuDLL; } set { _sudokuDLL = value; Reset(GameFieldCount); } } // Get the current points that where set in the current column private static List GetPointsInColumn(int x) { List cellPoints = new List(); for (int i = 0; i < GameFieldSize; i++) { cellPoints.Add(new IntegerPoint(x, i)); } return cellPoints; } } }