views:

311

answers:

3

I am trying to create my own normal 9x9 sudoku puzzle.

I divided the problem into two parts -

  1. creating a fully filled sudoku, and
  2. removing unnecessary numbers from the grid

Right now, I am stuck with the first part.


This is the algorithm I use in brief:

a) first of all I choose a number (say 1), generate a random cell position, and place it there if

  • the cell is not already occupied, and
  • if the row does not already have the number, and
  • if the column does not already have the number, and
  • if the 3x3 box does not already have the number

b) now I check for a situation in which in a row, or a column or a box, only one place is empty and I fill that

c) I check that if there is a number that in not present in a box but is present in the boxes in the same row and the same column (i am talking about 3x3 boxes here), the number's place is fixed and I fill it.

d) I repeat the above steps until every number appears nine times on the grid.


The problem I am facing is that, more than often I am getting an intermediate situation like this:

 0  1  0 | 0  0  3 | 0[4/2]0 
 0 [2] 0 | 0 [4] 1 | 3  0  0 
 3  0 [4]|[2] 0  0 | 0  0  1 
---------+---------+---------
 2  0  3 | 0  5  4 | 0  1  0 
 0  0  1 | 3  0  2 |[4] 0  0 
 0  4  0 | 0  1  0 |[2] 3  0 
---------+---------+---------
 1  0  2 | 0  3  0 | 0  0 [4] 
 4  3  0 | 1  0  0 | 0  0 [2] 
 5  0  0 | 4  2  0 | 1  0  3

See the place with [4/2] written? that is the place of 2 as well as 4 because of the boxes marked [].

What can I do to avoid getting in this situation (because this situation is a deadlock - I cannot move further)

A: 

If you've reached a contradictory state where a cell if both 2 and 4 some of your other 2s and 4s must be placed wrongly. You need to rollback and try some different solutions.

Sounds like you might have an algorithm problem? Some good stuff here.

monorailkitty
yes, you are right, i need to roll back. What can I do to avoid getting in this situation ever?
Amoeba
i don't think you can avoid it, sudoku inherently has a tree like path to the solution, sometimes you'll have to go back and take another branch because you can't know upfront which one to take (this is not true for simple soduko's, but advanced one's are often like this...)
Sander Versluys
Eventually you'll get into a situation where you can no longer make certain decisions. Let's say you've deduced that a certain cell is either 4, 5 or 6.You try 4. It doesn't work out. you undo all the changes you made since assuming 4 and then try 5. Keep track of your changes by placing them on a stack then pop them off to unroll.I make it sound so simple...
monorailkitty
okay... and I always thought that solving a sudoku would be harder... turns out creating it is not any easier!!
Amoeba
+3  A: 

There's another way to generate sudoku puzzles: Start with a known good grid - any one will do - then randomly 'shuffle' it by applying operations that don't destroy the invariants. Valid operations include:

  • Swapping rows within a block
  • Swapping columns within a block
  • Swapping entire rows of blocks (eg, first 3, middle 3, last 3 rows)
  • Swapping entire columns of blocks
  • Swapping all instances of one number with another
  • Reflecting the board
  • Rotating the board

With these operations, you can generate a very large range of possible boards. You need to be careful about how you apply the operations, however - much like the naive shuffle, it's easy to write an algorithm that makes some boards more likely than others. A technique similar to the Knuth shuffle may help here.

Edit: It has been pointed out in the comments that these operations alone aren't sufficient to create every possible grid.

