#include using std::ostream; using std::cout; using std::cin; #include using std::ifstream; #include #include "string.h" #include "Queue.h" LARGE_INTEGER tick1, tick2, ticksPerSecond; double time, timeThinking, timeDoing, totalThinking, totalDoing; class Domain { public: Domain(); void Dump() const; unsigned Size() const; bool Contains(const unsigned n) const; bool Insert(const unsigned n); bool Remove(const unsigned n); unsigned GetSingle() const; private: unsigned domain[9]; unsigned size; }; Domain::Domain() :size(9) { for(unsigned i=0; i<9; i++) domain[i] = i+1; } void Domain::Dump() const { for(unsigned i=0; i<9; i++) { if(i == size) cout << "|"; cout << domain[i]; } cout << "\n"; } unsigned Domain::Size() const { return size; } bool Domain::Contains(const unsigned n) const { for(unsigned i=0; i* q); bool RecursiveSet(unsigned r, unsigned c, unsigned val, Queue* q); Square** grid; }; SuDoKu::SuDoKu() { grid = new Square*[9]; for(unsigned i=0; i<9; i++) grid[i] = new Square[9]; } SuDoKu::SuDoKu(const SuDoKu& S) { unsigned i; grid = new Square*[9]; for(i=0; i<9; i++) grid[i] = new Square[9]; for(i=0; i<81; i++) grid[i/9][i%9] = S.grid[i/9][i%9]; } SuDoKu& SuDoKu::operator=(const SuDoKu& S) { if(&S == this) return *this; unsigned i; for(i=0; i<81; i++) grid[i/9][i%9] = S.grid[i/9][i%9]; return *this; } bool SuDoKu::Filled() const { for(unsigned i=0; i<81; i++) if(grid[i/9][i%9].GetValue() == 0) return false; return true; } char asdf[10]; ostream& operator<<(ostream& out, SuDoKu& S); bool SuDoKu::RecursiveSet(unsigned r, unsigned c, unsigned val, Queue* q) { grid[r][c].SetValue(val); //cout << *this; //cin.getline(asdf, 10); unsigned row, col; for(row=0; row<9; row++) if(row != r && grid[row][c].GetValue() == 0) { grid[row][c].RemoveFromDomain(val); if(grid[row][c].DomainSize() == 0) return false; q->Enqueue(RowColPair(row, c)); } for(col=0; col<9; col++) if(col != c && grid[r][col].GetValue() == 0) { grid[r][col].RemoveFromDomain(val); if(grid[r][col].DomainSize() == 0) return false; q->Enqueue(RowColPair(r, col)); } for(row = r - r%3; row < r - r%3 + 3; row++) for(col = c - c%3; col < c - c%3 + 3; col++) if(row != r && col != c && grid[row][col].GetValue() == 0) { grid[row][col].RemoveFromDomain(val); if(grid[row][col].DomainSize() == 0) return false; q->Enqueue(RowColPair(row, col)); } for(row=0; row<9; row++) if(row != r && grid[row][c].GetValue() == 0 && grid[row][c].DomainSize() == 1) if(!RecursiveSet(row, c, grid[row][c].DomainContents(), q)) return false; for(col=0; col<9; col++) if(col != c && grid[r][col].GetValue() == 0 && grid[r][col].DomainSize() == 1) if(!RecursiveSet(r, col, grid[r][col].DomainContents(), q)) return false; for(row = r - r%3; row < r - r%3 + 3; row++) for(col = c - c%3; col < c - c%3 + 3; col++) if(row != r && col != c && grid[row][col].GetValue() == 0 && grid[row][col].DomainSize() == 1) if(!RecursiveSet(row, col, grid[row][col].DomainContents(), q)) return false; return true; } bool SuDoKu::Set(unsigned r, unsigned c, unsigned val) { if(val == 0) { grid[r][c].SetValue(0); return true; } else { QueryPerformanceCounter(&tick2); time = tick2.QuadPart - tick1.QuadPart; timeDoing += time / ticksPerSecond.QuadPart; QueryPerformanceCounter(&tick1); Queue q; if(!RecursiveSet(r, c, val, &q)) return false; bool b = PigeonHole(&q); QueryPerformanceCounter(&tick2); time = tick2.QuadPart - tick1.QuadPart; timeThinking += time / ticksPerSecond.QuadPart; QueryPerformanceCounter(&tick1); return b; } } bool SuDoKu::PigeonHole(Queue* q) { bool valsInDomains[9]; RowColPair p(0,0); unsigned i, a, b, c, numUniqueVals, numEmptySquares; while(!q->Empty()) { for(i=0; i<9; i++) valsInDomains[i] = false; p=q->Dequeue(); for(a=0; a<9; a++) { if(grid[a][p.col].GetValue() == 0) { numEmptySquares++; for(b=1; b<=9; b++) { if(grid[a][p.col].DomainContains(b)) valsInDomains[b-1] = true; } } } for(i=0; i<9; i++) { if(valsInDomains[i]) numUniqueVals++; valsInDomains[i] = false; } if(numUniqueVals < numEmptySquares) return false; numUniqueVals = numEmptySquares = 0; for(a=0; a<9; a++) { if(grid[p.row][a].GetValue() == 0) { numEmptySquares++; for(b=1; b<=9; b++) { if(grid[p.row][a].DomainContains(b)) valsInDomains[b-1] = true; } } } for(i=0; i<9; i++) { if(valsInDomains[i]) numUniqueVals++; valsInDomains[i] = false; } if(numUniqueVals < numEmptySquares) return false; numUniqueVals = numEmptySquares = 0; for(a = p.row - p.row%3; a < p.row - p.row%3 + 3; a++) { for(b = p.col - p.col%3; b < p.col - p.col%3 + 3; b++) { if(grid[a][b].GetValue() == 0) { numEmptySquares++; for(c=1; c<=9; c++) { if(grid[a][b].DomainContains(c)) valsInDomains[c-1] = true; } } } } for(i=0; i<9; i++) { if(valsInDomains[i]) numUniqueVals++; valsInDomains[i] = false; } if(numUniqueVals < numEmptySquares) return false; numUniqueVals = numEmptySquares = 0; } return true; } ostream& operator<<(ostream& out, SuDoKu& S) { for(unsigned r=0; r<9; r++) { if(r%3 == 0) out << "+-----+-----+-----+\n|"; else out << "| | | |\n|"; for(unsigned c=0; c<9; c++) { if(S.grid[r][c].GetValue() != 0) out << S.grid[r][c].GetValue(); else out << " "; if(c%3 == 2) out << "|"; else out << " "; } out << "\n"; } out << "+-----+-----+-----+\n"; return out; } //////////////////////////////////////////////////////////// SuDoKu RecursiveAllDifSearch(SuDoKu S, const unsigned r, const unsigned c) { if(S.Filled()) return S; if(S.grid[r][c].GetValue() != 0) return RecursiveAllDifSearch(S, r + 1*(c == 8), (c + 1) % 9); for(unsigned n=1; n<=9; n++) { if(S.grid[r][c].DomainContains(n)) { SuDoKu Su(S); if(Su.Set(r, c, n)) { if(Su.Filled()) return Su; else { Su = RecursiveAllDifSearch(Su, r + 1*(c == 8), (c + 1) % 9); if(Su.Filled()) return Su; } } } } return S; } int main() { unsigned x; SuDoKu *S, *G; ifstream in; in.open("SuDoKu.txt"); if(in.fail()) exit(0); QueryPerformanceFrequency(&ticksPerSecond); totalDoing = totalThinking = 0; while(in >> x) { S = new SuDoKu; G = new SuDoKu; G->grid[0][0].SetValue(x); S->Set(0, 0, x); for(unsigned i=1; i<81; i++) { in >> x; S->Set(i/9, i%9, x); G->grid[i/9][i%9].SetValue(x); } cout << *G; timeThinking = timeDoing = 0; QueryPerformanceCounter(&tick1); SuDoKu S2 = RecursiveAllDifSearch(*S, 0, 0); QueryPerformanceCounter(&tick2); time = tick2.QuadPart - tick1.QuadPart; timeDoing += time / ticksPerSecond.QuadPart; if(S2.Filled()) cout << S2; else cout << "No Solution\n"; cout << "Doing: " << timeDoing << " seconds\n"; cout << "Thinking: " << timeThinking << " seconds\n"; totalDoing += timeDoing; totalThinking += timeThinking; delete S; delete G; } cout << "Total Time Doing: " << totalDoing << " seconds\n"; cout << "Total Time Thinking: " << totalThinking << " seconds\n"; return 0; }