summaryrefslogtreecommitdiff
path: root/generator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'generator.cpp')
-rw-r--r--generator.cpp128
1 files changed, 128 insertions, 0 deletions
diff --git a/generator.cpp b/generator.cpp
new file mode 100644
index 0000000..47e5e35
--- /dev/null
+++ b/generator.cpp
@@ -0,0 +1,128 @@
+/*
+ * Sudoku: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: generator.cpp 11 2005-10-28 01:00:01Z tom $
+ */
+
+#define USE_RAND
+#include "generator.h"
+#include "solver.h"
+#include "backtrack.h"
+#include "puzzle.h"
+#include <assert.h>
+
+using namespace Sudoku;
+using namespace BackTrack;
+
+
+//--- class Sudoku::Generator --------------------------------------------------
+
+/** Constructor */
+Generator::Generator(Puzzle& puzzle, unsigned int givens_count,
+ bool symmetric, unsigned int max_iter) :
+ Algorithm(*this, max_iter), puzzle(puzzle), symmetric(symmetric)
+{
+ assert(givens_count <= SDIM);
+
+ // Search a random Sudoku solution.
+ for (bool found = false; !found;)
+ {
+ sudoku.reset();
+ Solver solver(sudoku, true);
+ solver.find_next_solution();
+ found = solver.solution_is_valid();
+ }
+
+ // If symmetric pos_list contains only the first halve of all positions.
+ pos_count = SDIM;
+ free_count = SDIM - givens_count;
+ free_center = symmetric && pos_count % 2 != 0 && free_count % 2 != 0;
+ if (symmetric)
+ pos_count /= 2, free_count /= 2;
+
+ // Fill pos_list with positions in random order.
+ bool list[pos_count];
+ unsigned int p, i, c;
+ for (p = 0; p < pos_count; ++p)
+ list[p] = true;
+ for (i = 0; i < pos_count; ++i)
+ {
+ c = rand(pos_count - i) + 1;
+ for (p = 0; p < pos_count; ++p)
+ if (list[p])
+ if (--c == 0)
+ break;
+ assert(p < pos_count);
+ list[p] = false;
+ pos_list[i] = p;
+ }
+}
+
+/** Set the element to the first sibling. */
+void Generator::set_first_at(unsigned int level)
+{
+ assert(level < free_count);
+ free_list[level] = 0;
+}
+
+/** Set the element to the next sibling. */
+void Generator::set_next_at(unsigned int level)
+{
+ assert(level < free_count);
+ ++free_list[level];
+}
+
+/** Reset the element. */
+void Generator::reset_at(unsigned int level)
+{
+}
+
+/** Check if the element is set to the last sibling. */
+bool Generator::is_last_at(unsigned int level) const
+{
+ assert(level < free_count);
+ return free_list[level] >= pos_count - 1;
+}
+
+/** Check if the element is valid (following elements ignored). */
+bool Generator::is_valid_at(int level) const
+{
+ assert(level < int(free_count));
+
+ // free_list contains ordered indices to pos_list.
+ if (level > 0 && free_list[level] <= free_list[level - 1])
+ return false;
+ if (level >= 0 && free_list[level] > pos_count - (free_count - level))
+ return false;
+
+ // Fill list with marks for givens.
+ bool given_marks[SDIM];
+ int i;
+ for (i = 0; i < SDIM; ++i)
+ given_marks[i] = true;
+ for (i = 0; i <= level; ++i)
+ {
+ Pos p = pos_list[free_list[i]];
+ given_marks[p] = false;
+ if (symmetric)
+ given_marks[p.symmetric()] = false;
+ }
+ if (free_center)
+ given_marks[Pos::center()] = false;
+
+ // Set givens in puzzle and check if it has only one solution.
+ puzzle.set_givens(sudoku, given_marks);
+ Solver solver(puzzle);
+ solver.find_next_solution();
+ assert(solver.solution_is_valid());
+ solver.find_next_solution();
+ return !solver.solution_is_valid();
+}
+
+/** Check if the level is the last possible level. */
+bool Generator::is_last_level(int level) const
+{
+ return level >= int(free_count) - 1;
+}