* Copyright 2007-2012, Axel DΓΆrfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
#include "SudokuGenerator.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Catalog.h>
#include "ProgressWindow.h"
#include "SudokuField.h"
#include "SudokuSolver.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "SudokuGenerator"
SudokuGenerator::SudokuGenerator()
{
}
SudokuGenerator::~SudokuGenerator()
{
}
bool
SudokuGenerator::_HasOnlyOneSolution(SudokuField& field)
{
SudokuSolver solver(&field);
solver.ComputeSolutions();
return solver.CountSolutions() == 1;
}
void
SudokuGenerator::_Progress(BMessenger progress, const char* text,
float percent)
{
BMessage update(kMsgProgressStatusUpdate);
if (text)
update.AddString("message", text);
update.AddFloat("percent", percent);
progress.SendMessage(&update);
}
void
SudokuGenerator::Generate(SudokuField* target, uint32 fieldsLeft,
BMessenger progress, volatile bool *quit)
{
SudokuField field(target->BlockSize());
uint32 inputCount = field.Size() * field.Size() / 3;
_Progress(progress, B_TRANSLATE("Creating solvable field"), 5.f);
while (!*quit) {
field.Reset();
uint32 validMask = 0;
for (uint32 i = 0; i < inputCount; i++) {
uint32 x;
uint32 y;
do {
x = rand() % field.Size();
y = rand() % field.Size();
} while (!*quit && field.ValueAt(x, y) != 0);
validMask = field.ValidMaskAt(x, y);
if (validMask == 0)
break;
uint32 value;
do {
value = rand() % field.Size();
} while (!*quit && (validMask & (1UL << value)) == 0);
field.SetValueAt(x, y, value + 1);
}
if (validMask == 0)
continue;
SudokuSolver solver(&field);
solver.ComputeSolutions();
if (solver.CountSolutions() > 0) {
field.SetTo(solver.SolutionAt(rand() % solver.CountSolutions()));
break;
}
}
if (*quit)
return;
int32 removeCount = field.Size() * field.Size() - fieldsLeft;
bool tried[field.Size() * field.Size()];
int32 tries = field.Size() * field.Size() * 3 / 4;
memset(tried, 0, sizeof(tried));
_Progress(progress, B_TRANSLATE("Searching for removable values"), 30.f);
while (!*quit && removeCount > 0 && tries-- > 0) {
SudokuField copy(field);
uint32 x;
uint32 y;
do {
x = rand() % field.Size();
y = rand() % field.Size();
} while (copy.ValueAt(x, y) == 0 || tried[x + y * field.Size()]);
tried[x + y * field.Size()] = true;
copy.SetValueAt(x, y, 0);
if (_HasOnlyOneSolution(copy)) {
_Progress(progress, NULL, 100.f - (70.f * removeCount / 70.f));
field.SetTo(©);
removeCount--;
}
}
if (*quit)
return;
if (tries <= 0) {
puts("check all remove");
for (uint32 y = 0; y < field.Size(); y++) {
for (uint32 x = 0; x < field.Size(); x++) {
if (tried[x + y * field.Size()])
continue;
SudokuField copy(field);
copy.SetValueAt(x, y, 0);
if (_HasOnlyOneSolution(copy)) {
_Progress(progress, NULL,
100.f - (70.f * removeCount / 70.f));
field.SetTo(©);
if (--removeCount <= 0 || *quit)
break;
}
}
if (removeCount <= 0 || *quit)
break;
}
printf(" remove count = %" B_PRId32 "\n", removeCount);
}
for (uint32 y = 0; y < field.Size(); y++) {
for (uint32 x = 0; x < field.Size(); x++) {
if (field.ValueAt(x, y))
field.SetFlagsAt(x, y, kInitialValue);
}
}
if (*quit)
return;
target->SetTo(&field);
}