2 * Copyright 2007-2012, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
7 #include "SudokuGenerator.h"
15 #include "ProgressWindow.h"
16 #include "SudokuField.h"
17 #include "SudokuSolver.h"
20 #undef B_TRANSLATION_CONTEXT
21 #define B_TRANSLATION_CONTEXT "SudokuGenerator"
24 SudokuGenerator::SudokuGenerator()
29 SudokuGenerator::~SudokuGenerator()
35 SudokuGenerator::_HasOnlyOneSolution(SudokuField
& field
)
37 SudokuSolver
solver(&field
);
38 solver
.ComputeSolutions();
40 return solver
.CountSolutions() == 1;
45 SudokuGenerator::_Progress(BMessenger progress
, const char* text
,
48 BMessage
update(kMsgProgressStatusUpdate
);
50 update
.AddString("message", text
);
51 update
.AddFloat("percent", percent
);
52 progress
.SendMessage(&update
);
57 SudokuGenerator::Generate(SudokuField
* target
, uint32 fieldsLeft
,
58 BMessenger progress
, volatile bool *quit
)
60 // first step: generate a solved field - random brute force style
62 SudokuField
field(target
->BlockSize());
63 uint32 inputCount
= field
.Size() * field
.Size() / 3;
64 _Progress(progress
, B_TRANSLATE("Creating solvable field"), 5.f
);
69 // generate input field
73 for (uint32 i
= 0; i
< inputCount
; i
++) {
77 x
= rand() % field
.Size();
78 y
= rand() % field
.Size();
79 } while (!*quit
&& field
.ValueAt(x
, y
) != 0);
81 validMask
= field
.ValidMaskAt(x
, y
);
87 value
= rand() % field
.Size();
88 } while (!*quit
&& (validMask
& (1UL << value
)) == 0);
90 field
.SetValueAt(x
, y
, value
+ 1);
98 SudokuSolver
solver(&field
);
99 solver
.ComputeSolutions();
100 if (solver
.CountSolutions() > 0) {
101 // choose a random solution
102 field
.SetTo(solver
.SolutionAt(rand() % solver
.CountSolutions()));
110 // next step: try to remove as many fields as possible (and wished)
111 // that still have only a single solution
113 int32 removeCount
= field
.Size() * field
.Size() - fieldsLeft
;
114 bool tried
[field
.Size() * field
.Size()];
115 int32 tries
= field
.Size() * field
.Size() * 3 / 4;
116 memset(tried
, 0, sizeof(tried
));
117 _Progress(progress
, B_TRANSLATE("Searching for removable values"), 30.f
);
119 while (!*quit
&& removeCount
> 0 && tries
-- > 0) {
120 SudokuField
copy(field
);
124 x
= rand() % field
.Size();
125 y
= rand() % field
.Size();
126 } while (copy
.ValueAt(x
, y
) == 0 || tried
[x
+ y
* field
.Size()]);
128 tried
[x
+ y
* field
.Size()] = true;
129 copy
.SetValueAt(x
, y
, 0);
131 if (_HasOnlyOneSolution(copy
)) {
132 _Progress(progress
, NULL
, 100.f
- (70.f
* removeCount
/ 70.f
));
142 puts("check all remove");
143 for (uint32 y
= 0; y
< field
.Size(); y
++) {
144 for (uint32 x
= 0; x
< field
.Size(); x
++) {
145 if (tried
[x
+ y
* field
.Size()])
148 SudokuField
copy(field
);
149 copy
.SetValueAt(x
, y
, 0);
151 if (_HasOnlyOneSolution(copy
)) {
152 _Progress(progress
, NULL
,
153 100.f
- (70.f
* removeCount
/ 70.f
));
156 if (--removeCount
<= 0 || *quit
)
161 if (removeCount
<= 0 || *quit
)
164 printf(" remove count = %" B_PRId32
"\n", removeCount
);
167 // set the remaining values to be initial values
169 for (uint32 y
= 0; y
< field
.Size(); y
++) {
170 for (uint32 x
= 0; x
< field
.Size(); x
++) {
171 if (field
.ValueAt(x
, y
))
172 field
.SetFlagsAt(x
, y
, kInitialValue
);
179 target
->SetTo(&field
);