Nick Johnson
Doesn't a sudoku puzzle have the additional requirement that there mustn't be more than 1 solution?
Georg
That's a property of part 2 (erasing givens), not of the fully filled out board.
Nick Johnson
This method can generate a *huge* number of variations of a given board, but surprisingly, it cannot generate every possible one - at least not without an even more huge number of initial boards to start with. One of the invariants preserved by the transformations is the difficulty level. Reflecting the board is a redundant option - you can do that by row/column swapping.
Steve314
I should clarify - I believe you can generate any fully filled board by this transform method, but consider how many ways there are to leave gaps empty for any particular complete solution - that's the bit where you can't cover every combination just by transforms from one start position, and that's the bit that determines the human difficulty level. For a start, more difficult puzzles generally have more cells left empty at the start - swaps and rotates leave the number of empty cells unchanged.
Steve314
"With these operations, you can generate any possible sudoku board." Do you have a proof for that?
starblue
@Steve314: The OP explicitly broke the generation of a sudoku _puzzle_ into two parts - generating a filled board, and eliminating knowns - and then asked a question specifically about the first part only. Hence, my answer only addresses the first part.
Nick Johnson
@starblue: I don't have a formal proof to hand, no. I could be wrong, but I'm fairly sure those operations are sufficient.
Nick Johnson
@Nick Johnson: in programming the "fairly sure" always ring the "famous last words" in my mind :) Great idea though, much easier than trying to build a grid from scratch.
Matthieu M.
@Matthieu: More like in math or computer science than in programming, but you're right. :)
Nick Johnson
I've done the math. There's 6 permutations of the three block-columns, and 6 each of the columns within blocks, giving 6^4 so far. The same for rows, giving 6^8. These can handle reflections and 180 degree rotations, but the zero and 90 degree rotates are potentially useful, giving 2*6^8. There are 9! ways to permute the digit-to-digit mapping, giving a total of 1,218,998,108,160 (1.2 trillion) permutations. This is a strict upper bound - some are equivalent transforms - yet much less than in http://en.wikipedia.org/wiki/Mathematics_of_Sudoku#Enumerating_Sudoku_solutions
Steve314
From that Wikipedia link, it appears you need 5,472,730,538 different starting points to transform from, even for completely filled grids.
Steve314
In that case, I retract my original statement. Damn. :P
Nick Johnson
Although this wasn't what I was looking for at first, doing mutations of a known grid is actually a good way. Its fast and I dont have to backtrack!
Amoeba
+1  A: 

You will always get that situation. You need a recursive backtracking search to solve it.

Basically, the only way to determine whether a particular digit really is valid for a cell is to continue the search and see what happens.

Backtracking searches are normally done using recursive calls. Each call will iterate through the (possibly) still valid options for one cell, recursing to evaluate all the options for the next cell. When you can't continue, backtracking means returning from the current call - erasing any digit you tested out for that cell first, of course.

When you find a valid solution, either save it and backtrack to continue (ie find alternatives), or break out of all the recursive calls to finish. Success in a recursive backtracking search is a special case where throwing an exception for success is IMO a good idea - it is exceptional for a particular call to succeed, and the code will be clearer.

If generating a random board, iterate the options in a particular recursive call (for a particular cell) in random order.

The same basic algorithm also applies for a partly completed board (ie to solve existing sodoku) - when evaluating a cell that already has a digit, well, that's the only option for that cell so recurse for the next cell.

Here's the backtracking search from a solver I wrote once - a lot is abstracted out, but hopefully that just makes the principle clearer...

size_t Board::Rec_Search (size_t p_Pos)
{
  size_t l_Count = 0;

  if (p_Pos == 81)  //  Found a solution
  {
    l_Count++;

    std::cout << "------------------------" << std::endl;
    Draw ();
    std::cout << "------------------------" << std::endl;
  }
  else
  {
    if (m_Board [p_Pos] == 0)  //  Need to search here
    {
      size_t l_Valid_Set = Valid_Set (p_Pos);

      if (l_Valid_Set != 0)  //  Can only continue if there are possible digits
      {
        size_t  l_Bit = 1;  //  Scan position for valid set

        for (size_t i = 1; i <= 9; i++)
        {
          if (l_Valid_Set & l_Bit)
          {
            Set_Digit  (p_Pos, i);
            l_Count += Rec_Search (p_Pos + 1);
          }

          l_Bit <<= 1;
        }

        Clr_Digit (p_Pos);  //  Ensure cleared properly for backtracking
      }
    }
    else  //  Already filled in - skip
    {
      l_Count += Rec_Search (p_Pos + 1);
    }
  }

  return l_Count;
}
Steve314