Phil Factor's Phrenetic Phoughts

Simple-Talk columnist
The wilder shores of Transact SQL    Phil on Twitter   Phil on SQL Server Central  Phil on BOS

The Sudoku Puzzle Generator

Published Thursday, May 18, 2006 5:38 PM

/* Even now, I can think of no rational explanation for writing this Sudoku puzzle generator other than a bout of insomnia whilst programming too hard on a difficult website. Basically, it just popped out.

Sudoku is a poular number puzzle. The aim of the puzzle is to place numbers from 1 through 9 in each cell of a 9×9 grid made up of 3×3 "regions".

When the puzzle is presented, some of the numbers are shown and others aren't. The shown ones are the "givens");

The person doing the puzzle has to fill in the blanks. Computers are much better at doing this sort of laborious work.

Each row, column, and region must contain only one instance of each number from 1 to 9.

The puzzle was first published in a U.S. puzzle magazine in 1979.

The name Sudoku is a trademark in Japan

This stored procedure makes repeated attempts at a solution. It generally finds a solution 50% of the time, but keeps at it until it finds one. Each one is, hopefully, different.

I get no pleasure from solving Sudoku puzzles but if you do, you can modify the source to blank out some of the numbers once a solution has been reached.

You will notice that you can turn it into a very good Sudoku solving system just my modding the program with the 'Givens' for the puzzle instead of allowing the program to choose them all.

The stored procedure uses a function that produces a random number. This is not allowed, but I do it to makes sure a random number is different in each row of the result.*/


ALTER  VIEW vRandomNumber
/*
*/
AS
SELECT 
RAND() AS RandomNumber
GO 



/* here is a little function, passing back an integer 
random number which is used to sort the result of a 
select statement randomly */
ALTER   function ufiRandom

@lower INT,
@upper INT

RETURNS INT AS 
BEGIN 

RETURN 
FLOOR(
       (
SELECT RandomNumber FROM vRandomNumber)
               *(
@Upper-@lower+1)+@Lower)

END  GO 



/* and here is the Sudoku table generator */
ALTER PROCEDURE spMakeSudokuTable
AS

--generate a table to hold the valid numbers
DECLARE @AcceptableValues TABLE (number INT)
INSERT INTO @acceptableValues SELECT 1
INSERT INTO @acceptableValues SELECT 2
INSERT INTO @acceptableValues SELECT 3
INSERT INTO @acceptableValues SELECT 4
INSERT INTO @acceptableValues SELECT 5
INSERT INTO @acceptableValues SELECT 6
INSERT INTO @acceptableValues SELECT 7
INSERT INTO @acceptableValues SELECT 8
INSERT INTO @acceptableValues SELECT 9

--and a table that represents the board. We have to do
--a pivot table to represent the board in a human way
--later on in the SP
DECLARE @SudokuTable TABLE 
       
(MyID INT IDENTITY(1,1), 
       
Value INT
       
[column] INT,
       
[row] INT
       
Region INT)

---and stock it with all the rows, columns and region values
INSERT INTO @SudokuTable (Value[Column]RowRegion)
       
SELECT NULL, [column].number,row.number,
                (((
row.number-1)/3)*3) + (([column].number-1)/3)+1
       
FROM @AcceptableValues [column] CROSS JOIN @AcceptableValues row

--put in all the possible values for each cell. These get whittled down
--as the board is constructed merely by flagging that they are already used
--in the region
DECLARE @PossibleValues  TABLE 
(MyID INT IDENTITY(1,1), Value INT[row] INT,[column] INT,Region INTused INT )

