/* * Copyright 2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved. * Distributed under the terms of the MIT License. */ #include "SudokuSolver.h" #include "SudokuField.h" #include "Stack.h" struct SolutionStep { public: SolutionStep(const SudokuField* field); SolutionStep(const SolutionStep& other); ~SolutionStep(); void ToFirstUnset(); bool ToNextUnset(); void SetSolvedFields(); SudokuField* Field() { return fField; } uint32 X() { return fX; } uint32 Y() { return fY; } private: SudokuField* fField; uint32 fX; uint32 fY; }; typedef std::vector StepList; uint32 bit_count(uint32 value) { uint32 count = 0; while (value > 0) { if (value & 1) count++; value >>= 1; } return count; } // #pragma mark - SolutionStep::SolutionStep(const SudokuField* _field) { fField = new SudokuField(*_field); fX = 0; fY = 0; } SolutionStep::SolutionStep(const SolutionStep& other) { fField = new SudokuField(*other.fField); fX = other.fX; fY = other.fY; } SolutionStep::~SolutionStep() { delete fField; } void SolutionStep::ToFirstUnset() { for (uint32 y = 0; y < fField->Size(); y++) { for (uint32 x = 0; x < fField->Size(); x++) { if (!fField->ValueAt(x, y)) { uint32 validMask = fField->ValidMaskAt(x, y); if (bit_count(validMask) == 1) { // If the chosen value is already solved, we set its // value here and go on - this makes sure the first // unset we return has actually more than one possible // value uint32 value = 0; while ((validMask & (1UL << value)) == 0) { value++; } fField->SetValueAt(x, y, value + 1, true); continue; } fX = x; fY = y; return; } } } } bool SolutionStep::ToNextUnset() { for (uint32 y = fY; y < fField->Size(); y++) { for (uint32 x = 0; x < fField->Size(); x++) { if (y == fY && x == 0) { x = fX; continue; } if (!fField->ValueAt(x, y)) { fX = x; fY = y; return true; } } } return false; } // #pragma mark - SudokuSolver::SudokuSolver(SudokuField* field) : fField(field) { } SudokuSolver::SudokuSolver() : fField(NULL) { } SudokuSolver::~SudokuSolver() { // we don't own the field but the solutions _MakeEmpty(); } void SudokuSolver::_MakeEmpty() { for (uint32 i = 0; i < fSolutions.size(); i++) { delete fSolutions[i]; } } void SudokuSolver::SetTo(SudokuField* field) { fField = field; } void SudokuSolver::ComputeSolutions() { _MakeEmpty(); // We need to check if generating a solution is affordable with a // brute force algorithm like this one uint32 set = 0; for (uint32 y = 0; y < fField->Size(); y++) { for (uint32 x = 0; x < fField->Size(); x++) { if (fField->ValueAt(x, y)) set++; } } if (set < fField->Size() * fField->Size() / 6) return; Stack stack; SolutionStep* step = new SolutionStep(fField); step->ToFirstUnset(); stack.Push(step); uint32 count = 0; // brute force version while (stack.Pop(&step)) { uint32 x = step->X(); uint32 y = step->Y(); uint32 validMask = step->Field()->ValidMaskAt(x, y); count++; if (step->ToNextUnset()) { if (validMask != 0) { // generate further steps for (uint32 i = 0; i < fField->Size(); i++) { if ((validMask & (1UL << i)) == 0) continue; SolutionStep* next = new SolutionStep(*step); next->Field()->SetValueAt(x, y, i + 1, true); stack.Push(next); } } } else if (step->Field()->IsSolved()) fSolutions.push_back(new SudokuField(*step->Field())); delete step; } //printf("evaluated %lu steps\n", count); } uint32 SudokuSolver::CountSolutions() { return fSolutions.size(); } SudokuField* SudokuSolver::SolutionAt(uint32 index) { return fSolutions[index]; }