/// <summary> /// FillSingleChoices iterates through empty cells. For any empty cell /// with only one possible value, it fills in that value. /// </summary> /// <param name="grid">Current state of grid</param> private void FillSingleChoices(SquigglyGrid grid) { bool anyChanges = false; //Set if cell value set int numChoices; //Number of choices found do //While changes have been made AND grid is not solved { anyChanges = false; for (int i = 0; i < 9; i++) //Iterate through every row { for (int j = 0; j < 9; j++) //Iterate through every column { if (grid.Grid[i, j] == 0) { //Get number of choices available in grid[i, j] numChoices = ListPossible(i, j, grid); if (numChoices == 1) //If only one choice set value { grid.UserSetCell(i, j, FirstTrue()); //Changes made, anyChanges = true anyChanges = (grid.Grid[i, j] != 0); } } } } } while (anyChanges == true && !IsSolved(grid)); }
/// <summary> /// FindFewestChoices finds the first cell having the smallest number /// of available choices, and sets the row and column of that cell for /// use in SolveGrid /// </summary> /// <param name="grid">Current state of the grid</param> /// <param name="r">OUTPUT sets r for use in caller</param> /// <param name="c">OUTPUT sets c for use in caller</param> /// <param name="numChoices">OUTPUT sets var for use in caller</param> /// <returns>Returns true if valid cell found, false if not</returns> private bool FindFewestChoices(SquigglyGrid grid, out int r, out int c, out int numChoices) { bool[] minList = new bool[10]; int numCh, minR, minC, minChoice, i, j; bool bad, result; minChoice = 10; minR = 0; minC = 0; for (i = 1; i < 10; i++) //Initialize minList to FALSE { minList[i] = false; } bad = false; i = 0; while (!bad && i < 9) //While not a bad solutn and trying valid row { j = 0; while (!bad && j < 9) //not a bad solutn and trying valid column { if (grid.Grid[i, j] == 0) { numCh = ListPossible(i, j, grid); //Get # of choices if (numCh == 0) //If no choices found, bad solution { bad = true; } else //If not bad solutn... { if (numCh < minChoice) //If less than current min { minChoice = numCh; //Set new min value list.CopyTo(minList, 0); //Save list of possible minR = i; //set row of cell with least minC = j; //set col of cell with least } } } j++; } i++; } if (bad || minChoice == 10) //If bad solutn or minChoice never set { result = false; //No fewest possible choices r = 0; c = 0; numChoices = 0; } else { result = true; //Valid cell found, return information to caller r = minR; c = minC; numChoices = minChoice; minList.CopyTo(list, 0); } return(result); }
/// This constructs a squiggly generator class. public SquigglyGenerator(int[,] solution, int[,] scheme, Difficulty difficultyIn) { this.scheme = scheme; this.SolutionGrid = new SquigglyGrid(); this.SolutionGrid.Grid = solution; squigglySolver = new SquigglySolver(scheme); difficulty = difficultyIn; }
/// This constructs a squiggly generator class. public SquigglyGenerator(int[,] solution, int[,] scheme,Difficulty difficultyIn) { this.scheme = scheme; this.SolutionGrid = new SquigglyGrid(); this.SolutionGrid.Grid = solution; squigglySolver = new SquigglySolver(scheme); difficulty = difficultyIn; }
/// <summary> /// IsPossible returns true if IsInRow, IsInCol & IsIn3x3 return false /// </summary> /// <param name="g">Current state of the grid</param> /// <param name="row">row of target cell</param> /// <param name="col">column of target cell</param> /// <param name="value">value being sought</param> /// <returns>True if value can occupy cell at [row, col]</returns> private bool IsPossible(SquigglyGrid g, int row, int col, int value) { //Return true if value can go into [row, col] now bool result; result = (!IsInRow(g, row, value) && !IsInCol(g, col, value) && !IsIn3X3(g, row, col, value)); return(result); }
/// <summary> /// IsInRow checks if given value occurs in the given row /// </summary> /// <param name="grid">Current state of squiggly grid</param> /// <param name="row">Row to check</param> /// <param name="value">Value to look for</param> /// <returns></returns> private bool IsInRow(SquigglyGrid grid, int row, int value) { bool result = false; for (int i = 0; i < 9; i++) //Iterate through row { //check if cell holds value being sought result = result || (Math.Abs(grid.Grid[row, i]) == value); } return(result); }
/// <summary> /// IsInColumn checks if given value occurs in the given row. /// </summary> /// <param name="grid">Current state of the grid</param> /// <param name="col">Column being check</param> /// <param name="value">Value being sought</param> /// <returns></returns> private bool IsInCol(SquigglyGrid grid, int col, int value) { bool result = false; for (int i = 0; i < 9; i++) //Iterate through column { //check if cell holds value being sought result = result || (Math.Abs(grid.Grid[i, col]) == value); } return(result); }
// Call SolveGrid to solve squigglygrid //Store solved gamegrid as the correct solution in solutiongrid public SquigglyGrid Blanker(SquigglyGrid solvedGrid) { //enable blanking of squares based on difficulty SquigglyGrid tempGrid; SquigglyGrid saveCopy; //temporary grids to save between tests bool unique = true; //flag for if blanked form has unique soln int totalBlanks = 0; //count of current blanks int tries = 0; //count of tries to blank appropriately int desiredBlanks; //amount of blanks desired via difficulty int symmetry = 0; //symmetry type tempGrid = (SquigglyGrid)solvedGrid.Clone(); //cloned input grid (no damage) Random rnd = new Random(); //allow for random number generation switch (difficulty) //set desiredBlanks via chosen difficulty { case Difficulty.Easy: //easy difficulty desiredBlanks = 2; break; case Difficulty.Medium: //medium difficulty desiredBlanks = 50; break; case Difficulty.Hard: //hard difficulty desiredBlanks = 60; break; default: //easy difficulty desiredBlanks = 40; break; } symmetry = rnd.Next(0, 2); //Randomly select symmetry do { //call RandomlyBlank() to blank random squares symmetrically saveCopy = (SquigglyGrid)tempGrid.Clone(); // in case undo needed tempGrid = RandomlyBlank(tempGrid, symmetry, ref totalBlanks); //blanks 1 or 2 squares according to symmetry chosen squigglySolver = new SquigglySolver(scheme); unique = squigglySolver.SolveGrid((SquigglyGrid)tempGrid.Clone(), false); // will it solve uniquely? if (!unique) { tempGrid = (SquigglyGrid)saveCopy.Clone(); tries++; } } while ((totalBlanks < desiredBlanks) && (tries < 1000)); solvedGrid = tempGrid; solvedGrid.Finish(); return(solvedGrid); }
/// <summary> /// This clones the object. /// </summary> /// <returns>A clone of itself.</returns> public object Clone() { //enable cloning for safe copying of the object SquigglyGrid p = new SquigglyGrid(); for (int i = 0; i < Max; i++) { for (int j = 0; j < Max; j++) { p.InitSetCell(i, j, Grid[i, j]); } } return p; }
public SquigglyGrid RandomlyBlank(SquigglyGrid tempGrid, int sym, ref int blankCount) { //blank one or two squares(depending on if on center line) randomly Random rnd = new Random(); //allow random number generation int row = rnd.Next(0, 8); //choose randomly the row int column = rnd.Next(0, 8); //and column of cell to blank while (tempGrid.Grid[row, column] == 0) //don't blank a blank cell { row = rnd.Next(0, 8); column = rnd.Next(0, 8); } tempGrid.InitSetCell(row, column, 0); //clear chosen cell blankCount++; //increment the count of blanks switch (sym) { //based on symmetry, blank a second cell case 0: //vertical symmetry if (tempGrid.Grid[row, 8 - column] != 0) //if not already blanked { blankCount++; //increment blank counter } tempGrid.InitSetCell(row, 8 - column, 0); //blank opposite cell break; case 1: //horizontal symmetry if (tempGrid.Grid[8 - row, column] != 0) { blankCount++; } tempGrid.InitSetCell(8 - row, column, 0); break; case 2: //diagonal symmetry if (tempGrid.Grid[column, row] != 0) { blankCount++; } tempGrid.InitSetCell(column, row, 0); break; default: //diagonal symmetry if (tempGrid.Grid[row, 8 - column] != 0) { blankCount++; } tempGrid.InitSetCell(column, row, 0); break; } return(tempGrid); }
/// <summary> /// This clones the object. /// </summary> /// <returns>A clone of itself.</returns> public object Clone() { //enable cloning for safe copying of the object SquigglyGrid p = new SquigglyGrid(); for (int i = 0; i < Max; i++) { for (int j = 0; j < Max; j++) { p.InitSetCell(i, j, Grid[i, j]); } } return(p); }
// Call SolveGrid to solve squigglygrid //Store solved gamegrid as the correct solution in solutiongrid public SquigglyGrid Blanker(SquigglyGrid solvedGrid) { //enable blanking of squares based on difficulty SquigglyGrid tempGrid; SquigglyGrid saveCopy; //temporary grids to save between tests bool unique = true; //flag for if blanked form has unique soln int totalBlanks = 0; //count of current blanks int tries = 0; //count of tries to blank appropriately int desiredBlanks; //amount of blanks desired via difficulty int symmetry = 0; //symmetry type tempGrid = (SquigglyGrid)solvedGrid.Clone(); //cloned input grid (no damage) Random rnd = new Random(); //allow for random number generation switch (difficulty) //set desiredBlanks via chosen difficulty { case Difficulty.Easy: //easy difficulty desiredBlanks = 2; break; case Difficulty.Medium: //medium difficulty desiredBlanks = 50; break; case Difficulty.Hard: //hard difficulty desiredBlanks = 60; break; default: //easy difficulty desiredBlanks = 40; break; } symmetry = rnd.Next(0, 2); //Randomly select symmetry do { //call RandomlyBlank() to blank random squares symmetrically saveCopy = (SquigglyGrid)tempGrid.Clone(); // in case undo needed tempGrid = RandomlyBlank(tempGrid, symmetry, ref totalBlanks); //blanks 1 or 2 squares according to symmetry chosen squigglySolver = new SquigglySolver(scheme); unique = squigglySolver.SolveGrid((SquigglyGrid)tempGrid.Clone(), false); // will it solve uniquely? if (!unique) { tempGrid = (SquigglyGrid)saveCopy.Clone(); tries++; } } while ((totalBlanks < desiredBlanks) && (tries < 1000)); solvedGrid = tempGrid; solvedGrid.Finish(); return solvedGrid; }
/// <summary> /// IsIn3x3 determines which 3x3 grid cell is in using GroupNum. /// Values are: /// [0, 0] [0, 1] [0, 2] /// [1, 0] [1, 1] [1, 2] /// [2, 0] [2, 1] [2, 2] /// And then checks if given value occurs in the 3x3 grid. /// </summary> /// <param name="g">Current state of the grid</param> /// <param name="row">Row of cell being checked</param> /// <param name="col">Column of cell being checked</param> /// <param name="value">Value being sought</param> /// <returns>True if Value is found, false if not</returns> private bool IsIn3X3(SquigglyGrid g, int row, int col, int value) { int groupnum = scheme[row, col]; for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { if (scheme[i, j] == groupnum && g.Grid[i, j] == value) { return(true); } } } return(false); }
public SquigglyGrid InitGrid() { //Randomly fill in the first row and column of squigglygrid SquigglyGrid tempGrid = new SquigglyGrid { }; //temporary grid to assign values into int row = 0; //variable for navigating 'rows' int col = 0; //variable for navigating 'columns' int newVal; //value to place into grid //bool solved; List <int> valueSet = new List <int>(Enumerable.Range(1, 9)); //range of numbers that can be added to the grid List <int> valueSet2 = new List <int>(); //placeholder values in column 0 Random rnd = new Random(); //random variable for choosing random number int randIndex = 0; //index in valueSet/valueSet2 that is accessed randIndex = rnd.Next(0, 8); //get a random number and place in grid(0,0) newVal = valueSet[randIndex]; tempGrid.InitSetCell(row, col, newVal); valueSet.Remove(newVal); //remove paced value from options for (row = 1; row < 9; row++) { //fills in column 0 with remaining possible values, storing in place- //holder as it goes so as to preserve when placing in row 0 later randIndex = rnd.Next(0, valueSet.Count); newVal = valueSet[randIndex]; valueSet2.Add(newVal); valueSet.Remove(newVal); tempGrid.InitSetCell(row, col, newVal); } //row = 0; //reset row to 0 for (int i = 8; i >= 0; i--) { tempGrid.InitSetCell(0, 9 - i, tempGrid.Grid[i, 0]); } do { squigglySolver = new SquigglySolver(scheme); squigglySolver.SolveGrid((SquigglyGrid)tempGrid.Clone(), false); //Slv to fill remainder of grid SolutionGrid = squigglySolver.SolutionGrid; } while (SolutionGrid == null || SolutionGrid.IsBlank()); PermaGrid = Blanker(SolutionGrid); //call Blanker to carry out the return(PermaGrid); //blanking of fileds,then return the grid to user to solve }
/// <summary> /// IsSolved checks to see if all cells in the grid contain a value. /// If so, due to how the solve algorithm solves, the squiggly must be /// solved correctly. /// </summary> /// <param name="grid">Current state of the squiggly grid</param> /// <returns>TRUE: Squiggly is solved, FALSE: Not solved</returns> public bool IsSolved(SquigglyGrid grid) { bool result = true; //Assume squiggly is solved int r, c; r = 0; while (result == true && r < 9) //Check every row { c = 0; while (result == true && c < 9) //Check every column { //If an empty cell is found, result gets FALSE result = (result && grid.Grid[r, c] != 0); c++; } r++; } return result; }
/// <summary> /// IsSolved checks to see if all cells in the grid contain a value. /// If so, due to how the solve algorithm solves, the squiggly must be /// solved correctly. /// </summary> /// <param name="grid">Current state of the squiggly grid</param> /// <returns>TRUE: Squiggly is solved, FALSE: Not solved</returns> public bool IsSolved(SquigglyGrid grid) { bool result = true; //Assume squiggly is solved int r, c; r = 0; while (result == true && r < 9) //Check every row { c = 0; while (result == true && c < 9) //Check every column { //If an empty cell is found, result gets FALSE result = (result && grid.Grid[r, c] != 0); c++; } r++; } return(result); }
/// <summary> /// ListPossible populates list[] with "true" at each index /// representing that value is a possible value for cell at [row, col]. /// It returns the total count of possible values in that square /// </summary> /// <param name="row">Row of target cell</param> /// <param name="col">Column of target cell</param> /// <param name="g">current state of grid</param> /// <returns>Integer count of possible values for given cell</returns> private int ListPossible(int row, int col, SquigglyGrid g) { int count = 0; ClearList(); //Create a fresh list for bool population for (int i = 1; i < 10; i++) //For i = 1..9 (valid values) { if (IsPossible(g, row, col, i) == true) //If i can go in cell { list[i] = true; count++; } else //Value of i found in Row, Col, or 3x3 { list[i] = false; } } return(count); }
public Squiggly(Difficulty diff,int[,] scheme) : base(diff) { random = new Random(); base.scheme = scheme; foundit = false; base.init(); solve(0, 0); squigglyGenerator = new SquigglyGenerator(solution, scheme, diff); squigglyGrid = new SquigglyGrid(); squigglyGrid.Grid = solution; SquigglyGrid blanked = squigglyGenerator.Blanker(squigglyGrid); mask = blanked.Grid; for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { mask[i, j] = -mask[i, j]; userGrid[i, j] = mask[i, j]; } } }
public Squiggly(Difficulty diff, int[,] scheme) : base(diff) { random = new Random(); base.scheme = scheme; foundit = false; base.init(); solve(0, 0); squigglyGenerator = new SquigglyGenerator(solution, scheme, diff); squigglyGrid = new SquigglyGrid(); squigglyGrid.Grid = solution; SquigglyGrid blanked = squigglyGenerator.Blanker(squigglyGrid); mask = blanked.Grid; for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { mask[i, j] = -mask[i, j]; userGrid[i, j] = mask[i, j]; } } }
/// <summary> /// FindFewestChoices finds the first cell having the smallest number /// of available choices, and sets the row and column of that cell for /// use in SolveGrid /// </summary> /// <param name="grid">Current state of the grid</param> /// <param name="r">OUTPUT sets r for use in caller</param> /// <param name="c">OUTPUT sets c for use in caller</param> /// <param name="numChoices">OUTPUT sets var for use in caller</param> /// <returns>Returns true if valid cell found, false if not</returns> private bool FindFewestChoices(SquigglyGrid grid, out int r, out int c, out int numChoices) { bool[] minList = new bool[10]; int numCh, minR, minC, minChoice, i, j; bool bad, result; minChoice = 10; minR = 0; minC = 0; for (i = 1; i < 10; i++) //Initialize minList to FALSE { minList[i] = false; } bad = false; i = 0; while (!bad && i < 9) //While not a bad solutn and trying valid row { j = 0; while (!bad && j < 9) //not a bad solutn and trying valid column { if (grid.Grid[i, j] == 0) { numCh = ListPossible(i, j, grid); //Get # of choices if (numCh == 0) //If no choices found, bad solution { bad = true; } else //If not bad solutn... { if (numCh < minChoice) //If less than current min { minChoice = numCh; //Set new min value list.CopyTo(minList, 0);//Save list of possible minR = i; //set row of cell with least minC = j; //set col of cell with least } } } j++; } i++; } if (bad || minChoice == 10) //If bad solutn or minChoice never set { result = false; //No fewest possible choices r = 0; c = 0; numChoices = 0; } else { result = true; //Valid cell found, return information to caller r = minR; c = minC; numChoices = minChoice; minList.CopyTo(list, 0); } return result; }
/// <summary> /// IsIn3x3 determines which 3x3 grid cell is in using GroupNum. /// Values are: /// [0, 0] [0, 1] [0, 2] /// [1, 0] [1, 1] [1, 2] /// [2, 0] [2, 1] [2, 2] /// And then checks if given value occurs in the 3x3 grid. /// </summary> /// <param name="g">Current state of the grid</param> /// <param name="row">Row of cell being checked</param> /// <param name="col">Column of cell being checked</param> /// <param name="value">Value being sought</param> /// <returns>True if Value is found, false if not</returns> private bool IsIn3X3(SquigglyGrid g, int row, int col, int value) { int groupnum = scheme[row, col]; for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { if (scheme[i, j] == groupnum && g.Grid[i, j] == value) { return true; } } } return false; }
/// <summary> /// IsInColumn checks if given value occurs in the given row. /// </summary> /// <param name="grid">Current state of the grid</param> /// <param name="col">Column being check</param> /// <param name="value">Value being sought</param> /// <returns></returns> private bool IsInCol(SquigglyGrid grid, int col, int value) { bool result = false; for (int i = 0; i < 9; i++) //Iterate through column { //check if cell holds value being sought result = result || (Math.Abs(grid.Grid[i, col]) == value); } return result; }
/// <summary> /// IsInRow checks if given value occurs in the given row /// </summary> /// <param name="grid">Current state of squiggly grid</param> /// <param name="row">Row to check</param> /// <param name="value">Value to look for</param> /// <returns></returns> private bool IsInRow(SquigglyGrid grid, int row, int value) { bool result = false; for (int i = 0; i < 9; i++) //Iterate through row { //check if cell holds value being sought result = result || (Math.Abs(grid.Grid[row, i]) == value); } return result; }
private void dataGridView1_KeyDown(object sender, KeyEventArgs e) { if (dataGridView1.SelectedCells.Count > 0) { //dataGridView1.SelectedCells[0].Value = ""; var selected = dataGridView1.SelectedCells[0]; int sel_i = selected.RowIndex; int sel_j = selected.ColumnIndex; if (CellMap[sel_i, sel_j] == LOCKED) { return; } if (!(e.KeyValue >= 49 && e.KeyValue <= 57 || e.KeyValue >= 97 && e.KeyValue <= 105)) { //MessageBox.Show(String.Format("{0}",e.KeyValue)); if (e.KeyValue == 27 || e.KeyValue == 8 || e.KeyValue == 46) // Use e.KeyCode == Keys.Enter etc. { selected.Value = ""; } } else { int value = -1; if (e.KeyValue >= 49 && e.KeyValue <= 57) { selected.Value = e.KeyValue - 48; value = e.KeyValue - 48; } else { selected.Value = e.KeyValue - 96; value = e.KeyValue - 96; } if (standardGrid != null) { standardGrid.Grid[sel_i, sel_j] = value; } else if (squigglyGrid != null) { squigglyGrid.Grid[sel_i, sel_j] = value; } highlightSelectedNumber(); } } if (standardGrid != null) { if (standardSolver.IsSolved(standardGrid)) { MessageBox.Show("Congratulations!!!"); standardGrid = null; } } else if (squigglyGrid != null) { if (squigglySolver.IsSolved(squigglyGrid)) { MessageBox.Show("Congratulations!!!"); squigglyGrid = null; } } }
public SquigglyGrid InitGrid() { //Randomly fill in the first row and column of squigglygrid SquigglyGrid tempGrid = new SquigglyGrid { }; //temporary grid to assign values into int row = 0; //variable for navigating 'rows' int col = 0; //variable for navigating 'columns' int newVal; //value to place into grid //bool solved; List<int> valueSet = new List<int>(Enumerable.Range(1, 9)); //range of numbers that can be added to the grid List<int> valueSet2 = new List<int>(); //placeholder values in column 0 Random rnd = new Random(); //random variable for choosing random number int randIndex = 0; //index in valueSet/valueSet2 that is accessed randIndex = rnd.Next(0, 8); //get a random number and place in grid(0,0) newVal = valueSet[randIndex]; tempGrid.InitSetCell(row, col, newVal); valueSet.Remove(newVal); //remove paced value from options for (row = 1; row < 9; row++) { //fills in column 0 with remaining possible values, storing in place- //holder as it goes so as to preserve when placing in row 0 later randIndex = rnd.Next(0, valueSet.Count); newVal = valueSet[randIndex]; valueSet2.Add(newVal); valueSet.Remove(newVal); tempGrid.InitSetCell(row, col, newVal); } //row = 0; //reset row to 0 for (int i = 8; i >= 0; i--) { tempGrid.InitSetCell(0, 9 - i, tempGrid.Grid[i, 0]); } do { squigglySolver = new SquigglySolver(scheme); squigglySolver.SolveGrid((SquigglyGrid)tempGrid.Clone(), false); //Slv to fill remainder of grid SolutionGrid = squigglySolver.SolutionGrid; } while (SolutionGrid == null || SolutionGrid.IsBlank()); PermaGrid = Blanker(SolutionGrid); //call Blanker to carry out the return PermaGrid; //blanking of fileds,then return the grid to user to solve }
/// <summary> /// ListPossible populates list[] with "true" at each index /// representing that value is a possible value for cell at [row, col]. /// It returns the total count of possible values in that square /// </summary> /// <param name="row">Row of target cell</param> /// <param name="col">Column of target cell</param> /// <param name="g">current state of grid</param> /// <returns>Integer count of possible values for given cell</returns> private int ListPossible(int row, int col, SquigglyGrid g) { int count = 0; ClearList(); //Create a fresh list for bool population for (int i = 1; i < 10; i++) //For i = 1..9 (valid values) { if (IsPossible(g, row, col, i) == true) //If i can go in cell { list[i] = true; count++; } else //Value of i found in Row, Col, or 3x3 { list[i] = false; } } return count; }
/// <summary> /// SolveGrid attempts to solve a squiggly by checking through all /// possible values for each cell, discarding values that do not lead /// to a valid solution. On a try, it recursively calls itself to /// maintain previous states of the grid to back track to if the /// current path fails. It creates a local version of the grid to /// facilitate this. It also checks if the squiggly is uniquely solvable. /// </summary> /// <param name="g">Current state of the grid</param> /// <param name="checkUnique">Do we care if it has unique soln?</param> /// <returns></returns> public bool SolveGrid(SquigglyGrid g, bool checkUnique) { SquigglyGrid grid = new SquigglyGrid(); grid = (SquigglyGrid)g.Clone(); //Copy the input grid int i, choice, r, c, numChoices; bool done, got_one, solved, result; got_one = false; recursions++; FillSingleChoices(grid); //First, fill in all single choice values if (IsSolved(grid)) //If it's already solved { if (numSolns > 0) //If another soln already found { stoplooking = true; //Don't look for more result = false; //Return false, no UNIQUE soln } else //If no other soln found yet { numSolns++; final[numSolns] = (SquigglyGrid)g.Clone(); //Save found soln result = true; SolutionGrid = grid; } } else //If not solved yet { if (!FindFewestChoices(grid, out r, out c, out numChoices)) { result = false; //Invalid solution } else //Current grid still valid { i = 1; done = false; got_one = false; while (!done && i <= numChoices) { choice = PickOneTrue(); //Pick a possible value list[choice] = false; //Won't want to use it again grid.UserSetCell(r, c, choice); if (recursions < MaxDepth) { //-----------We must go deeper. SUDCEPTION!-----------// solved = (SolveGrid(grid, checkUnique)); //Recurse } else { solved = false; } if (stoplooking == true) { done = true; got_one = true; } else { got_one = (got_one || solved); if (!checkUnique) //If not looking for unique soln { done = got_one; //Then we have a solution } } i++; } result = got_one; } } return result; }
public SquigglyGrid RandomlyBlank(SquigglyGrid tempGrid, int sym, ref int blankCount) { //blank one or two squares(depending on if on center line) randomly Random rnd = new Random(); //allow random number generation int row = rnd.Next(0, 8); //choose randomly the row int column = rnd.Next(0, 8); //and column of cell to blank while (tempGrid.Grid[row, column] == 0) //don't blank a blank cell { row = rnd.Next(0, 8); column = rnd.Next(0, 8); } tempGrid.InitSetCell(row, column, 0); //clear chosen cell blankCount++; //increment the count of blanks switch (sym) { //based on symmetry, blank a second cell case 0: //vertical symmetry if (tempGrid.Grid[row, 8 - column] != 0) //if not already blanked blankCount++; //increment blank counter tempGrid.InitSetCell(row, 8 - column, 0); //blank opposite cell break; case 1: //horizontal symmetry if (tempGrid.Grid[8 - row, column] != 0) blankCount++; tempGrid.InitSetCell(8 - row, column, 0); break; case 2: //diagonal symmetry if (tempGrid.Grid[column, row] != 0) blankCount++; tempGrid.InitSetCell(column, row, 0); break; default: //diagonal symmetry if (tempGrid.Grid[row, 8 - column] != 0) blankCount++; tempGrid.InitSetCell(column, row, 0); break; } return tempGrid; }
public CustomSquiggly(int[,] scheme, Difficulty diff) { this.difficulty = diff; this.scheme = scheme; tries++; this.Grid = new int[9, 9]; this.rows = new int[10, 10]; this.cols = new int[10, 10]; this.groups = new int[10, 10]; solution = new int[9, 9]; Random rand = new Random(); int newVal; List <int> valueSet = new List <int>(Enumerable.Range(1, 9)); Random rnd = new Random(); int randIndex = 0; randIndex = rnd.Next(0, 8); newVal = valueSet[randIndex]; solution[0, 0] = newVal; valueSet.Remove(newVal); for (int i = 1; i < 9; i++) { randIndex = rnd.Next(0, valueSet.Count); newVal = valueSet[randIndex]; valueSet.Remove(newVal); solution[i, 0] = newVal; rows[i, newVal] = 1; cols[0, newVal] = 1; groups[getGroup(i, 0), newVal] = 1; } for (int i = 8; i >= 1; i--) { newVal = solution[0, 9 - i] = solution[i, 0]; rows[0, newVal] = 1; cols[9 - i, newVal] = 1; groups[getGroup(0, 9 - i), newVal] = 1; } //easy /*int []r = {0,0,0,1,1,1,1,1,1,2,2,2,3,3,3,4,4,4,4,4,5,5,5,6,6,6,7,7,7,7,7,7,8,8,8}; * int []c = {1,5,6,0,1,2,4,6,7,0,4,5,1,6,8,0,2,4,6,8,0,2,7,3,4,8,1,2,4,6,7,8,2,3,7}; * int[] v = { 2, 9, 6, 7, 6, 3, 9, 1, 2, 9, 2, 7, 4, 7, 5, 1, 7, 6, 8, 2, 8, 2, 5, 6, 7, 9, 7, 9, 1, 5, 8, 3, 8, 3, 4 }; */ //hard /*int[] r = { 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 5 }; * int[] c = { 1, 5, 6, 0, 1, 2, 4, 6, 7, 0, 4, 5, 1, 6, 8, 0, 2, 4, 6, 8, 0 }; * int[] v = { 2, 9, 6, 7, 6, 3, 9, 1, 2, 9, 2, 7, 4, 7, 5, 1, 7, 6, 8, 2, 8 }; * * /*int [] r = {0,0,0,0,0,1,2,2,2,3,3,5,5,6,6,6,7,8,8,8,8,8}; * int [] c = {1,2,3,4,5,0,2,6,8,1,4,4,7,0,2,6,8,3,4,5,6,7}; * int[] v = { 4, 7, 3, 5, 6, 3, 5, 4, 3, 9, 6, 1, 8, 4, 3, 6, 9, 1, 9, 5, 8, 3 };*/ /*for (int i = 0; i < r.Length; i++) * { * solution[r[i], c[i]] = v[i]; * rows[r[i], v[i]] = 1; * cols[c[i], v[i]] = 1; * groups[getGroup(r[i], c[i]), v[i]] = 1; * }*/ dfs(0, 0); SquigglyGenerator gen = new SquigglyGenerator(Grid, scheme, difficulty); SquigglyGrid grid = new SquigglyGrid(); grid.Grid = Grid; SquigglyGrid blanked = gen.Blanker(grid); solution = (int[, ])Grid.Clone(); Grid = blanked.Grid; }
/// <summary> /// SolveGrid attempts to solve a squiggly by checking through all /// possible values for each cell, discarding values that do not lead /// to a valid solution. On a try, it recursively calls itself to /// maintain previous states of the grid to back track to if the /// current path fails. It creates a local version of the grid to /// facilitate this. It also checks if the squiggly is uniquely solvable. /// </summary> /// <param name="g">Current state of the grid</param> /// <param name="checkUnique">Do we care if it has unique soln?</param> /// <returns></returns> public bool SolveGrid(SquigglyGrid g, bool checkUnique) { SquigglyGrid grid = new SquigglyGrid(); grid = (SquigglyGrid)g.Clone(); //Copy the input grid int i, choice, r, c, numChoices; bool done, got_one, solved, result; got_one = false; recursions++; FillSingleChoices(grid); //First, fill in all single choice values if (IsSolved(grid)) //If it's already solved { if (numSolns > 0) //If another soln already found { stoplooking = true; //Don't look for more result = false; //Return false, no UNIQUE soln } else //If no other soln found yet { numSolns++; final[numSolns] = (SquigglyGrid)g.Clone(); //Save found soln result = true; SolutionGrid = grid; } } else //If not solved yet { if (!FindFewestChoices(grid, out r, out c, out numChoices)) { result = false; //Invalid solution } else //Current grid still valid { i = 1; done = false; got_one = false; while (!done && i <= numChoices) { choice = PickOneTrue(); //Pick a possible value list[choice] = false; //Won't want to use it again grid.UserSetCell(r, c, choice); if (recursions < MaxDepth) { //-----------We must go deeper. SUDCEPTION!-----------// solved = (SolveGrid(grid, checkUnique)); //Recurse } else { solved = false; } if (stoplooking == true) { done = true; got_one = true; } else { got_one = (got_one || solved); if (!checkUnique) //If not looking for unique soln { done = got_one; //Then we have a solution } } i++; } result = got_one; } } return(result); }
public void setGrid(gameType type, Difficulty level) { for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { dataGridView1.Rows[i].Cells[j].Value = ""; } } if (type == gameType.Standard) { squigglyGrid = null; PuzzleGenerator gen = new PuzzleGenerator(level); PuzzleGrid grid = gen.InitGrid(); standardSolver = new PuzzleSolver(); standardSolver.SolutionGrid = gen.SolutionGrid; standardGrid = new PuzzleGrid(); for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { if (grid.Grid[i, j] != 0) { dataGridView1.Rows[i].Cells[j].Value = -grid.Grid[i, j]; } standardGrid.Grid[i, j] = -grid.Grid[i, j]; ColorMap[i, j] = Color.White; } } } else { standardGrid = null; schemeBuilder(); Random r = new Random(); int[,] scheme = Schemes[r.Next(6)]; bool Completed = false; CustomSquiggly squigglyGrid = null; squigglySolver = new SquigglySolver(scheme); while (squigglyGrid == null && !Completed) { squigglyGrid = Limex(() => new CustomSquiggly(scheme, level), 4000, out Completed); } for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { if (squigglyGrid.Grid[i, j] != 0) { dataGridView1.Rows[i].Cells[j].Value = -squigglyGrid.Grid[i, j]; } dataGridView1.Rows[i].Cells[j].Style.BackColor = colors[scheme[i, j]]; ColorMap[i, j] = colors[scheme[i, j]]; } } string rez = "$$$$$$ try\n"; for (int ii = 0; ii < 9; ii++) { for (int jj = 0; jj < 9; jj++) { rez += CustomSquiggly.solution[ii, jj] + " "; } rez += "\n"; } MessageBox.Show(rez); } LockCellMap(); }
/// <summary> /// IsPossible returns true if IsInRow, IsInCol & IsIn3x3 return false /// </summary> /// <param name="g">Current state of the grid</param> /// <param name="row">row of target cell</param> /// <param name="col">column of target cell</param> /// <param name="value">value being sought</param> /// <returns>True if value can occupy cell at [row, col]</returns> private bool IsPossible(SquigglyGrid g, int row, int col, int value) { //Return true if value can go into [row, col] now bool result; result = (!IsInRow(g, row, value) && !IsInCol(g, col, value) && !IsIn3X3(g, row, col, value)); return result; }