Sudoku Solver in C++
The input file should look like:
BEGIN sudoku.in
5 3 0 0 7 0 0 0 0
6 0 0 1 9 5 0 0 0
0 9 8 0 0 0 0 6 0
8 0 0 0 6 0 0 0 3
4 0 0 8 0 3 0 0 1
7 0 0 0 2 0 0 0 6
0 6 0 0 0 0 2 8 0
0 0 0 4 1 9 0 0 5
0 0 0 0 8 0 0 7 9
END sudoku.in
Full explanation: here
1 2 #include <iostream> 3 #include <fstream> 4 5 using namespace std; 6 7 class SudokuBoard; 8 void printB(SudokuBoard sb); 9 10 typedef unsigned int uint; 11 12 const uint MAXVAL = 9; 13 const uint L = 9; 14 const uint C = 9; 15 const uint S = L * C; 16 const uint ZONEL = 3; 17 const uint ZONEC = 3; 18 const uint ZONES = ZONEL * ZONEC; 19 20 const uint lineElements[L][C] = { 21 { 0, 1, 2, 3, 4, 5, 6, 7, 8}, 22 { 9, 10, 11, 12, 13, 14, 15, 16, 17}, 23 {18, 19, 20, 21, 22, 23, 24, 25, 26}, 24 {27, 28, 29, 30, 31, 32, 33, 34, 35}, 25 {36, 37, 38, 39, 40, 41, 42, 43, 44}, 26 {45, 46, 47, 48, 49, 50, 51, 52, 53}, 27 {54, 55, 56, 57, 58, 59, 60, 61, 62}, 28 {63, 64, 65, 66, 67, 68, 68, 70, 71}, 29 {72, 73, 74, 75, 76, 77, 78, 79, 80} 30 }; 31 32 const uint columnElements[C][L] = { 33 { 0, 9, 18, 27, 36, 45, 54, 63, 72}, 34 { 1, 10, 19, 28, 37, 46, 55, 64, 73}, 35 { 2, 11, 20, 29, 38, 47, 56, 65, 74}, 36 { 3, 12, 21, 30, 39, 48, 57, 66, 75}, 37 { 4, 13, 22, 31, 40, 49, 58, 67, 76}, 38 { 5, 14, 23, 32, 41, 50, 59, 68, 77}, 39 { 6, 15, 24, 33, 42, 51, 60, 69, 78}, 40 { 7, 16, 25, 34, 43, 52, 61, 70, 79}, 41 { 8, 17, 26, 35, 44, 53, 62, 71, 80} 42 }; 43 44 const uint zoneElements[S / ZONES][ZONES] = { 45 { 0, 1, 2, 9, 10, 11, 18, 19, 20}, 46 { 3, 4, 5, 12, 13, 14, 21, 22, 23}, 47 { 6, 7, 8, 15, 16, 17, 24, 25, 26}, 48 {27, 28, 29, 36, 37, 38, 45, 46, 47}, 49 {30, 31, 32, 39, 40, 41, 48, 49, 50}, 50 {33, 34, 35, 42, 43, 44, 51, 52, 53}, 51 {54, 55, 56, 63, 64, 65, 72, 73, 74}, 52 {57, 58, 59, 66, 67, 68, 75, 76, 77}, 53 {60, 61, 62, 68, 70, 71, 78, 79, 80} 54 }; 55 56 class SudokuBoard { 57 public: 58 SudokuBoard() : 59 filledIn(0) 60 { 61 for (uint i(0); i < S; ++i) 62 table[i] = usedDigits[i] = 0; 63 } 64 65 virtual ~SudokuBoard() { 66 } 67 68 int const at(uint l, uint c) { // Returns the value at line l and row c 69 if (isValidPos(l, c)) 70 return table[l * L + c]; 71 else 72 return -1; 73 } 74 75 void set(uint l, uint c, uint val) { // Sets the cell at line l and row c to hold the value val 76 if (isValidPos(l, c) && ((0 < val) && (val <= MAXVAL))) { 77 if (table[l * C + c] == 0) 78 ++filledIn; 79 table[l * C + c] = val; 80 for (uint i = 0; i < C; ++i) // Update lines 81 usedDigits[lineElements[l][i]] |= 1<<val; 82 for (uint i = 0; i < L; ++i) // Update columns 83 usedDigits[columnElements[c][i]] |= 1<<val; 84 int z = findZone(l * C + c); 85 for (uint i = 0; i < ZONES; ++i) // Update columns 86 usedDigits[zoneElements[z][i]] |= 1<<val; 87 } 88 } 89 90 void solve() { 91 try { // This is just a speed boost 92 scanAndSet(); // Logic approach 93 goBruteForce(); // Brute force approach 94 } catch (int e) { // This is just a speed boost 95 } 96 } 97 98 void scanAndSet() { 99 int b; 100 bool changed(true); 101 while (changed) { 102 changed = false; 103 for (uint i(0); i < S; ++i) 104 if (0 == table[i]) // Is there a digit already written? 105 if ((b = bitcount(usedDigits[i])) == MAXVAL - 1) { // If there's only one digit I can place in this cell, do 106 int d(1); // Find the digit 107 while ((usedDigits[i] & 1<<d) > 0) 108 ++d; 109 set(i / C, i % C, d); // Fill it in 110 changed = true; // The board has been changed so this step must be rerun 111 } else if (bitcount(usedDigits[i]) == MAXVAL) 112 throw 666; // Speed boost 113 } 114 } 115 116 void goBruteForce() { 117 int max(-1); // Find the cell with the _minimum_ number of posibilities (i.e. the one with the largest number of /used/ digits) 118 for (uint i(0); i < S; ++i) 119 if (table[i] == 0) // Is there a digit already written? 120 if ((max == -1) || (bitcount(usedDigits[i]) > bitcount(usedDigits[max]))) 121 max = i; 122 123 if (max != -1) { 124 for (uint i(1); i <= MAXVAL; ++i) // Go through each possible digit 125 if ((usedDigits[max] & 1<<i) == 0) { // If it can be placed in this cell, do 126 SudokuBoard temp(*this); // Create a new board 127 temp.set(max / C, max % C, i); // Complete the attempt 128 temp.solve(); // Solve it 129 if (temp.getFilledIn() == S) { // If the board was completely solved (i.e. the number of filled in cells is S) 130 for (uint j(0); j < S; ++j) // Copy the board into this one 131 set(j / C, j % C, temp.at(j / C, j % C)); 132 return; // Break the recursive cascade 133 } 134 } 135 } 136 } 137 138 uint getFilledIn() { 139 return filledIn; 140 } 141 142 private: 143 uint table[S]; 144 uint usedDigits[S]; 145 uint filledIn; 146 147 bool const inline isValidPos(int l, int c) { 148 return ((0 <= l) && (l < (int)L) && (0 <= c) && (c < (int)C)); 149 } 150 151 uint const inline findZone(uint off) { 152 return ((off / C / ZONEL) * (C / ZONEC) + (off % C / ZONEC)); 153 } 154 155 uint const inline bitcount(uint x) { 156 uint count(0); 157 for (; x; ++count, x &= (x - 1)); 158 return count; 159 } 160 }; 161 162 void printB(SudokuBoard sb) { 163 cout << " | ------------------------------- |" << endl; 164 for (uint i(0); i < S; ++i) { 165 if (i % 3 == 0) 166 cout << " |"; 167 cout << " " << sb.at(i / L, i % L); 168 if (i % C == C - 1) { 169 if (i / C % 3 == 2) 170 cout << " |" << endl << " | -------------------------------"; 171 cout << " |" << endl; 172 } 173 } 174 cout << endl; 175 } 176 177 int main(int argc, char *argv[]) { 178 SudokuBoard sb; 179 180 ifstream fin("sudoku4.in"); 181 int aux; 182 for (uint i(0); i < S; ++i) { 183 fin >> aux; 184 sb.set(i / L, i % L, aux); 185 } 186 fin.close(); 187 188 printB(sb); 189 sb.solve(); 190 printB(sb); 191 192 return 0; 193 } 194