INSERT INTO @PossibleValues (value[row],[column],Regionused
       
SELECT number,[column],row,Region,0
       
FROM @SudokuTable CROSS JOIN @AcceptableValues

DECLARE @RowToSet INT
DECLARE 
@ColumnToSet INT
DECLARE 
@RegiontoSet INT
DECLARE 
@Value INT

--until we get a valid board----
WHILE EXISTS (SELECT FROM @SudokuTable WHERE value IS NULL)
    
BEGIN
    UPDATE 
@SudokuTable SET value=NULL--clean out any previous work
    
UPDATE @possibleValues SET used=0
       
--loop round constructing the board
    
WHILE EXISTS (SELECT FROM @PossibleValues WHERE used=0)
       
BEGIN
       
--are there any squares which have only
       --one possible value?
       
SELECT TOP @ColumnToSet=[column]
               
@RowToSet=row ,
               
@RegionToSet= MAX(Region)
               
FROM @PossibleValues 
               
WHERE used=
               
GROUP BY [column],row 
               
HAVING COUNT(*)=1
       
IF @@rowcount=0
       
--find one of the squares with
       --the most possibilities
               
SELECT TOP @ColumnToSet=[column]
                       
@RowToSet=row ,
                       
@RegiontoSet=MAX(Region)
                       
FROM @PossibleValues 
                       
WHERE used=
                       
GROUP BY [column],row 
                       
ORDER BY COUNT(*),dbo.ufiRandom(1,20DESC
       
--choose one at random
       
SELECT TOP @value=value FROM @PossibleValues
               
WHERE [column]= @ColumnToSet 
                       
AND row=@RowToSet AND used=0
               
ORDER BY dbo.ufiRandom(2,6)
       
--show that this square has no possibilities left
       
UPDATE @PossibleValues SET 
               
used=WHERE [column]=@ColumnToSet AND row=@RowToSet

       
--flag its usage in that row
       
UPDATE @PossibleValues SET 
               
used= WHERE value=@Value AND  row=@RowToSet

       
--flag its usage in that column
       
UPDATE @PossibleValues SET 
               
used=WHERE value=@Value AND [column]=@ColumnToSet

       
--flag its usage in that Region
       
UPDATE @PossibleValues SET 
               
used=WHERE value=@Value AND Region=@RegionToSet

       
--and enter it into the table
       
UPDATE @SudokuTable SET value=@Value
               
WHERE [column]=@ColumnToSet AND row=@RowToSet
       
END
    END

SELECT 
       
[a]=CONVERT(INT,MAX(CASE WHEN [Column]=THEN value ELSE END)),
       
[b]=CONVERT(INT,MAX(CASE WHEN [Column]=THEN value ELSE END) ),
       
[c]=CONVERT(INT,MAX(CASE WHEN [Column]=THEN value ELSE END)),
       
[d]=CONVERT(INT,MAX(CASE WHEN [Column]=THEN value ELSE END)),
       
[e]=CONVERT(INT,MAX(CASE WHEN [Column]=THEN value ELSE END)),
       
[f]=CONVERT(INT,MAX(CASE WHEN [Column]=THEN value ELSE END)),
       
[g]=CONVERT(INT,MAX(CASE WHEN [Column]=THEN value ELSE END)),
       
[h]=CONVERT(INT,MAX(CASE WHEN [Column]=THEN value ELSE END)),
       
[i]= CONVERT(INT,MAX(CASE WHEN [Column]=THEN value ELSE END))
FROM  @SudokuTable GROUP BY row

Comments

 

Andy Leonard said:

Phil, this is some slick code!

:{> Andy
May 22, 2006 12:12 AM
 

Applied Visual Studio Team System said:

Phil Factor demonstrates some snappy SQL programming with his Sudoku Generator - check it out!...
May 22, 2006 12:49 AM
 

sluggy said:

Wow!!??!! I recently wrote a solver in x86 asm, so i will use your generator to test my solver, and i bet i can solve way quicker than you can generate :)
May 26, 2006 2:34 PM
 

Phil Factor said:

I've now done a web interface to this which presents the puzzle showing just the 'givens'. Any moment now this will be appearing on the new wonderful Simple-Talk site. It works quite fast enough for me.
I think any SQL Server programmer will retort that the important time it the time it takes to develop this sort of stuff. As I get older I get less tolerant of the delay between the idea and the completion.
The code above can be used to solve a sudoku puzzle, and I was hoping that someone else would contribute that.
May 27, 2006 11:47 AM
You need to sign in to comment on this blog


















<May 2006>
SuMoTuWeThFrSa
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910
Niklaus Wirth: Geek of the Week
 It is difficult to begin to estimate the huge extent of the contribution that Niklaus Wirth has made to... Read more...

Building an Exchange Server 2007 environment
 Of course, changing a 32,000 mailbox system, based in 40 Exchange Servers, to a centralised 25,000... Read more...

Manage Stress Before it Kills You
 The key to a long career in IT is in learning how to cope adaptively with stress. Matt Simmons, like... Read more...

Expecting the Worst
 Optimists are often disappointed Read more...

To Boldly Ask IT for Development Work
 Phil has always been mystified by the way that, in Science-Fiction films, the crew of space-ships are... Read more...