// Is there one and only one solution? private Ret TestUniqueness() { // Find untouched location with most information int xp = 0; int yp = 0; byte[] Mp = null; int cMp = 10; for (int y = 0; y < 9; y++) { for (int x = 0; x < 9; x++) { // Is this spot unused? if (m_sudoku[y, x] == 0) { // Set M of possible solutions byte[] M = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; // Remove used numbers in the vertical direction for (int a = 0; a < 9; a++) { M[m_sudoku[a, x]] = 0; } // Remove used numbers in the horizontal direction for (int b = 0; b < 9; b++) { M[m_sudoku[y, b]] = 0; } // Remove used numbers in the sub square. int squareIndex = m_subSquare[y, x]; for (int c = 0; c < 9; c++) { EntryPoint p = m_subIndex[squareIndex, c]; M[m_sudoku[p.x, p.y]] = 0; } int cM = 0; // Calculate cardinality of M for (int d = 1; d < 10; d++) { cM += M[d] == 0 ? 0 : 1; } // Is there more information in this spot than in the best yet? if (cM < cMp) { cMp = cM; Mp = M; xp = x; yp = y; } } } } // Finished? if (cMp == 10) { return(Ret.Unique); } // Couldn't find a solution? if (cMp == 0) { return(Ret.NoSolution); } // Try elements int success = 0; for (int i = 1; i < 10; i++) { if (Mp[i] != 0) { m_sudoku[yp, xp] = Mp[i]; switch (TestUniqueness()) { case Ret.Unique: success++; break; case Ret.NotUnique: return(Ret.NotUnique); case Ret.NoSolution: break; } // More than one solution found? if (success > 1) { return(Ret.NotUnique); } } } // Restore to original state. m_sudoku[yp, xp] = 0; switch (success) { case 0: return(Ret.NoSolution); case 1: return(Ret.Unique); default: // Won't happen. return(Ret.NotUnique); } }
/// <summary> /// Solves the given Sudoku. /// </summary> /// <returns>Success</returns> public bool Solve() { // Find untouched location with most information int xp = 0; int yp = 0; byte[] Mp = null; int cMp = 10; for (int y = 0; y < 9; y++) { for (int x = 0; x < 9; x++) { // Is this spot unused? if (m_sudoku[y, x] == 0) { // Set M of possible solutions byte[] M = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; // Remove used numbers in the vertical direction for (int a = 0; a < 9; a++) { M[m_sudoku[a, x]] = 0; } // Remove used numbers in the horizontal direction for (int b = 0; b < 9; b++) { M[m_sudoku[y, b]] = 0; } // Remove used numbers in the sub square. int squareIndex = m_subSquare[y, x]; for (int c = 0; c < 9; c++) { EntryPoint p = m_subIndex[squareIndex, c]; M[m_sudoku[p.x, p.y]] = 0; } int cM = 0; // Calculate cardinality of M for (int d = 1; d < 10; d++) { cM += M[d] == 0 ? 0 : 1; } // Is there more information in this spot than in the best yet? if (cM < cMp) { cMp = cM; Mp = M; xp = x; yp = y; } } } } // Finished? if (cMp == 10) { return(true); } // Couldn't find a solution? if (cMp == 0) { return(false); } // Try elements for (int i = 1; i < 10; i++) { if (Mp[i] != 0) { m_sudoku[yp, xp] = Mp[i]; if (Solve()) { return(true); } } } // Restore to original state. m_sudoku[yp, xp] = 0; return(false); }
// Generate spots private bool Gen(int spots) { for (int i = 0; i < spots; i++) { int xRand, yRand; do { xRand = Randomizer.GetInt(9); yRand = Randomizer.GetInt(9); } while(m_sudoku[yRand, xRand] != 0); ///////////////////////////////////// // Get feasible values for spot. ///////////////////////////////////// // Set M of possible solutions byte[] M = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; // Remove used numbers in the vertical direction for (int a = 0; a < 9; a++) { M[m_sudoku[a, xRand]] = 0; } // Remove used numbers in the horizontal direction for (int b = 0; b < 9; b++) { M[m_sudoku[yRand, b]] = 0; } // Remove used numbers in the sub square. int squareIndex = m_subSquare[yRand, xRand]; for (int c = 0; c < 9; c++) { EntryPoint p = m_subIndex[squareIndex, c]; M[m_sudoku[p.x, p.y]] = 0; } int cM = 0; // Calculate cardinality of M for (int d = 1; d < 10; d++) { cM += M[d] == 0 ? 0 : 1; } // Is there a number to use? if (cM > 0) { int e = 0; do { // Randomize number from the feasible set M e = Randomizer.GetInt(1, 10); } while(M[e] == 0); // Set number in Sudoku m_sudoku[yRand, xRand] = (byte)e; } else { // Error return(false); } } // Successfully generated a feasible set. return(true); }