#include using std::ostream; using std::cout; using std::cin; #include LARGE_INTEGER ticksPerSecond; LARGE_INTEGER tick1, tick2; double timeThinking(0), timeDoing(0), time, totalThinking(0), totalDoing(0); bool timing = false; #include using std::ifstream; class Domain { public: Domain(); Domain(const Domain& D); void AddInterference(const unsigned n); unsigned RemoveInterference(const unsigned n); unsigned NumInterferencesAt(const unsigned n); unsigned Size(); Domain& operator=(const Domain& D); ~Domain(); private: unsigned* d; unsigned size; }; Domain::Domain() :size(9) { d = new unsigned int[9]; for(unsigned j=0; j<9; j++) d[j] = 0; } Domain::Domain(const Domain& D) :size(D.size) { d = new unsigned int[9]; for(unsigned j=0; j<9; j++) d[j] = D.d[j]; } void Domain::AddInterference(const unsigned n) { if(d[n-1] == 0) size--; d[n-1]++; } unsigned Domain::RemoveInterference(const unsigned n) { if(d[n-1] == 1) size++; d[n-1]--; return size; } unsigned Domain::NumInterferencesAt(const unsigned n) { return d[n-1]; } unsigned Domain::Size() { return size; } Domain& Domain::operator=(const Domain& D) { if(&D == this) return *this; size = D.size; for(unsigned j=0; j<9; j++) d[j] = D.d[j]; return *this; } Domain::~Domain() { delete [] d; } //////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////// class Square { public: Square(); Square(const Square& S); void SetUpDomain(); Domain* GetDomain(); unsigned int GetValue() const; void SetValue(const unsigned int x, bool p = false); Square& operator=(const Square& S); bool IsPermanent(); ~Square(); private: bool permanent; unsigned int val; Domain* dom; }; Square::Square() :dom(NULL), val(0), permanent(false) {} Square::Square(const Square& S) :val(S.val), permanent(S.permanent) { if(S.dom != NULL) dom = new Domain(*(S.dom)); else dom = NULL; } void Square::SetUpDomain() { if(dom == NULL) dom = new Domain; } Domain* Square::GetDomain() { return dom; } unsigned int Square::GetValue() const { return val; } void Square::SetValue(const unsigned int x, bool p) { val = x; permanent = p; } Square& Square::operator=(const Square& S) { if(this == &S) return *this; delete dom; if(S.dom != NULL) dom = new Domain(*(S.dom)); else dom = NULL; val = S.val; permanent = S.permanent; return *this; } bool Square::IsPermanent() { return permanent; } Square::~Square() { delete dom; } //////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////// class SuDoKu { public: SuDoKu(); SuDoKu(SuDoKu& S); bool Set(const unsigned row, const unsigned col, const unsigned val, const bool permanent = false); Square* GetSquare(unsigned row, unsigned col); bool Test(unsigned row, unsigned col, unsigned val); bool Filled(); void Show(ostream& out); SuDoKu& operator=(SuDoKu& S); ~SuDoKu(); private: Square** grid; }; SuDoKu::SuDoKu() { grid = new Square*[9]; for(unsigned i=0; i<9; i++) grid[i] = new Square[9]; } SuDoKu::SuDoKu(SuDoKu& S) { grid = new Square*[9]; for(unsigned i=0; i<9; i++) grid[i] = new Square[9]; for(unsigned r=0; r<9; r++) for(unsigned c=0; c<9; c++) grid[r][c] = Square(S.grid[r][c]); } bool SuDoKu::Set(const unsigned row, const unsigned col, const unsigned val, const bool permanent) { if(val == 0) { if(grid[row][col].GetValue() != 0 && grid[row][col].GetDomain() != NULL) { for(unsigned x=0; x<9; x++) { if(x != row) grid[x][col].GetDomain()->RemoveInterference(grid[row][col].GetValue()); if(x != col) grid[row][x].GetDomain()->RemoveInterference(grid[row][col].GetValue()); } for(unsigned y = row - row%3; y < row - row%3 + 3; y++) for(unsigned z = col - col%3; z < col - col%3 + 3; z++) if(y != row && z != col) grid[y][z].GetDomain()->RemoveInterference(grid[row][col].GetValue()); } grid[row][col].SetValue(val); return true; } else { if(grid[row][col].GetValue() == val) return true; if(timing) { QueryPerformanceCounter(&tick2); time = (tick2.QuadPart - tick1.QuadPart); time /= (double) ticksPerSecond.QuadPart; timeDoing += time; QueryPerformanceCounter(&tick1); } grid[row][col].SetValue(val, permanent); bool puzzleStillSolvable = true; for(unsigned a=0; a<9; a++) { if(a != row) { grid[a][col].GetDomain()->AddInterference(val); if(grid[a][col].GetDomain()->Size() == 0) puzzleStillSolvable = false; } if(a != col) { grid[row][a].GetDomain()->AddInterference(val); if(grid[col][a].GetDomain()->Size() == 0) puzzleStillSolvable = false; } } for(unsigned b = row - row%3; b < row - row%3 + 3; b++) for(unsigned c = col - col%3; c < col - col%3 + 3; c++) if(b != row && c != col) { grid[b][c].GetDomain()->AddInterference(val); if(grid[b][c].GetDomain()->Size() == 0) puzzleStillSolvable = false; } if(timing) { QueryPerformanceCounter(&tick2); time = (tick2.QuadPart - tick1.QuadPart); time /= ticksPerSecond.QuadPart; timeThinking += time; QueryPerformanceCounter(&tick1); } return puzzleStillSolvable; } } Square* SuDoKu::GetSquare(unsigned row, unsigned col) { return &(grid[row][col]); } bool SuDoKu::Test(const unsigned row, const unsigned col, const unsigned val) { unsigned r, c; for(r=0; r<9; r++) if(r != row && grid[r][col].GetValue() == val) return false; for(c=0; c<9; c++) if(c != col && grid[row][c].GetValue() == val) return false; for(r = row - row%3; r < row - row%3 + 3; r++) for(c = col - col%3; c < col - col%3 + 3; c++) if(r != row && c != col && grid[r][c].GetValue() == val) return false; return true; } bool SuDoKu::Filled() { for(unsigned r=0; r<9; r++) for(unsigned c=0; c<9; c++) if(grid[r][c].GetValue() == 0) return false; return true; } void SuDoKu::Show(ostream& out) { for(unsigned r=0; r<9; r++) { if(r%3 == 0) out << "+-----+-----+-----+\n|"; else out << "| | | |\n|"; for(unsigned c=0; c<9; c++) { if(grid[r][c].GetValue() != 0) out << grid[r][c].GetValue(); else out << " "; if(c%3 == 2) out << "|"; else out << " "; } out << "\n"; } out << "+-----+-----+-----+\n"; } SuDoKu& SuDoKu::operator=(SuDoKu& S) { if(this == &S) return *this; for(unsigned i=0; i<9; i++) delete [] grid[i]; delete [] grid; grid = new Square*[9]; for(unsigned j=0; j<9; j++) { grid[j] = new Square[9]; for(unsigned k=0; k<9; k++) grid[j][k] = S.grid[j][k]; } return *this; } SuDoKu::~SuDoKu() { for(unsigned i=0; i<9; i++) delete [] grid[i]; delete [] grid; } char* asdf = new char[10]; //////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////// bool RecursiveForwardCheckingSearch(SuDoKu& S, const unsigned r, const unsigned c) { if(S.GetSquare(r, c)->IsPermanent()) return RecursiveForwardCheckingSearch(S, r + 1*(c == 8), (c + 1) % 9); for(unsigned n=1; n<=9; n++) { if(S.GetSquare(r, c)->GetDomain()->NumInterferencesAt(n) == 0) { bool stillSolvable = S.Set(r, c, n); if(S.Filled()) return true; /*S.Show(cout); cin.getline(asdf, 1);*/ if(!stillSolvable) S.Set(r, c, 0); else if(RecursiveForwardCheckingSearch(S, r + 1*(c == 8), (c + 1) % 9)) return true; S.Set(r, c, 0); } } return false; } SuDoKu* ForwardCheckingSearch(SuDoKu S) { if(RecursiveForwardCheckingSearch(S, 0, 0)) return new SuDoKu(S); else return NULL; } bool RecursiveBacktrackingSearch(SuDoKu& S, unsigned r, unsigned c) { if(S.GetSquare(r, c)->IsPermanent()) return RecursiveBacktrackingSearch(S, r + 1*(c == 8), (c + 1) % 9); for(unsigned n=1; n<=9; n++) { if(S.Test(r, c, n)) { S.GetSquare(r, c)->SetValue(n); //S.Show(cout); //cin.getline(asdf, 1); if(S.Filled()) return true; else if(RecursiveBacktrackingSearch(S, r + 1*(c == 8), (c + 1) % 9)) return true; } } S.GetSquare(r, c)->SetValue(0); return false; } SuDoKu* BacktrackingSearch(SuDoKu S) { if(RecursiveBacktrackingSearch(S, 0, 0)) return new SuDoKu(S); else return NULL; } int main() { SuDoKu *S, *p; unsigned x; QueryPerformanceFrequency(&ticksPerSecond); ifstream in; in.open("SuDoKu.txt"); if(in.fail()) exit(0); while(in >> x) { S = new SuDoKu; for(unsigned i=0; i<81; i++) S->GetSquare(i/9, i%9)->SetUpDomain(); S->Set(0, 0, x, true); for(unsigned i=1; i<81; i++) { in >> x; S->Set(i/9, i%9, x, true); } S->Show(cout); timing = true; QueryPerformanceCounter(&tick1); p = BacktrackingSearch(*S); QueryPerformanceCounter(&tick2); timing = false; time = (tick2.QuadPart - tick1.QuadPart); time /= ticksPerSecond.QuadPart; timeDoing += time; if(p) p->Show(cout); else cout << "No Solution Found\n"; cout << "Doing: " << timeDoing << " seconds\n"; //cout << "Thinking: " << timeThinking << " seconds\n"; totalDoing += timeDoing; //totalThinking += timeThinking; delete S; delete p; } cout << "Total Time Doing: " << totalDoing << " seconds\n"; //cout << "Total Time Thinking: " << totalThinking << " seconds\n"; return 0; }