haiku/src/apps/sudoku/SudokuSolver.cpp

235 lines
3.7 KiB
C++

/*
* 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<SolutionStep*> 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<SolutionStep*> 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];
}