Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
Author |
Topic |
nr
SQLTeam MVY
12543 Posts |
Posted - 2005-05-27 : 19:51:43
|
Heard of this?It's in a lot of papers in the uk at the moment.You have to fill a 9x9 grid with the numbers 1 to 9 such that the digits appear once and only once in each row, column and box (the 9x9 square is divided into 9 3x3 boxes)You will receive a square with some numbers already filled in.The challenge is to solve any puzzle using sql server.The first part is to devise a notation suitable for the problemThen to form the queries to solve it.See http://www.sudoku.org.uk/backpuzzles.htmfor sample puzzlesI'll post my attempt (which doesn't work all the time at the moment) later on.My mistake - looks like it does work.==========================================Cursors are useful if you don't know sql.DTS can be used in a similar way.Beer is not cold and it isn't fizzy. |
|
nr
SQLTeam MVY
12543 Posts |
Posted - 2005-05-27 : 20:04:59
|
p.s. I'm not very proud of my solution. It runs a few queries in a loop until it completes all obvious things then guesses repeatedly until it gets the solution - running the initial queries on each guess.I'd like to put in more queries to remove more options but it gets a bit complicated.Also the incentive isn't there once I have a solution.Excluding the grid setup it's les than 100 lines.==========================================Cursors are useful if you don't know sql.DTS can be used in a similar way.Beer is not cold and it isn't fizzy. |
|
|
Arnold Fribble
Yak-finder General
1961 Posts |
Posted - 2005-05-28 : 05:22:24
|
Not like this, then? DECLARE @x tinyint, @y tinyint, @prefix varchar(40)PRINT 'CREATE TABLE N (n tinyint PRIMARY KEY)'SET @prefix = 'INSERT INTO N SELECT 'SET @x = 1WHILE @x <= 9 BEGIN PRINT @prefix + CAST(@x AS varchar) SET @prefix = 'UNION ALL SELECT ' SET @x = @x +1ENDPRINT ''PRINT 'SELECT TOP 1 * FROM'SET @y = 0WHILE @y < 9 BEGIN SET @x = 0 WHILE @x < 9 BEGIN PRINT ' (SELECT n AS n' + CAST(@y AS varchar) + CAST(@x AS varchar) + ' FROM N) AS N' + CAST(@y AS varchar) + CAST(@x AS varchar) + CASE WHEN @x = 8 AND @y = 8 THEN '' ELSE ',' END SET @x = @x + 1 END SET @y = @y + 1ENDDECLARE @x1 tinyint, @y1 tinyint, @distinct varchar(300), @dsep char(1)SET @prefix = 'WHERE'SET @y = 0WHILE @y < 9 BEGIN SET @x = 0 WHILE @x < 9 BEGIN SET @distinct = '' SET @dsep = '(' SET @y1 = @y WHILE @y1 < 9 BEGIN SET @x1 = @x WHILE @x1 < 9 BEGIN IF (NOT(@x1=@x) OR NOT(@y1=@y)) AND (@x1=@x OR @y1=@y OR (@x1/3 = @x/3 AND @y1/3 = @y/3)) BEGIN SET @distinct = @distinct + @dsep + 'n' + CAST(@y1 AS varchar) + CAST(@x1 AS varchar) SET @dsep = ',' END SET @x1 = @x1 + 1 END SET @y1 = @y1 + 1 END IF @distinct <> '' PRINT @prefix + ' n' + CAST(@y AS varchar) + CAST(@x AS varchar) + ' NOT IN ' + @distinct + ')' SET @prefix = ' AND' SET @x = @x + 1 END SET @y = @y + 1ENDDECLARE @grid varchar(200)SET @grid = ' 5 7 ' + ' 61 39 ' + '7 5 8' + ' 839 716 ' + ' ' + ' 218 439 ' + '3 9 6' + ' 75 82 ' + ' 8 4 'SET @y = 0WHILE @y < 9 BEGIN SET @x = 0 WHILE @x < 9 BEGIN DECLARE @ns char(1) SET @ns = SUBSTRING(@grid, @y*9+@x+1, 1) IF ISNUMERIC(@ns) = 1 PRINT ' AND n' + CAST(@y AS varchar) + CAST(@x AS varchar) + ' = ' + @ns SET @x = @x + 1 END SET @y = @y + 1END |
|
|
nr
SQLTeam MVY
12543 Posts |
Posted - 2005-05-28 : 05:49:34
|
Interesting - when I try to run the output from that it doesn't complete but uses all my cpu.How long should it take?==========================================Cursors are useful if you don't know sql.DTS can be used in a similar way.Beer is not cold and it isn't fizzy. |
|
|
Arnold Fribble
Yak-finder General
1961 Posts |
Posted - 2005-05-28 : 06:27:21
|
quote: How long should it take?
Probably until your computer stops working or you get bored and cancel it. While it may be good enough for finding Yaks, I don't think the query optimizer's up to the job of solving constraint satisfaction problems of that size.So unless there are some other constraints (or ways of modeling the problem) that massively reduce the search space, I think this approach is a nonrunner. |
|
|
nr
SQLTeam MVY
12543 Posts |
Posted - 2005-05-28 : 07:43:20
|
Doesn't it find values that aren't in the other cells?If so that doesn't get far in solving the problem.I took the approach of finding values that couldn't be in cells - then checked different cases (well only 2 at the moment) until there was one value per cell.It seems to work for the simple games but not for the more complicated.The difficult one I use for testing I haven't solved myself sp don't know what tests to model.==========================================Cursors are useful if you don't know sql.DTS can be used in a similar way.Beer is not cold and it isn't fizzy. |
|
|
Arnold Fribble
Yak-finder General
1961 Posts |
Posted - 2005-05-28 : 10:04:05
|
quote: Doesn't it find values that aren't in the other cells?If so that doesn't get far in solving the problem.
Oh, it would give you the right solution(s) if it ever finished. It's just not going to finish because it's searching too much of the problem space with an expectation that there are many solutions.I've got a (sensible) partial solution that seems to have no difficulty on the 'gentle' and 'moderate' level, but it doesn't yet split the search space into multiple possibilities when it can't prune any more. |
|
|
Arnold Fribble
Yak-finder General
1961 Posts |
Posted - 2005-05-28 : 13:55:37
|
Ok, well here's what I have so far... getting a bit bored with the Daily Telegraph ones: they're not posing much of a problem!First, some problems:DROP VIEW SudokuProblemGridGODROP TABLE SudokuProblemDROP TABLE NGOCREATE TABLE SudokuProblem ( problemNo integer NOT NULL PRIMARY KEY, difficulty varchar(10) NOT NULL, notes varchar(200) NULL, settings char(81) NOT NULL)INSERT INTO SudokuProblemSELECT 1, 'easy', 'can be done just applying prune', ' 5 7 ' + ' 61 39 ' + '7 5 8' + ' 839 716 ' + ' ' + ' 218 439 ' + '3 9 6' + ' 75 82 ' + ' 8 4 'UNION ALLSELECT 2, 'easy', 'this needs pick too', ' 3 51' + '5 2 64 ' + ' 7 5 ' + ' 63 7 ' + '2 7 8 6' + ' 4 21 ' + ' 7 8 ' + ' 81 6 9' + '17 5 'UNION ALLSELECT 3, 'tough', 'this one''s broken: there are 4 possible solutions', '2 7 ' + ' 17324 ' + ' 76 ' + ' 268' + ' 6 1 8 3 ' + '984 ' + ' 14 ' + ' 92568 ' + ' 3 5'UNION ALLSELECT 4, 'diabolical', NULL, ' 2 6 8 ' + '58 97 ' + ' 4 ' + '37 5 ' + '6 4' + ' 8 13' + ' 2 ' + ' 98 36' + ' 3 6 9 'UNION ALLSELECT 5, 'gentle', NULL, '4 9 7 8' + ' 562 391 ' + '1 5' + ' 9 1 ' + ' 1 3 2 ' + ' 6 8 ' + '3 9' + ' 918 567 ' + '6 8 5 2'UNION ALLSELECT 6, 'moderate', NULL, '83 1 ' + ' 6 7 5 ' + ' 9 8' + ' 6 5 9 ' + '4 6 9 3' + ' 9 7 5 ' + '9 2 ' + ' 1 8 9 ' + ' 6 87'UNION ALLSELECT 7, 'moderate', NULL, ' 3 6 2 8 ' + ' 19 34 ' + '9 5' + ' 7 3 5 ' + '1 8' + ' 9 7 2 ' + '7 2' + ' 83 46 ' + ' 4 5 7 9 'UNION ALLSELECT 8, 'moderate', NULL, ' 356 9 ' + ' 8 4' + '9 8 65 ' + ' 85 12 ' + ' ' + ' 94 17 ' + ' 64 1 9' + '1 8 ' + ' 2 963 'UNION ALLSELECT 9, 'gentle', NULL, '7 2 4' + '26 93' + ' 9 5 ' + ' 8 7 61' + ' 6 3 ' + '32 9 5 ' + ' 1 2 ' + '19 75' + '8 3 6'UNION ALLSELECT 10, 'moderate', NULL, ' 6 1 ' + ' 7 2 ' + '95 82' + ' 45 38 ' + '51 29' + ' 91 86 ' + '86 53' + ' 8 9 ' + ' 5 4 'UNION ALLSELECT 11, 'moderate', NULL, ' 56 421' + ' 9 86' + ' 2 7 ' + '8 4 1 ' + ' 5 3 ' + ' 1 8 7' + ' 1 9 ' + '47 2 ' + '639 41 'UNION ALLSELECT 12, 'tough', NULL, ' 128' + '2 4 9 7 ' + ' 7 3 4 ' + '1 2 3 ' + ' 5 8 ' + ' 6 9 1' + ' 7 6 1 ' + ' 9 2 3 7' + '528 'UNION ALLSELECT 13, 'diabolical', NULL, ' 125 487 ' + ' ' + '75 23' + ' 41 87 ' + ' 2 5 4 ' + ' 34 95 ' + '48 17' + ' ' + ' 357 169 'UNION ALLSELECT 49, 'diabolical', NULL, ' 6 29' + ' 4 5 3 ' + ' 7 14 ' + '7 54 ' + ' 53 24 ' + ' 12 3' + ' 54 1 ' + ' 6 8 5 ' + '82 5 'UNION ALLSELECT 55, 'diabolical', NULL, '2 3 ' + '8 4 62 3' + ' 138 ' + ' 39 ' + '5 7 6 1' + ' 32 ' + ' 914 ' + '6 25 8 9' + ' 1 2'UNION ALLSELECT 62, 'diabolical', NULL, ' 4 6 ' + '51 9 6' + ' 8 3 4' + '7 1 62 ' + ' 8 6 ' + ' 47 5 1' + '3 4 6 ' + '1 2 38' + ' 6 9 'UNION ALLSELECT 69, 'diabolical', NULL, ' 81 65' + '51 67 8' + ' ' + ' 9 4 3 ' + ' 61 97 ' + ' 5 3 8 ' + ' ' + '6 78 93' + '17 59 'UNION ALLSELECT 76, 'diabolical', NULL, ' 1 4 ' + '95 17' + ' 78 56 ' + '4 97 5 ' + ' 8 ' + ' 3 54 1' + ' 62 41 ' + '19 86' + ' 7 9 'CREATE TABLE N (n tinyint PRIMARY KEY)INSERT INTO N SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALLSELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALLSELECT 8 UNION ALL SELECT 9GOCREATE VIEW SudokuProblemGrid ASSELECT problemNo, x, y, CAST(n AS tinyint) AS nFROM ( SELECT SP.problemNo, X.n AS x, Y.n AS y, SUBSTRING(SP.settings, (Y.n-1)*9+X.n ,1) AS n FROM SudokuProblem AS SP, N AS X, N AS Y ) AS GWHERE ISNUMERIC(n) = 1 DROP TABLE SCREATE TABLE S ( s int NOT NULL, x tinyint NOT NULL, y tinyint NOT NULL, b tinyint NOT NULL, n tinyint NOT NULL, PRIMARY KEY (s, y, x, n))-- all possibilities for all cellsINSERT INTO S (s, x, y, b, n)SELECT 0, X.n, Y.n, (Y.n-1)/3*3+(X.n-1)/3+1, N.nFROM N AS X, N AS Y, N-- fill in problemDELETE FROM SFROM SINNER JOIN SudokuProblemGrid AS G ON S.x = G.x AND S.y = G.y AND S.n <> G.nWHERE G.problemNo = 49WHILE 1=1 BEGIN WHILE 1=1 BEGIN DECLARE @prune int, @pick int -- prune any possibilities that conflict with known values DELETE FROM S FROM S INNER JOIN ( SELECT s, x, y, b, MIN(n) AS n FROM S GROUP BY s, x, y, b HAVING COUNT(*) = 1 ) AS K ON S.s = K.s AND S.n = K.n AND (S.x = K.x OR S.y = K.y OR S.b = K.b) AND NOT(S.x = K.x AND S.y = K.y) SET @prune = @@ROWCOUNT -- pick any values that only occur once in row, column or block DELETE FROM S WHERE EXISTS ( SELECT * FROM S AS S0 WHERE S.s = S0.s AND S.x = S0.x AND S.y = S0.y AND S.n <> S0.n AND ( NOT EXISTS( SELECT * FROM S AS S1 WHERE S0.s = S1.s AND S0.n = S1.n AND S0.x = S1.x AND S0.y <> S1.y ) OR NOT EXISTS( SELECT * FROM S AS S1 WHERE S0.s = S1.s AND S0.n = S1.n AND S0.x <> S1.x AND S0.y = S1.y ) OR NOT EXISTS( SELECT * FROM S AS S1 WHERE S0.s = S1.s AND S0.n = S1.n AND NOT(S0.x = S1.x AND S0.y = S1.y) AND S0.b = S1.b ) ) ) SET @pick = @@ROWCOUNT IF @prune = 0 AND @pick = 0 BREAK END -- delete failed spaces DELETE FROM S WHERE s IN ( SELECT s FROM (SELECT s FROM S GROUP BY s, x, y) AS A GROUP BY s HAVING COUNT(*) < 81 ) -- if no live spaces left, we're done IF NOT EXISTS(SELECT * FROM S GROUP BY s, x, y HAVING COUNT(*) > 1) BREAK -- renumber possible spaces to make duplicate numbering easier UPDATE S1 SET s = 2*(SELECT COUNT(DISTINCT s) FROM S AS S0 WHERE S0.s < S1.s) FROM S AS S1 -- duplicate live spaces INSERT INTO S SELECT s+1, x, y, b, n FROM S WHERE s IN (SELECT s FROM S GROUP BY s, x, y HAVING COUNT(*) > 1) -- find a cell to split in each pair of live spaces -- choose that value in even spaces and exclude it in odd spaces DELETE FROM S FROM S INNER JOIN ( SELECT s, agg/100 AS y, agg/10%10 AS x, agg%10 AS n FROM ( SELECT s, MIN(y*100+x*10+n) AS agg FROM ( SELECT s, x, y, MIN(n) AS n FROM S GROUP BY s, x, y HAVING COUNT(*) > 1 ) AS A GROUP BY s ) AS A ) AS SP ON S.s = SP.s AND S.x = SP.x AND S.y = SP.y AND ((S.s % 2 = 1 AND S.n = SP.n) OR (S.s % 2 = 0 AND S.n <> SP.n))ENDSELECT s, y, MAX(CASE WHEN x = 1 THEN n END) + MAX(CASE WHEN x = 2 THEN n END) + MAX(CASE WHEN x = 3 THEN n END) + MAX(CASE WHEN x = 4 THEN n END) + MAX(CASE WHEN x = 5 THEN n END) + MAX(CASE WHEN x = 6 THEN n END) + MAX(CASE WHEN x = 7 THEN n END) + MAX(CASE WHEN x = 8 THEN n END) + MAX(CASE WHEN x = 9 THEN n END) AS rowFROM (SELECT s, x, y, CAST(n AS char(1)) AS n FROM S) AS AGROUP BY s, yORDER BY s, y |
|
|
nr
SQLTeam MVY
12543 Posts |
Posted - 2005-05-28 : 18:07:43
|
I borrowed your means of inputting the data.It solvess the ones that I had but needs to guess on the one I got from your list (still solves it though). Might look into that later but not sure how to define another rule.create proc #s_DispGridas-- display gridselect r.i, [1] = (select n from #a where r = r.i and c = 1) ,[2] = (select n from #a where r = r.i and c = 2) ,[3] = (select n from #a where r = r.i and c = 3) ,[4] = (select n from #a where r = r.i and c = 4) ,[5] = (select n from #a where r = r.i and c = 5) ,[6] = (select n from #a where r = r.i and c = 6) ,[7] = (select n from #a where r = r.i and c = 7) , = (select n from #a where r = r.i and c = 8) ,[9] = (select n from #a where r = r.i and c = 9)from (select i=1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) rgoset nocount ondrop table #agodrop table #bgocreate table #a (c int, r int, b int, n varchar(9))create table #b (c int, r int, b int, n varchar(9))declare @b int, @c int, @r int, @n int, @nums float, @cnt int-- c = col, r = row, n = possible numbers in slot, b = box number-- initialise gridinsert #a (c, r, b, n) select i.i, j.j, 0, '123456789'from (select i=1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) icross join (select j=1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) jupdate #a set b = 1 where c between 1 and 3 and r between 1 and 3update #a set b = 2 where c between 4 and 6 and r between 1 and 3update #a set b = 3 where c between 7 and 9 and r between 1 and 3update #a set b = 4 where c between 1 and 3 and r between 4 and 6update #a set b = 5 where c between 4 and 6 and r between 4 and 6update #a set b = 6 where c between 7 and 9 and r between 4 and 6update #a set b = 7 where c between 1 and 3 and r between 7 and 9update #a set b = 8 where c between 4 and 6 and r between 7 and 9update #a set b = 9 where c between 7 and 9 and r between 7 and 9-- set valuesdeclare @grid varchar(81)select @grid = ' 1 42 5' + ' 2 71 39' + ' 4 ' + '2 71 6' + ' 4 ' + '6 74 3' + ' 7 ' + '12 73 5 ' + '3 82 7 '--goto runselect @grid = '2 4 8 1 ' + ' 8 1 3' + ' 1 7 5 ' + ' 1 2 64' + ' 43 2 ' + '59 8 7 ' + ' 7 9 4 ' + '6 7 38' + ' 5 1 3 7'--goto runSELECT @grid = ' 1 4 ' + '95 17' + ' 78 56 ' + '4 97 5 ' + ' 8 ' + ' 3 54 1' + ' 62 41 ' + '19 86' + ' 7 9 'run: -- set up grid select @r = 1, @c = 1 while @r <= 9 begin update #a set n = substring(@grid, ((@r-1) * 9) + @c, 1) where substring(@grid, ((@r-1) * 9) + @c, 1) <> ' ' and r = @r and c = @c select @c = @c + 1 if @c = 10 select @r = @r + 1, @c = 1 endexec #s_DispGriddeclare @vanilla int , @attempt intselect @vanilla = 0 , @attempt = 0test:select @cnt = 0while @cnt <> (select sum(len(n)) from #a) -- loop until no changebegin select @cnt = sum(len(n)) from #a -- set all those where there are single instances of values update a set n = num.i from #a a cross join (select i=1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) num left join #a ar on (a.r = ar.r) and (a.r <> ar.r or a.c <> ar.c) and ar.n like '%' + convert(varchar(1), num.i) + '%' left join #a ac on (a.c = ac.c) and (a.r <> ac.r or a.c <> ac.c) and ac.n like '%' + convert(varchar(1), num.i) + '%' left join #a ab on (a.b = ab.b) and (a.r <> ab.r or a.c <> ab.c) and ab.n like '%' + convert(varchar(1), num.i) + '%' where ar.r is null or ac.r is null or ab.r is null -- remove all those where there are single values update t1 set n = replace(t1.n, t2.n, '') from #a t1 cross join (select i=1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) num join #a t2 on (t1.r = t2.r or t1.c = t2.c or t1.b = t2.b) and (t1.r <> t2.r or t1.c <> t2.c) where len(t2.n) = 1 and t1.n like '%' + t2.n + '%' and t2.n = convert(varchar(1),num.i) -- remove all those where there are two values twice update t1 set n = replace(replace(t1.n, left(t2.n,1), ''), right(t2.n,1), '') from #a t1 cross join (select type = 'r' union select 'c' union select 'b') type cross join ( select i = convert(varchar(1),num1.i)+convert(varchar(1),num2.i) from (select i=1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) num1 join (select i=1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) num2 on num1.i < num2.i ) num join #a t2 on ( (t1.r = t2.r and type.type = 'r') or (t1.c = t2.c and type.type = 'c') or (t1.b = t2.b and type.type = 'b') ) and t2.n = num.i join #a t3 on ( (t3.r = t2.r and type.type = 'r') or (t3.c = t2.c and type.type = 'c') or (t3.b = t2.b and type.type = 'b') ) and (t3.r <> t2.r or t3.c <> t2.c) and t3.n = t2.n where patindex('%[' + num.i + ']%', t1.n) <> 0 and (t1.r <> t2.r or t1.c <> t2.c) and (t1.r <> t3.r or t1.c <> t3.c) -- remove all those where there are three values thrice update t1 set n = replace(replace(t1.n, left(t2.n,1), ''), right(t2.n,1), '') from #a t1 cross join (select type = 'r' union select 'c' union select 'b') type cross join ( select i = convert(varchar(1),num1.i)+convert(varchar(1),num2.i)+convert(varchar(1),num3.i) from (select i=1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) num1 join (select i=1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) num2 on num1.i < num2.i join (select i=1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) num3 on num2.i < num3.i ) num join #a t2 on ( (t2.r = t1.r and type.type = 'r') or (t2.c = t1.c and type.type = 'c') or (t2.b = t1.b and type.type = 'b') ) and t2.n = num.i and (t2.r <> t1.r or t2.c <> t1.c) join #a t3 on ( (t3.r = t1.r and type.type = 'r') or (t3.c = t1.c and type.type = 'c') or (t3.b = t1.b and type.type = 'b') ) and t3.n = num.i and (t3.r <> t1.r or t3.c <> t1.c) and (t3.r <> t2.r or t3.c <> t2.c) join #a t4 on ( (t4.r = t1.r and type.type = 'r') or (t4.c = t1.c and type.type = 'c') or (t4.b = t1.b and type.type = 'b') ) and t4.n = num.i and (t4.r <> t1.r or t4.c <> t1.c) and (t4.r <> t2.r or t4.c <> t2.c) and (t4.r <> t3.r or t4.c <> t3.c) where patindex('%[' + num.i + ']%', t1.n) <> 0 endif @attempt > 20 goto oopsif 81 <> (select sum(len(n)) from #a) or exists (select * from #a where n = '') -- not completebegin exec #s_DispGrid select 'no solution - guessing' if @attempt = 0 insert #b select * from #a select @attempt = @attempt + 1 if exists(select * from #a where n = '') -- failed begin delete #a insert #a select * from #b end select @r = r, @c = c from ( select top 1 r,c from #a where len(n) > 1 order by newid() ) a update #a set n = substring(n, convert(int,len(n) * rand() + 1), 1) where r = @r and c = @c select @r, @c select @attempt exec #s_DispGrid goto testendoops: -- display gridexec #s_DispGrid godrop proc #s_DispGridgo ==========================================Cursors are useful if you don't know sql.DTS can be used in a similar way.Beer is not cold and it isn't fizzy. |
|
|
Seventhnight
Master Smack Fu Yak Hacker
2878 Posts |
Posted - 2005-05-31 : 14:48:22
|
We all know I won't pass up a good puzzle. So here is my shot at it all. I mimcked the input method shown above (except I added a 'step' column). This loop solves all the puzzles at one time, and takes ~26 seconds on my box. Let me know what you all think. DROP TABLE #SudokuProblemGOCREATE TABLE #SudokuProblem ( problemNo integer NOT NULL, step int not null, difficulty varchar(10) NOT NULL, notes varchar(200) NULL, settings char(81) NOT NULL PRIMARY KEY (problemNo, step, settings))INSERT INTO #SudokuProblemSELECT 1, 0, 'easy', 'can be done just applying prune', ' 5 7 ' + ' 61 39 ' + '7 5 8' + ' 839 716 ' + ' ' + ' 218 439 ' + '3 9 6' + ' 75 82 ' + ' 8 4 'UNION ALLSELECT 2, 0, 'easy', 'this needs pick too', ' 3 51' + '5 2 64 ' + ' 7 5 ' + ' 63 7 ' + '2 7 8 6' + ' 4 21 ' + ' 7 8 ' + ' 81 6 9' + '17 5 'UNION ALLSELECT 3, 0, 'tough', 'this one''s broken: there are 4 possible solutions', '2 7 ' + ' 17324 ' + ' 76 ' + ' 268' + ' 6 1 8 3 ' + '984 ' + ' 14 ' + ' 92568 ' + ' 3 5'UNION ALLSELECT 4, 0, 'diabolical', NULL, ' 2 6 8 ' + '58 97 ' + ' 4 ' + '37 5 ' + '6 4' + ' 8 13' + ' 2 ' + ' 98 36' + ' 3 6 9 'UNION ALLSELECT 5, 0, 'gentle', NULL, '4 9 7 8' + ' 562 391 ' + '1 5' + ' 9 1 ' + ' 1 3 2 ' + ' 6 8 ' + '3 9' + ' 918 567 ' + '6 8 5 2'UNION ALLSELECT 6, 0, 'moderate', NULL, '83 1 ' + ' 6 7 5 ' + ' 9 8' + ' 6 5 9 ' + '4 6 9 3' + ' 9 7 5 ' + '9 2 ' + ' 1 8 9 ' + ' 6 87'UNION ALLSELECT 7, 0, 'moderate', NULL, ' 3 6 2 8 ' + ' 19 34 ' + '9 5' + ' 7 3 5 ' + '1 8' + ' 9 7 2 ' + '7 2' + ' 83 46 ' + ' 4 5 7 9 'UNION ALLSELECT 8, 0, 'moderate', NULL, ' 356 9 ' + ' 8 4' + '9 8 65 ' + ' 85 12 ' + ' ' + ' 94 17 ' + ' 64 1 9' + '1 8 ' + ' 2 963 'UNION ALLSELECT 9, 0, 'gentle', NULL, '7 2 4' + '26 93' + ' 9 5 ' + ' 8 7 61' + ' 6 3 ' + '32 9 5 ' + ' 1 2 ' + '19 75' + '8 3 6'UNION ALLSELECT 10, 0, 'moderate', NULL, ' 6 1 ' + ' 7 2 ' + '95 82' + ' 45 38 ' + '51 29' + ' 91 86 ' + '86 53' + ' 8 9 ' + ' 5 4 'UNION ALLSELECT 11, 0, 'moderate', NULL, ' 56 421' + ' 9 86' + ' 2 7 ' + '8 4 1 ' + ' 5 3 ' + ' 1 8 7' + ' 1 9 ' + '47 2 ' + '639 41 'UNION ALLSELECT 12, 0, 'tough', NULL, ' 128' + '2 4 9 7 ' + ' 7 3 4 ' + '1 2 3 ' + ' 5 8 ' + ' 6 9 1' + ' 7 6 1 ' + ' 9 2 3 7' + '528 'UNION ALLSELECT 13, 0, 'diabolical', NULL, ' 125 487 ' + ' ' + '75 23' + ' 41 87 ' + ' 2 5 4 ' + ' 34 95 ' + '48 17' + ' ' + ' 357 169 'UNION ALLSELECT 49, 0, 'diabolical', NULL, ' 6 29' + ' 4 5 3 ' + ' 7 14 ' + '7 54 ' + ' 53 24 ' + ' 12 3' + ' 54 1 ' + ' 6 8 5 ' + '82 5 'UNION ALLSELECT 55, 0, 'diabolical', NULL, '2 3 ' + '8 4 62 3' + ' 138 ' + ' 39 ' + '5 7 6 1' + ' 32 ' + ' 914 ' + '6 25 8 9' + ' 1 2'UNION ALLSELECT 62, 0, 'diabolical', NULL, ' 4 6 ' + '51 9 6' + ' 8 3 4' + '7 1 62 ' + ' 8 6 ' + ' 47 5 1' + '3 4 6 ' + '1 2 38' + ' 6 9 'UNION ALLSELECT 69, 0, 'diabolical', NULL, ' 81 65' + '51 67 8' + ' ' + ' 9 4 3 ' + ' 61 97 ' + ' 5 3 8 ' + ' ' + '6 78 93' + '17 59 'UNION ALLSELECT 76, 0, 'diabolical', NULL, ' 1 4 ' + '95 17' + ' 78 56 ' + '4 97 5 ' + ' 8 ' + ' 3 54 1' + ' 62 41 ' + '19 86' + ' 7 9 'Declare @rPos int, @rNum int, @rCnt int, @cPos int, @cNum int, @cCnt int, @step intSet @step = 0While @step < 100Begin -- get possible entries (from the row point of view) Select problemNo, rPos, rNum = Y.Number, rCnt = count(*) Into #rCntsPrep From ( Select problemNo, step, difficulty, notes, rPos = B.number, cPos = C.number, row = substring(Settings,1+9*(B.number-1),9), col = substring(Settings,C.number+9*0,1) + substring(Settings,C.number+9*1,1) + substring(Settings,C.number+9*2,1) + substring(Settings,C.number+9*3,1) + substring(Settings,C.number+9*4,1) + substring(Settings,C.number+9*5,1) + substring(Settings,C.number+9*6,1) + substring(Settings,C.number+9*7,1) + substring(Settings,C.number+9*8,1), settings From #SudokuProblem A, admin.dbo.getsequence(1,9,1) B, admin.dbo.getsequence(1,9,1) C Where step=@step ) Z, admin.dbo.getsequence(1,9,1) Y Where substring(row,cPos,1)='' and row not like '%'+convert(varchar,Y.number)+'%' and col not like '%'+convert(varchar,Y.number)+'%' Group By problemNo, rPos, Y.number order by count(*) -- filter to get the most reliable position (from the row point of view) Select Z.problemNo, Z.rPos, rNum=min(Z.rNum), Z.rCnt Into #rCnts From #rCntsPrep Z Inner Join ( Select A.problemNo, rPos=min(A.rPos), A.rCnt From #rCntsPrep A Inner Join (Select problemNo, rCnt = min(rCnt) From #rCntsPrep Group By problemNo) B On A.problemNo = B.problemNo and A.rCnt = B.rCnt Group By A.problemNo, A.rCnt ) Y On Z.problemNo = Y.problemNo and Z.rCnt = Y.rCnt and Z.rPos = Y.rPos Group By Z.problemNo, Z.rPos, Z.rCnt-- Select * From #rCnts -- get possible entries (from the column point of view) Select problemNo, cPos, cNum = Y.Number, cCnt = count(*) Into #cCntsPrep From ( Select problemNo, step, difficulty, notes, rPos = B.number, cPos = C.number, row = substring(Settings,1+9*(B.number-1),9), col = substring(Settings,C.number+9*0,1) + substring(Settings,C.number+9*1,1) + substring(Settings,C.number+9*2,1) + substring(Settings,C.number+9*3,1) + substring(Settings,C.number+9*4,1) + substring(Settings,C.number+9*5,1) + substring(Settings,C.number+9*6,1) + substring(Settings,C.number+9*7,1) + substring(Settings,C.number+9*8,1), settings From #SudokuProblem A, admin.dbo.getsequence(1,9,1) B, admin.dbo.getsequence(1,9,1) C Where step=@step ) Z, admin.dbo.getsequence(1,9,1) Y Where substring(row,cPos,1)='' and row not like '%'+convert(varchar,Y.number)+'%' and col not like '%'+convert(varchar,Y.number)+'%' Group By problemNo, cPos, Y.number order by count(*) -- filter to get the most reliable position (from the column point of view) Select Z.problemNo, Z.cPos, cNum=min(Z.cNum), Z.cCnt Into #cCnts From #cCntsPrep Z Inner Join ( Select A.problemNo, cPos=min(A.cPos), A.cCnt From #cCntsPrep A Inner Join (Select problemNo, cCnt = min(cCnt) From #cCntsPrep Group By problemNo) B On A.problemNo = B.problemNo and A.cCnt = B.cCnt Group By A.problemNo, A.cCnt ) Y On Z.problemNo = Y.problemNo and Z.cCnt = Y.cCnt and Z.cPos = Y.cPos Group By Z.problemNo, Z.cPos, Z.cCnt-- Select * From #cCnts -- insert next possible steps for all problems Insert Into #SudokuProblem Select Z.problemNo, step=step+1, Z.difficulty, Z.notes, settings = stuff(settings,9*(Z.rPos-1)+Z.cPos,1,convert(varchar,Y.number)) From ( Select problemNo, step, difficulty, notes, rPos = B.number, cPos = C.number, row = substring(Settings,1+9*(B.number-1),9), col = substring(Settings,C.number+9*0,1) + substring(Settings,C.number+9*1,1) + substring(Settings,C.number+9*2,1) + substring(Settings,C.number+9*3,1) + substring(Settings,C.number+9*4,1) + substring(Settings,C.number+9*5,1) + substring(Settings,C.number+9*6,1) + substring(Settings,C.number+9*7,1) + substring(Settings,C.number+9*8,1), settings From #SudokuProblem A, admin.dbo.getsequence(1,9,1) B, admin.dbo.getsequence(1,9,1) C Where step=@step ) Z, admin.dbo.getsequence(1,9,1) Y, #rCnts X, #cCnts W Where substring(row,Z.cPos,1)='' and row not like '%'+convert(varchar,Y.number)+'%' and col not like '%'+convert(varchar,Y.number)+'%' and Z.problemNo = X.problemNo and Z.problemNo = W.problemNo and ( ((case when X.rCnt<=W.cCnt then 1 else 0 end)=1 and Z.rPos=X.rPos and Y.number=X.rNum) or ((case when X.rCnt<=W.cCnt then 1 else 0 end)=0 and Z.cPos=W.cPos and Y.number=W.cNum) ) -- cleanup temp tables Drop Table #rCntsPrep Drop Table #rCnts Drop Table #cCntsPrep Drop Table #cCnts --Select * From #SudokuProblem where step=@step Set @step = @step + 1 -- if you want to see all of the steps comment out the following delete statement Delete A From #SudokuProblem A Inner Join (Select problemNo, step = max(step) From #SudokuProblem Group by problemNo) B On A.problemNo = B.problemNo Where A.step < B.stepEndSelect * From #SudokuProblem CoreySecret Service Agent: Mr. President, you're urinating on me.President Lyndon Johnson: I know I am. It's my prerogative. |
|
|
Seventhnight
Master Smack Fu Yak Hacker
2878 Posts |
Posted - 2005-05-31 : 16:19:33
|
Just noticed mine has a few issues still... be back soon.CoreySecret Service Agent: Mr. President, you're urinating on me.President Lyndon Johnson: I know I am. It's my prerogative. |
|
|
rockmoose
SQL Natt Alfen
3279 Posts |
Posted - 2005-05-31 : 22:18:13
|
This evaluates all solutions to a problem.I am not sure if the filter for selecting all valid solutions is 100% proof,it might give "faulty" answers, but I don't think so, just can't prove it.Anyway, it will give all correct ones as well.( I was to lazy to write out all the inequalities )------------- SETUP --------------------------- need arnold's #SudokuProblem table ------------------------------- Actually Corey's temporary verison... ---------------drop table nGOdrop table tripleGOdrop table #hgridGOdrop table #vgridGOdrop table #sqrsGOcreate table n(n tinyint primary key)GOinsert nselect 1 union select 2 union select 3 union select 4 union select 5union select 6 union select 7 union select 8 union select 9create table triple (a tinyint, b tinyint, c tinyint, primary key(a,b,c))GOinsert tripleselect * from n n1, n n2, n n3where n1.n <> n2.n and n1.n <> n3.n and n2.n <> n3.ncreate table #hgrid(line tinyint primary key, nbrs varchar(9))GOcreate table #vgrid(line tinyint primary key, nbrs varchar(9))GOcreate table #sqrs(s int, a int, b int, c int, d int, e int, f int, g int, h int, i int)GO------------------ END SETUP --------------------------------------- RUN FROM HERE AFTER SETUP -----truncate table #sqrstruncate table #hgridtruncate table #vgrid-- select * from #SudokuProbleminsert #hgrid(line,nbrs)select n ,substring(settings,1 + (n-1)*9,9)from #SudokuProblem cross join nwhere problemNo = 49 ----------------<-------------------- CHOOSE PROBLEMdeclare @nbrs varchar(9), @i int, @h int, @v intset @i = 1while @i < 10begin set @nbrs = '' select @nbrs = @nbrs + substring(nbrs,@i,1) from #hgrid insert #vgrid(line,nbrs) select @i, @nbrs set @i = @i + 1endset @i = 1while @i < 10begin select @h = 3*((@i-1)%3), @v = 3*((@i-1)/3) insert #sqrs select @i as s, t1.a a ,t1.b b ,t1.c c, t2.a d ,t2.b e ,t2.c f, t3.a g ,t3.b h ,t3.c i from triple t1 join triple t2 on (t1.a <> t2.a and t1.a <> t2.b and t1.a <> t2.c) and (t1.b <> t2.a and t1.b <> t2.b and t1.b <> t2.c) and (t1.c <> t2.a and t1.c <> t2.b and t1.c <> t2.c) join triple t3 on (t1.a <> t3.a and t1.a <> t3.b and t1.a <> t3.c) and (t1.b <> t3.a and t1.b <> t3.b and t1.b <> t3.c) and (t1.c <> t3.a and t1.c <> t3.b and t1.c <> t3.c) and (t2.a <> t3.a and t2.a <> t3.b and t2.a <> t3.c) and (t2.b <> t3.a and t2.b <> t3.b and t2.b <> t3.c) and (t2.c <> t3.a and t2.c <> t3.b and t2.c <> t3.c) join #hgrid h1 on h1.line = 1 + @v join #vgrid v1 on v1.line = 1 + @h join #hgrid h2 on h2.line = 2 + @v join #vgrid v2 on v2.line = 2 + @h join #hgrid h3 on h3.line = 3 + @v join #vgrid v3 on v3.line = 3 + @h where ( cast(t1.a as char(1)) = substring(h1.nbrs,1 + @h,1) or (substring(h1.nbrs,1 + @h,1) = '' and charindex(cast(t1.a as char(1)),h1.nbrs) + charindex(cast(t1.a as char(1)),v1.nbrs) = 0)) and( cast(t1.b as char(1)) = substring(h1.nbrs,2 + @h,1) or (substring(h1.nbrs,2 + @h,1) = '' and charindex(cast(t1.b as char(1)),h1.nbrs) + charindex(cast(t1.b as char(1)),v2.nbrs) = 0)) and( cast(t1.c as char(1)) = substring(h1.nbrs,3 + @h,1) or (substring(h1.nbrs,3 + @h,1) = '' and charindex(cast(t1.c as char(1)),h1.nbrs) + charindex(cast(t1.c as char(1)),v3.nbrs) = 0)) and( cast(t2.a as char(1)) = substring(h2.nbrs,1 + @h,1) or (substring(h2.nbrs,1 + @h,1) = '' and charindex(cast(t2.a as char(1)),h2.nbrs) + charindex(cast(t2.a as char(1)),v1.nbrs) = 0)) and( cast(t2.b as char(1)) = substring(h2.nbrs,2 + @h,1) or (substring(h2.nbrs,2 + @h,1) = '' and charindex(cast(t2.b as char(1)),h2.nbrs) + charindex(cast(t2.b as char(1)),v2.nbrs) = 0)) and( cast(t2.c as char(1)) = substring(h2.nbrs,3 + @h,1) or (substring(h2.nbrs,3 + @h,1) = '' and charindex(cast(t2.c as char(1)),h2.nbrs) + charindex(cast(t2.c as char(1)),v3.nbrs) = 0)) and( cast(t3.a as char(1)) = substring(h3.nbrs,1 + @h,1) or (substring(h3.nbrs,1 + @h,1) = '' and charindex(cast(t3.a as char(1)),h3.nbrs) + charindex(cast(t3.a as char(1)),v1.nbrs) = 0)) and( cast(t3.b as char(1)) = substring(h3.nbrs,2 + @h,1) or (substring(h3.nbrs,2 + @h,1) = '' and charindex(cast(t3.b as char(1)),h3.nbrs) + charindex(cast(t3.b as char(1)),v2.nbrs) = 0)) and( cast(t3.c as char(1)) = substring(h3.nbrs,3 + @h,1) or (substring(h3.nbrs,3 + @h,1) = '' and charindex(cast(t3.c as char(1)),h3.nbrs) + charindex(cast(t3.c as char(1)),v3.nbrs) = 0)) set @i = @i + 1endselect cast(s1.a as char(1))+cast(s1.b as char(1))+cast(s1.c as char(1))+cast(s2.a as char(1))+cast(s2.b as char(1))+cast(s2.c as char(1))+cast(s3.a as char(1))+cast(s3.b as char(1))+cast(s3.c as char(1))+ char(10)+cast(s1.d as char(1))+cast(s1.e as char(1))+cast(s1.f as char(1))+cast(s2.d as char(1))+cast(s2.e as char(1))+cast(s2.f as char(1))+cast(s3.d as char(1))+cast(s3.e as char(1))+cast(s3.f as char(1))+ char(10)+cast(s1.g as char(1))+cast(s1.h as char(1))+cast(s1.i as char(1))+cast(s2.g as char(1))+cast(s2.h as char(1))+cast(s2.i as char(1))+cast(s3.g as char(1))+cast(s3.h as char(1))+cast(s3.i as char(1))+ char(10)+cast(s4.a as char(1))+cast(s4.b as char(1))+cast(s4.c as char(1))+cast(s5.a as char(1))+cast(s5.b as char(1))+cast(s5.c as char(1))+cast(s6.a as char(1))+cast(s6.b as char(1))+cast(s6.c as char(1))+ char(10)+cast(s4.d as char(1))+cast(s4.e as char(1))+cast(s4.f as char(1))+cast(s5.d as char(1))+cast(s5.e as char(1))+cast(s5.f as char(1))+cast(s6.d as char(1))+cast(s6.e as char(1))+cast(s6.f as char(1))+ char(10)+cast(s4.g as char(1))+cast(s4.h as char(1))+cast(s4.i as char(1))+cast(s5.g as char(1))+cast(s5.h as char(1))+cast(s5.i as char(1))+cast(s6.g as char(1))+cast(s6.h as char(1))+cast(s6.i as char(1))+ char(10)+cast(s7.a as char(1))+cast(s7.b as char(1))+cast(s7.c as char(1))+cast(s8.a as char(1))+cast(s8.b as char(1))+cast(s8.c as char(1))+cast(s9.a as char(1))+cast(s9.b as char(1))+cast(s9.c as char(1))+ char(10)+cast(s7.d as char(1))+cast(s7.e as char(1))+cast(s7.f as char(1))+cast(s8.d as char(1))+cast(s8.e as char(1))+cast(s8.f as char(1))+cast(s9.d as char(1))+cast(s9.e as char(1))+cast(s9.f as char(1))+ char(10)+cast(s7.g as char(1))+cast(s7.h as char(1))+cast(s7.i as char(1))+cast(s8.g as char(1))+cast(s8.h as char(1))+cast(s8.i as char(1))+cast(s9.g as char(1))+cast(s9.h as char(1))+cast(s9.i as char(1)) +char(10) as gridfrom(select * from #sqrs where s = 1) s1join (select * from #sqrs where s = 2) s2 on 1 = 1join (select * from #sqrs where s = 3) s3 on s1.a + s1.b + s1.c + s2.a + s2.b + s2.c + s3.a + s3.b + s3.c = 45 and s1.d + s1.e + s1.f + s2.d + s2.e + s2.f + s3.d + s3.e + s3.f = 45 and s1.g + s1.h + s1.i + s2.g + s2.h + s2.i + s3.g + s3.h + s3.i = 45 and s1.a * s1.b * s1.c * s2.a * s2.b * s2.c * s3.a * s3.b * s3.c = 362880 and s1.d * s1.e * s1.f * s2.d * s2.e * s2.f * s3.d * s3.e * s3.f = 362880 and s1.g * s1.h * s1.i * s2.g * s2.h * s2.i * s3.g * s3.h * s3.i = 362880join (select * from #sqrs where s = 4) s4 on 1 = 1join (select * from #sqrs where s = 5) s5 on 1 = 1join (select * from #sqrs where s = 6) s6 on s4.a + s4.b + s4.c + s5.a + s5.b + s5.c + s6.a + s6.b + s6.c = 45 and s4.d + s4.e + s4.f + s5.d + s5.e + s5.f + s6.d + s6.e + s6.f = 45 and s4.g + s4.h + s4.i + s5.g + s5.h + s5.i + s6.g + s6.h + s6.i = 45 and s4.a * s4.b * s4.c * s5.a * s5.b * s5.c * s6.a * s6.b * s6.c = 362880 and s4.d * s4.e * s4.f * s5.d * s5.e * s5.f * s6.d * s6.e * s6.f = 362880 and s4.g * s4.h * s4.i * s5.g * s5.h * s5.i * s6.g * s6.h * s6.i = 362880join (select * from #sqrs where s = 7) s7 on 1 = 1join (select * from #sqrs where s = 8) s8 on 1 = 1join (select * from #sqrs where s = 9) s9 on s7.a + s7.b + s7.c + s8.a + s8.b + s8.c + s9.a + s9.b + s9.c = 45 and s7.d + s7.e + s7.f + s8.d + s8.e + s8.f + s9.d + s9.e + s9.f = 45 and s7.g + s7.h + s7.i + s8.g + s8.h + s8.i + s9.g + s9.h + s9.i = 45 and s7.a * s7.b * s7.c * s8.a * s8.b * s8.c * s9.a * s9.b * s9.c = 362880 and s7.d * s7.e * s7.f * s8.d * s8.e * s8.f * s9.d * s9.e * s9.f = 362880 and s7.g * s7.h * s7.i * s8.g * s8.h * s8.i * s9.g * s9.h * s9.i = 362880where s1.a + s1.d + s1.g + s4.a + s4.d + s4.g + s7.a + s7.d + s7.g = 45 and s1.b + s1.e + s1.h + s4.b + s4.e + s4.h + s7.b + s7.e + s7.h = 45 and s1.c + s1.f + s1.i + s4.c + s4.f + s4.i + s7.c + s7.f + s7.i = 45 and s2.a + s2.d + s2.g + s5.a + s5.d + s5.g + s8.a + s8.d + s8.g = 45 and s2.b + s2.e + s2.h + s5.b + s5.e + s5.h + s8.b + s8.e + s8.h = 45 and s2.c + s2.f + s2.i + s5.c + s5.f + s5.i + s8.c + s8.f + s8.i = 45 and s3.a + s3.d + s3.g + s6.a + s6.d + s6.g + s9.a + s9.d + s9.g = 45 and s3.b + s3.e + s3.h + s6.b + s6.e + s6.h + s9.b + s9.e + s9.h = 45 and s3.c + s3.f + s3.i + s6.c + s6.f + s6.i + s9.c + s9.f + s9.i = 45 and s1.a * s1.d * s1.g * s4.a * s4.d * s4.g * s7.a * s7.d * s7.g = 362880 and s1.b * s1.e * s1.h * s4.b * s4.e * s4.h * s7.b * s7.e * s7.h = 362880 and s1.c * s1.f * s1.i * s4.c * s4.f * s4.i * s7.c * s7.f * s7.i = 362880 and s2.a * s2.d * s2.g * s5.a * s5.d * s5.g * s8.a * s8.d * s8.g = 362880 and s2.b * s2.e * s2.h * s5.b * s5.e * s5.h * s8.b * s8.e * s8.h = 362880 and s2.c * s2.f * s2.i * s5.c * s5.f * s5.i * s8.c * s8.f * s8.i = 362880 and s3.a * s3.d * s3.g * s6.a * s6.d * s6.g * s9.a * s9.d * s9.g = 362880 and s3.b * s3.e * s3.h * s6.b * s6.e * s6.h * s9.b * s9.e * s9.h = 362880 and s3.c * s3.f * s3.i * s6.c * s6.f * s6.i * s9.c * s9.f * s9.i = 362880 rockmoose |
|
|
TG
Master Smack Fu Yak Hacker
6065 Posts |
Posted - 2005-07-09 : 16:18:39
|
I hope you folks don't mind that I re awakened this thread. My local paper (Washington Post) just started printing these puzzles. I did a few of them the old fasioned way (instead of my usual crossword) and decided to try to create a programmatic tsql version of the algorithm I used to do them manually. It ended up to be variations of Arnold's and Corey's versions. It only solves for the first solution it finds but it works pretty quickly (the easy ones are sub-second and tough ones are between 1 and 3 seconds on my laptop depending on the luck of random choices for whatIf scenarios). Anyway, here it is:EDIT: (new version)set nocount ondeclare @numbers table (n int)declare @p table (r int, c int, q int, v int, vType varchar(15))declare @possibleVals table (r int, c int, q int, v int)declare @selectedVals table (r int, c int, q int, v int)declare @distinctVals table (v int)declare @i tinyint ,@row int ,@col int ,@quad int ,@val int ,@vType varchar(15) ,@pStr varchar(90) ,@valcount int ,@lastcount int ,@origCount int ,@loopCount int ,@whatIfAttempts int ,@puzzleResult varchar(9)insert @numbersselect 1 unionselect 2 unionselect 3 unionselect 4 unionselect 5 unionselect 6 unionselect 7 unionselect 8 unionselect 9--============================================================--Set up the puzzle--pretty easy one from Washington Postset @pStr ='-7-1-2-9-' +'---564---' +'--6---1--' +'--4---9--' +'-157-832-' +'--7---6--' +'--9---2--' +'---359---' +'-4-6-7-8-'--No 1 from Arnold/Corey posts (easy)set @pStr = ' 5 7 ' + ' 61 39 ' + '7 5 8' + ' 839 716 ' + ' ' + ' 218 439 ' + '3 9 6' + ' 75 82 ' + ' 8 4 '--No 76 from Arnold/Corey posts (diabolical)set @pStr = ' 1 4 ' + '95 17' + ' 78 56 ' + '4 97 5 ' + ' 8 ' + ' 3 54 1' + ' 62 41 ' + '19 86' + ' 7 9 '--medium easy one from Washington Postset @pStr ='1------45' +'2--7--8--' +'-8--69---' +'--2-5--1-' +'--41-37--' +'-1--4-5--' +'---98--3-' +'--6--1--8' +'84------1'--No 76 from Arnold/Corey posts (diabolical)set @pStr = ' 1 4 ' + '95 17' + ' 78 56 ' + '4 97 5 ' + ' 8 ' + ' 3 54 1' + ' 62 41 ' + '19 86' + ' 7 9 '--virtually empty, many possible solutionsset @pStr = ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + '1 '--invalid setup testset @pStr = ' ' + ' ' + '1 ' + ' ' + ' ' + ' ' + ' ' + ' ' + '1 '--No 69 from Arnold/Corey posts (diabolical)set @pStr = ' 81 65' + '51 67 8' + ' ' + ' 9 4 3 ' + ' 61 97 ' + ' 5 3 8 ' + ' ' + '6 78 93' + '17 59 'set @pStr = replace(@pStr, ' ', '-')select @vType = 'Original' ,@i = 1while @i < 82begin select @row = ceiling(@i/9.00) ,@col = isnull(nullif(@i%9,0),9) ,@quad = case when @row between 1 and 3 then case when @col between 1 and 3 then 1 when @col between 4 and 6 then 2 when @col between 7 and 9 then 3 end when @row between 4 and 6 then case when @col between 1 and 3 then 4 when @col between 4 and 6 then 5 when @col between 7 and 9 then 6 end when @row between 7 and 9 then case when @col between 1 and 3 then 7 when @col between 4 and 6 then 8 when @col between 7 and 9 then 9 end end ,@val = nullif(substring(@pStr,@i,1),'-') ,@i = @i+1 insert @p (r,c,q,v,vType) values (@row, @col, @quad, @val, @vType) end--find out if puzzle can be solved (invalid setup)if exists(select 'tg' from @p where v is not null group by r,v having count(*) > 1)or exists(select 'tg' from @p where v is not null group by c,v having count(*) > 1)or exists(select 'tg' from @p where v is not null group by q,v having count(*) > 1)begin print 'puzzle has invalid set up. It violates the rules' returnend--print puzzle setupset @pStr = ''set @i = 1while @i < 82begin select @row = ceiling(@i/9.00) ,@col = isnull(nullif(@i%9,0),9) ,@i = @i+1 select @val = v from @p where r = @row and c = @col select @pStr = @pStr + isNull(convert(varchar,v),'-') from @p where r = @row and c = @col if @col = 9 set @pStr = @pStr + char(13)endselect @pStr [puzzleSetup]--============================================================--solve the puzzleselect @origCount = count(*) ,@loopcount = 0 ,@whatIfAttempts = 0from @p where v is not null--For different whatif scenario, start over from hereTryAgain:if @WhatIfAttempts > 10 goto cutprint--set/reset puzzle to point before 1st whatIf scenarioupdate @p set v = null ,vType = 'Original'where vType like 'WhatIf%'select @valCount = count(*) ,@lastCount = 0 ,@vType = 'Original'from @pwhere v is not null--start loop to solvewhile (@valcount <> @lastcount and @valcount < 81) or @valcount = 0begin --reinitialize vars for next loop select @lastcount = @valcount ,@loopCount = @loopCount + 1 ,@vType = case when @vType like 'WhatIf%' then 'WhatIfOneValue' else 'OneValue' end --reinitialize tabel vars for next loop delete @possibleVals delete @selectedVals delete @distinctVals --insert all possible values for each position to @possibleVals table --based on known values in each row, column, and quadrant insert @possibleVals (r,c,q,v) select a.r, a.c, a.q, b.n from @p a cross join @numbers b where b.n not in ( select v from @p where r = a.r and v is not null union select v from @p where c = a.c and v is not null union select v from @p where q = a.q and v is not null ) and v is null if @@rowcount = 0 begin --this could happen for an incorrect WhatIf scenario set @whatIfAttempts = @whatIfAttempts + 1 goto tryAgain end -------------------------------------------------------------------- --all sections must solve for only one possible solution at a time --if this puzzle has multiple solutions, don't allow a column, row, --or quadrant to have a repeated value. --get a distinct list of possible values insert @distinctVals select distinct v from (--get all values where the position has only one possible value select min(v) v from @possibleVals group by r,c having count(*) = 1 ) a -------------------------------------------------------------------- --This section sets the value for all positions where there is --only one possible value based on known values in the position's --row, column, or quadrant. while @@rowcount > 0 begin --get 1 position for each distinct value insert @selectedVals (r,c,q,v) select a.r, a.c, a.q, a.v from @possibleVals a join (--only one position for each distinct value select min( (r*10)+c ) rc, a.v from @distinctVals a join (--only positions with 1 possible value select r, c, min(v) v from @possibleVals group by r,c having count(*) = 1 ) b on a.v = b.v group by a.v ) b on a.v = b.v and (a.r*10)+a.c = rc where not exists ( select 'tg' from @selectedVals where v = a.v and (r = a.r or c = a.c or q = a.q) ) end --@selectedVals now contains every position that --has only 1 possible value for this possible solution tree. update a set a.v = b.v ,a.vType = @vType from @p a join @selectedVals b on a.r = b.r and a.c = b.c where a.v is null --increment counts from last statement and get new valuecount select @valcount = count(*) from @p where v is not null -------------------------------------------------------------------- --This section sets the value for all positions where there are --at least 2 possible values. Check for any position in a given --row, column, or quadrant that is the only position in that rol, --column or quadrant that could be set to a single value. --(gotta be this value) only do this section if the previous section --set no new values. if @valcount = @lastcount and exists (select 'tg' from @p where v is null) begin set @vType = case when @vType like 'WhatIf%' then 'WhatIfGottaBee' else 'GottaBee' end ------------------------------------------- --get gottabees by column insert @selectedVals (r,c,q,v) select a.r, a.c, a.q, b.v from @possibleVals a join (-- select c, v from @possibleVals group by c,v having count(*) = 1 ) b on a.c = b.c and a.v = b.v --get gottabees by row insert @selectedVals (r,c,q,v) select a.r, a.c, a.q, b.v from @possibleVals a join ( select r, v from @possibleVals group by r,v having count(*) = 1 ) b on a.r = b.r and a.v = b.v where not exists ( select 'tg' from @selectedVals where v = b.v and r = a.r and c = a.c and q = a.q) --get gottabees by quadrant insert @selectedVals (r,c,q,v) select a.r, a.c, a.q, b.v from @possibleVals a join ( select q, v from @possibleVals group by q,v having count(*) = 1 ) b on a.q = b.q and a.v = b.v where not exists ( select 'tg' from @selectedVals where v = b.v and r = a.r and c = a.c and q = a.q) update a set a.v = b.v ,a.vType = @vType from @p a join @selectedVals b on a.r = b.r and a.c = b.c select @valcount = count(*) from @p where v is not null ------------------------------------------- end -------------------------------------------------------------------- --If no new values have been set by the previous 2 sections and the --puzzle is not yet solved then set 1 position value to one of its --possible values as a Wwhat If Scenario. if @valcount = @lastcount and exists (select 'tg' from @p where v is null) begin select @vType = 'WhatIf' ,@WhatIfAttempts = isnull(nullif(@WhatIfAttempts,0),1) insert @selectedVals (r,c,v) select top 1 b.r, b.c, b.v from (--find a random position that has(or is tied for) the fewest possible values select top 1 r,c from @possibleVals group by r, c order by count(*), newid() ) a join @possibleVals b on a.r = b.r and a.c = b.c order by newid() update a set a.v = b.v ,a.vType = @vType from @p a join @SelectedVals b on a.r = b.r and a.c = b.c end select @valcount = count(*) from @p where v is not nullend--couldn't solve the puzzle so try again with a different what if scenarioif @valcount < 81begin set @whatIfAttempts = @whatIfAttempts + 1 goto TryAgainend--============================================================--print solved puzzle and solving statisticsCutPrint:set @pStr = ''set @i = 1while @i < 82begin select @row = ceiling(@i/9.00) ,@col = isnull(nullif(@i%9,0),9) ,@i = @i+1 select @val = v from @p where r = @row and c = @col select @pStr = @pStr + isNull(convert(varchar,v),'-') from @p where r = @row and c = @col if @col = 9 set @pStr = @pStr + char(13)end--print puzzleselect @pStr [PuzzleSolved]--find out if its correct or notif exists(select 'tg' from @p group by r having sum(v) <> 45 or count(distinct v) <> 9)or exists(select 'tg' from @p group by c having sum(v) <> 45 or count(distinct v) <> 9)or exists(select 'tg' from @p group by q having sum(v) <> 45 or count(distinct v) <> 9) set @puzzleResult = 'Incorrect'else set @puzzleResult = 'Correct'--print statsselect Category, resultfrom ( select 1 rowid, 'PuzzleResult' category, @PuzzleResult result union select 2, 'TotalLoopsToSolve', convert(varchar,@loopcount) union select 3, 'WhatIfScenarioCount', convert(varchar,@WhatIfAttempts) union select case when vType = 'Original' then 4 when vType = 'OneValue' then 5 when vType = 'GottaBee' then 6 when vType = 'WhatIf' then 7 when vType = 'WhatIfOneValue' then 8 else 9 end ,case when vType = 'Original' then 'OriginalValueCount' when vType = 'OneValue' then 'OnePossibleVal-Count' when vType = 'GottaBee' then 'GottaBee-Count' when vType = 'WhatIf' then 'WhatIf-Count' when vType = 'WhatIfOneValue' then 'WhatIfOneValue-Count' else 'WhatIfGottaBee-count' end ,convert(varchar,count(*)) from @p group by vType ) aorder by rowid Be One with the OptimizerTG |
|
|
rockmoose
SQL Natt Alfen
3279 Posts |
Posted - 2005-07-09 : 21:15:02
|
TG, very fast.For scenario 69, the results are a bit random on my computer.Sometimes a correct, and sometimes an incorrect solution is given, example wrong solution of #69 on my pc:puzzleSetup--------------81--6551--67--8----------9---4-3--61---97--5-3---8----------6--78--9317--59---PuzzleSolved------------749813265514967328836245719298174536361528974457396182984432657625781493173659842TotalLoopsToSolve-----------------41 A repost with more Formatted Code, than my previous post, somewhat rewritten:This runs in 5 sec on my PC.Given the number of combinations of the 9 table crossjoin (18.114.969.600), and the "neat" where clause, The query optimizer is very very good at shortcircuiting the # of evaluated combinations,the vast majority are discarded very early in the process.drop table tripledrop table #sqrsDROP TABLE #SudokuProblemGOcreate table #SudokuProblem ( problemNo int PRIMARY KEY, difficulty varchar(10) NOT NULL, notes varchar(200) NOT NULL, settings char(81) NOT NULL UNIQUE )insert #SudokuProblemselect 1,'easy','can be done just applying prune',' 5 7 61 39 7 5 8 839 716 218 439 3 9 6 75 82 8 4 'union all select 2,'easy','this needs pick too',' 3 515 2 64 7 5 63 7 2 7 8 6 4 21 7 8 81 6 917 5 'union all select 3,'tough','this one''s broken: there are 4 possible solutions','2 7 17324 76 268 6 1 8 3 984 14 92568 3 5'union all select 4,'diabolical','',' 2 6 8 58 97 4 37 5 6 4 8 13 2 98 36 3 6 9 'union all select 5,'gentle','','4 9 7 8 562 391 1 5 9 1 1 3 2 6 8 3 9 918 567 6 8 5 2'union all select 6,'moderate','','83 1 6 7 5 9 8 6 5 9 4 6 9 3 9 7 5 9 2 1 8 9 6 87'union all select 7,'moderate','',' 3 6 2 8 19 34 9 5 7 3 5 1 8 9 7 2 7 2 83 46 4 5 7 9 'union all select 8,'moderate','',' 356 9 8 49 8 65 85 12 94 17 64 1 91 8 2 963 'union all select 9,'gentle','','7 2 426 93 9 5 8 7 61 6 3 32 9 5 1 2 19 758 3 6'union all select 10,'moderate','',' 6 1 7 2 95 82 45 38 51 29 91 86 86 53 8 9 5 4 'union all select 11,'moderate','',' 56 421 9 86 2 7 8 4 1 5 3 1 8 7 1 9 47 2 639 41 'union all select 12,'tough','',' 1282 4 9 7 7 3 4 1 2 3 5 8 6 9 1 7 6 1 9 2 3 7528 'union all select 13,'diabolical','',' 125 487 75 23 41 87 2 5 4 34 95 48 17 357 169 'union all select 49,'diabolical','',' 6 29 4 5 3 7 14 7 54 53 24 12 3 54 1 6 8 5 82 5 'union all select 55,'diabolical','','2 3 8 4 62 3 138 39 5 7 6 1 32 914 6 25 8 9 1 2'union all select 62,'diabolical','',' 4 6 51 9 6 8 3 47 1 62 8 6 47 5 13 4 6 1 2 38 6 9 'union all select 69,'diabolical','',' 81 6551 67 8 9 4 3 61 97 5 3 8 6 78 9317 59 'union all select 76,'diabolical','',' 1 4 95 17 78 56 4 97 5 8 3 54 1 62 41 19 86 7 9 'union all select 101,'diabolical','pretty easy one from Washington Post',' 7 1 2 9 564 6 1 4 9 157 832 7 6 9 2 359 4 6 7 8 'union all select 141,'diabolical','medium easy one from Washington Post','1 452 7 8 8 69 2 5 1 41 37 1 4 5 98 3 6 1 884 1'declare @problemNo intset @problemNo = 69 ----------------<-------------------- CHOOSE PROBLEMdeclare @n table(n tinyint primary key)declare @hgrid table(line tinyint primary key, nbrs varchar(9))declare @vgrid table(line tinyint primary key, nbrs varchar(9))create table #sqrs(s int, a int, b int, c int, d int, e int, f int, g int, h int, i int)create table triple(a tinyint, b tinyint, c tinyint, primary key(a,b,c))insert @nselect 1 union select 2 union select 3 union select 4 union select 5union select 6 union select 7 union select 8 union select 9insert tripleselect * from @n n1, @n n2, @n n3where n1.n <> n2.n and n1.n <> n3.n and n2.n <> n3.ninsert @hgrid(line,nbrs)select n ,substring(settings,1 + (n-1)*9,9)from #SudokuProblem cross join @nwhere problemNo = @problemNodeclare @nbrs varchar(9), @i int, @h int, @v intset @i = 1while @i < 10begin set @nbrs = '' select @nbrs = @nbrs + substring(nbrs,@i,1) from @hgrid insert @vgrid(line,nbrs) select @i, @nbrs set @i = @i + 1endset @i = 1while @i < 10begin select @h = 3*((@i-1)%3), @v = 3*((@i-1)/3) insert #sqrs select @i as s, t1.a a ,t1.b b ,t1.c c, t2.a d ,t2.b e ,t2.c f, t3.a g ,t3.b h ,t3.c i from triple t1 join triple t2 on (t1.a <> t2.a and t1.a <> t2.b and t1.a <> t2.c) and (t1.b <> t2.a and t1.b <> t2.b and t1.b <> t2.c) and (t1.c <> t2.a and t1.c <> t2.b and t1.c <> t2.c) join triple t3 on (t1.a <> t3.a and t1.a <> t3.b and t1.a <> t3.c) and (t1.b <> t3.a and t1.b <> t3.b and t1.b <> t3.c) and (t1.c <> t3.a and t1.c <> t3.b and t1.c <> t3.c) and (t2.a <> t3.a and t2.a <> t3.b and t2.a <> t3.c) and (t2.b <> t3.a and t2.b <> t3.b and t2.b <> t3.c) and (t2.c <> t3.a and t2.c <> t3.b and t2.c <> t3.c) join @hgrid h1 on h1.line = 1 + @v join @vgrid v1 on v1.line = 1 + @h join @hgrid h2 on h2.line = 2 + @v join @vgrid v2 on v2.line = 2 + @h join @hgrid h3 on h3.line = 3 + @v join @vgrid v3 on v3.line = 3 + @h where ( cast(t1.a as char(1)) = substring(h1.nbrs,1 + @h,1) or (substring(h1.nbrs,1 + @h,1) = '' and charindex(cast(t1.a as char(1)),h1.nbrs) + charindex(cast(t1.a as char(1)),v1.nbrs) = 0)) and( cast(t1.b as char(1)) = substring(h1.nbrs,2 + @h,1) or (substring(h1.nbrs,2 + @h,1) = '' and charindex(cast(t1.b as char(1)),h1.nbrs) + charindex(cast(t1.b as char(1)),v2.nbrs) = 0)) and( cast(t1.c as char(1)) = substring(h1.nbrs,3 + @h,1) or (substring(h1.nbrs,3 + @h,1) = '' and charindex(cast(t1.c as char(1)),h1.nbrs) + charindex(cast(t1.c as char(1)),v3.nbrs) = 0)) and( cast(t2.a as char(1)) = substring(h2.nbrs,1 + @h,1) or (substring(h2.nbrs,1 + @h,1) = '' and charindex(cast(t2.a as char(1)),h2.nbrs) + charindex(cast(t2.a as char(1)),v1.nbrs) = 0)) and( cast(t2.b as char(1)) = substring(h2.nbrs,2 + @h,1) or (substring(h2.nbrs,2 + @h,1) = '' and charindex(cast(t2.b as char(1)),h2.nbrs) + charindex(cast(t2.b as char(1)),v2.nbrs) = 0)) and( cast(t2.c as char(1)) = substring(h2.nbrs,3 + @h,1) or (substring(h2.nbrs,3 + @h,1) = '' and charindex(cast(t2.c as char(1)),h2.nbrs) + charindex(cast(t2.c as char(1)),v3.nbrs) = 0)) and( cast(t3.a as char(1)) = substring(h3.nbrs,1 + @h,1) or (substring(h3.nbrs,1 + @h,1) = '' and charindex(cast(t3.a as char(1)),h3.nbrs) + charindex(cast(t3.a as char(1)),v1.nbrs) = 0)) and( cast(t3.b as char(1)) = substring(h3.nbrs,2 + @h,1) or (substring(h3.nbrs,2 + @h,1) = '' and charindex(cast(t3.b as char(1)),h3.nbrs) + charindex(cast(t3.b as char(1)),v2.nbrs) = 0)) and( cast(t3.c as char(1)) = substring(h3.nbrs,3 + @h,1) or (substring(h3.nbrs,3 + @h,1) = '' and charindex(cast(t3.c as char(1)),h3.nbrs) + charindex(cast(t3.c as char(1)),v3.nbrs) = 0)) set @i = @i + 1endselect replace(substring(settings,1+(n-1)*9,9),' ','-') as puzzleSetupfrom #SudokuProblem, @nwhere problemNo = @problemNoorder by nselect cast(exp(sum(log(cnt))) as bigint) as NoOfCombinationsfrom (select s,count(*) as cnt from #sqrs group by s) tselect cast(s1.a as char(1))+cast(s1.b as char(1))+cast(s1.c as char(1))+cast(s2.a as char(1))+cast(s2.b as char(1))+cast(s2.c as char(1))+cast(s3.a as char(1))+cast(s3.b as char(1))+cast(s3.c as char(1))+ char(10)+cast(s1.d as char(1))+cast(s1.e as char(1))+cast(s1.f as char(1))+cast(s2.d as char(1))+cast(s2.e as char(1))+cast(s2.f as char(1))+cast(s3.d as char(1))+cast(s3.e as char(1))+cast(s3.f as char(1))+ char(10)+cast(s1.g as char(1))+cast(s1.h as char(1))+cast(s1.i as char(1))+cast(s2.g as char(1))+cast(s2.h as char(1))+cast(s2.i as char(1))+cast(s3.g as char(1))+cast(s3.h as char(1))+cast(s3.i as char(1))+ char(10)+cast(s4.a as char(1))+cast(s4.b as char(1))+cast(s4.c as char(1))+cast(s5.a as char(1))+cast(s5.b as char(1))+cast(s5.c as char(1))+cast(s6.a as char(1))+cast(s6.b as char(1))+cast(s6.c as char(1))+ char(10)+cast(s4.d as char(1))+cast(s4.e as char(1))+cast(s4.f as char(1))+cast(s5.d as char(1))+cast(s5.e as char(1))+cast(s5.f as char(1))+cast(s6.d as char(1))+cast(s6.e as char(1))+cast(s6.f as char(1))+ char(10)+cast(s4.g as char(1))+cast(s4.h as char(1))+cast(s4.i as char(1))+cast(s5.g as char(1))+cast(s5.h as char(1))+cast(s5.i as char(1))+cast(s6.g as char(1))+cast(s6.h as char(1))+cast(s6.i as char(1))+ char(10)+cast(s7.a as char(1))+cast(s7.b as char(1))+cast(s7.c as char(1))+cast(s8.a as char(1))+cast(s8.b as char(1))+cast(s8.c as char(1))+cast(s9.a as char(1))+cast(s9.b as char(1))+cast(s9.c as char(1))+ char(10)+cast(s7.d as char(1))+cast(s7.e as char(1))+cast(s7.f as char(1))+cast(s8.d as char(1))+cast(s8.e as char(1))+cast(s8.f as char(1))+cast(s9.d as char(1))+cast(s9.e as char(1))+cast(s9.f as char(1))+ char(10)+cast(s7.g as char(1))+cast(s7.h as char(1))+cast(s7.i as char(1))+cast(s8.g as char(1))+cast(s8.h as char(1))+cast(s8.i as char(1))+cast(s9.g as char(1))+cast(s9.h as char(1))+cast(s9.i as char(1)) +char(10) as PuzzleSolvedfrom #sqrs s1, #sqrs s2, #sqrs s3, #sqrs s4, #sqrs s5, #sqrs s6, #sqrs s7, #sqrs s8, #sqrs s9where (s1.s=1 and s2.s=2 and s3.s=3 and s4.s=4 and s5.s=5 and s6.s=6 and s7.s=7 and s8.s=8 and s9.s=9) and (s1.a + s1.b + s1.c + s2.a + s2.b + s2.c + s3.a + s3.b + s3.c = 45 and s1.d + s1.e + s1.f + s2.d + s2.e + s2.f + s3.d + s3.e + s3.f = 45 and s1.g + s1.h + s1.i + s2.g + s2.h + s2.i + s3.g + s3.h + s3.i = 45 and s4.a + s4.b + s4.c + s5.a + s5.b + s5.c + s6.a + s6.b + s6.c = 45 and s4.d + s4.e + s4.f + s5.d + s5.e + s5.f + s6.d + s6.e + s6.f = 45 and s4.g + s4.h + s4.i + s5.g + s5.h + s5.i + s6.g + s6.h + s6.i = 45 and s7.a + s7.b + s7.c + s8.a + s8.b + s8.c + s9.a + s9.b + s9.c = 45 and s7.d + s7.e + s7.f + s8.d + s8.e + s8.f + s9.d + s9.e + s9.f = 45 and s7.g + s7.h + s7.i + s8.g + s8.h + s8.i + s9.g + s9.h + s9.i = 45 and s1.a + s1.d + s1.g + s4.a + s4.d + s4.g + s7.a + s7.d + s7.g = 45 and s1.b + s1.e + s1.h + s4.b + s4.e + s4.h + s7.b + s7.e + s7.h = 45 and s1.c + s1.f + s1.i + s4.c + s4.f + s4.i + s7.c + s7.f + s7.i = 45 and s2.a + s2.d + s2.g + s5.a + s5.d + s5.g + s8.a + s8.d + s8.g = 45 and s2.b + s2.e + s2.h + s5.b + s5.e + s5.h + s8.b + s8.e + s8.h = 45 and s2.c + s2.f + s2.i + s5.c + s5.f + s5.i + s8.c + s8.f + s8.i = 45 and s3.a + s3.d + s3.g + s6.a + s6.d + s6.g + s9.a + s9.d + s9.g = 45 and s3.b + s3.e + s3.h + s6.b + s6.e + s6.h + s9.b + s9.e + s9.h = 45 and s3.c + s3.f + s3.i + s6.c + s6.f + s6.i + s9.c + s9.f + s9.i = 45) and (s1.a * s1.b * s1.c * s2.a * s2.b * s2.c * s3.a * s3.b * s3.c = 362880 and s1.d * s1.e * s1.f * s2.d * s2.e * s2.f * s3.d * s3.e * s3.f = 362880 and s1.g * s1.h * s1.i * s2.g * s2.h * s2.i * s3.g * s3.h * s3.i = 362880 and s4.a * s4.b * s4.c * s5.a * s5.b * s5.c * s6.a * s6.b * s6.c = 362880 and s4.d * s4.e * s4.f * s5.d * s5.e * s5.f * s6.d * s6.e * s6.f = 362880 and s4.g * s4.h * s4.i * s5.g * s5.h * s5.i * s6.g * s6.h * s6.i = 362880 and s7.a * s7.b * s7.c * s8.a * s8.b * s8.c * s9.a * s9.b * s9.c = 362880 and s7.d * s7.e * s7.f * s8.d * s8.e * s8.f * s9.d * s9.e * s9.f = 362880 and s7.g * s7.h * s7.i * s8.g * s8.h * s8.i * s9.g * s9.h * s9.i = 362880 and s1.a * s1.d * s1.g * s4.a * s4.d * s4.g * s7.a * s7.d * s7.g = 362880 and s1.b * s1.e * s1.h * s4.b * s4.e * s4.h * s7.b * s7.e * s7.h = 362880 and s1.c * s1.f * s1.i * s4.c * s4.f * s4.i * s7.c * s7.f * s7.i = 362880 and s2.a * s2.d * s2.g * s5.a * s5.d * s5.g * s8.a * s8.d * s8.g = 362880 and s2.b * s2.e * s2.h * s5.b * s5.e * s5.h * s8.b * s8.e * s8.h = 362880 and s2.c * s2.f * s2.i * s5.c * s5.f * s5.i * s8.c * s8.f * s8.i = 362880 and s3.a * s3.d * s3.g * s6.a * s6.d * s6.g * s9.a * s9.d * s9.g = 362880 and s3.b * s3.e * s3.h * s6.b * s6.e * s6.h * s9.b * s9.e * s9.h = 362880 and s3.c * s3.f * s3.i * s6.c * s6.f * s6.i * s9.c * s9.f * s9.i = 362880) rockmoose |
|
|
elwoos
Master Smack Fu Yak Hacker
2052 Posts |
Posted - 2005-07-12 : 04:10:58
|
I always wondered if these could be solved using matrix manipulation/linear programming type techniques, aren't they "just" a set of simultaneous linear equations with some contraints?steveAlright Brain, you don't like me, and I don't like you. But lets just do this, and I can get back to killing you with beer. |
|
|
TG
Master Smack Fu Yak Hacker
6065 Posts |
Posted - 2005-07-15 : 13:52:39
|
quote: TG, very fast.For scenario 69, the results are a bit random on my computer.Sometimes a correct, and sometimes an incorrect solution is given, example wrong solution of #69 on my pc:
Yep, the Washington Post puzzles only have 1 possible solution so when I wrote my version I didn't think about the possibility of multiple solutions. I've beefed up my verion to only solve for one solution at a time. If it hits a wall it tries a different "what if" scenario.I also added a puzzle with only 1 pre-set value. It still finishes pretty quickly (about 7 seconds). I think that one is a killer for the brute force versions like Rockmoose's. Although, I am very impressed with the approach and the efficiency his considering the extreme number of possible combinations.Because of the length of the code I'm just going to update my original, flawed post with the corrected version. What a fun waste of time this has been (Thanks nr!)Be One with the OptimizerTG |
|
|
rockmoose
SQL Natt Alfen
3279 Posts |
Posted - 2005-07-15 : 14:25:09
|
>> I think that one is a killer for the brute force versions like Rockmoose'sYes, it will definitely not work.However, to find an answer, You can always add any random pre-sets You want,as long as You don't change the originals, it will give a correct answer if any answer is found.I did a test, for fun, by removing some pre-sets, I aborted this after 15 min, it had found ~ 70 Answers by then.here are the first 3...[/code]puzzleSetup-----------1------452--7--8---8--69-----2-5--1---41-37---1--4-5-----98----------------------select 7*9888*108*6*96*32*6*11304*56*6*100 as NoOfCombinations--------------------------------------------------------------Server: Msg 8115, Level 16, State 2, Line 112Arithmetic overflow error converting expression to data type bigint.Answer is : 313.996.922.537.272.934.400PuzzleSolved --------------------------------------------------------------------179328645246715839385469127932857416564193782718246593651982374897634251423571968179328645246715839385469127932857416564193782718246593651982374827634951493571268179328645246715839385469127932857416654193782718246593561982374897634251423571968[/code]rockmoose |
|
|
Kristen
Test
22859 Posts |
Posted - 2006-01-03 : 12:14:16
|
New Scientist published an article on Sudoku (24/31 December 2005) that gave three examples:-- New Scientist - minimum usage of 17 "hints" (a)set @pStr ='1-----7--' +'2--------' +'---3-----' +'78--6----' +'---4---3-' +'---------' +'-341---5-' +'-5--786--' +'--7---1--'-- New Scientist - minimum usage of 17 "hints" (b)set @pStr ='------6-1' +'-4-2-----' +'---------' +'---7---2-' +'13-------' +'5--4-----' +'4-2-1----' +'----563--' +'-------8-'-- New Scientist - Max. hints with no solutionset @pStr ='281675934' +'96--81572' +'57--29816' +'725148693' +'316792458' +'849536721' +'197863245' +'438257169' +'652914387'which talks about software to generate a puzzle AND establish the level of difficulty in solving it, whilst at the same time making puzzles which are as fun to solve as the human generated one in the newspapers / books etc.So some SQL to generate interesting-to-solve puzzles would be good chaps ... Kristen |
|
|
rockmoose
SQL Natt Alfen
3279 Posts |
Posted - 2006-01-03 : 15:24:06
|
Don't tell me you're still solving soduko puzzles after this thread Kristen !?I don't think they have solved/proved the smallest number of hints necessary to make a solvable puzzle.Is 17 the smallest known still?Excuse my poor search engine skills...rockmoose |
|
|
Seventhnight
Master Smack Fu Yak Hacker
2878 Posts |
Posted - 2006-01-03 : 18:02:04
|
Oh.... by the way... I built a new solver... it usually only takes 8-10 steps, and solves all but the tough and diabolical. I'll figure that out later Drop Table #SudokuProblemDrop Table #SudokuGridGOcreate table #SudokuProblem ( problemNo int PRIMARY KEY, difficulty varchar(10) NOT NULL, notes varchar(200) NOT NULL, settings char(81) NOT NULL UNIQUE )insert #SudokuProblemselect 1,'easy','can be done just applying prune',' 5 7 61 39 7 5 8 839 716 218 439 3 9 6 75 82 8 4 'union all select 2,'easy','this needs pick too',' 3 515 2 64 7 5 63 7 2 7 8 6 4 21 7 8 81 6 917 5 'union all select 200,'easy','this needs pick too',' 3 8 515 2 164 7 5 6347 2 798 6 4521 7 8 3 814 6 9179 6 5 'union all select 3,'tough','this one''s broken: there are 4 possible solutions','2 7 17324 76 268 6 1 8 3 984 14 92568 3 5'union all select 4,'diabolical','',' 2 6 8 58 97 4 37 5 6 4 8 13 2 98 36 3 6 9 'union all select 5,'gentle','','4 9 7 8 562 391 1 5 9 1 1 3 2 6 8 3 9 918 567 6 8 5 2'union all select 6,'moderate','','83 1 6 7 5 9 8 6 5 9 4 6 9 3 9 7 5 9 2 1 8 9 6 87'union all select 7,'moderate','',' 3 6 2 8 19 34 9 5 7 3 5 1 8 9 7 2 7 2 83 46 4 5 7 9 'union all select 8,'moderate','',' 356 9 8 49 8 65 85 12 94 17 64 1 91 8 2 963 'union all select 9,'gentle','','7 2 426 93 9 5 8 7 61 6 3 32 9 5 1 2 19 758 3 6'union all select 10,'moderate','',' 6 1 7 2 95 82 45 38 51 29 91 86 86 53 8 9 5 4 'union all select 11,'moderate','',' 56 421 9 86 2 7 8 4 1 5 3 1 8 7 1 9 47 2 639 41 'union all select 12,'tough','',' 1282 4 9 7 7 3 4 1 2 3 5 8 6 9 1 7 6 1 9 2 3 7528 'union all select 13,'diabolical','',' 125 487 75 23 41 87 2 5 4 34 95 48 17 357 169 'union all select 49,'diabolical','',' 6 29 4 5 3 7 14 7 54 53 24 12 3 54 1 6 8 5 82 5 'union all select 55,'diabolical','','2 3 8 4 62 3 138 39 5 7 6 1 32 914 6 25 8 9 1 2'union all select 62,'diabolical','',' 4 6 51 9 6 8 3 47 1 62 8 6 47 5 13 4 6 1 2 38 6 9 'union all select 69,'diabolical','',' 81 6551 67 8 9 4 3 61 97 5 3 8 6 78 9317 59 'union all select 76,'diabolical','',' 1 4 95 17 78 56 4 97 5 8 3 54 1 62 41 19 86 7 9 'union all select 101,'diabolical','pretty easy one from Washington Post',' 7 1 2 9 564 6 1 4 9 157 832 7 6 9 2 359 4 6 7 8 'union all select 141,'diabolical','medium easy one from Washington Post','1 452 7 8 8 69 2 5 1 41 37 1 4 5 98 3 6 1 884 1'declare @problemNo intset @problemNo = 141 ----------------<-------------------- CHOOSE PROBLEMdeclare @n table(n tinyint primary key)insert @nselect 1 union select 2 union select 3 union select 4 union select 5union select 6 union select 7 union select 8 union select 9Delete From #SudokuProblem Where problemNo <> @problemNoSelect row = Row.n, col = Col.n, grid = ((Col.n-1)/3+1)*10 + ((Row.n-1)/3+1), Data = convert(int,nullif(substring(settings,(Row.n-1)*9 + Col.n,1),' '))Into #SudokuGridFrom #SudokuProblemCross Join @n ColCross Join @n RowDeclare @counter int, @currentGrid varchar(1000)Set @counter = 0Select count(*) From #SudokuGrid Where Data is nullSet @currentGrid = nullSelect @currentGrid = isnull(@currentGrid,'') + isnull(convert(varchar,Data),' ') From #SudokuGrid Order by row, colSelect Step=@counter, Unsolved = count(*), @currentGrid From #SudokuGrid Where Data is nullSet @counter = @counter + 1While (@counter < 20 and (Select count(*) From #SudokuGrid Where Data is null)>0)Begin Drop Table #options Select Z.row, Z.col, Z.grid, Z.Data, n = Y.n, Y = Y.n, X = X.n, W = W.n Into #options From (Select A.* From #SudokuGrid A Where Data is null) Z Inner Join ( Select A.row, n From (Select distinct row, n From #SudokuGrid, @n) A Left Join (Select row, Data From #SudokuGrid Where Data is not null) B On A.row = B.row and A.n = B.Data Where B.data is null ) Y On Z.row = Y.row Inner Join ( Select A.col, n From (Select distinct col, n From #SudokuGrid, @n) A Left Join (Select col, Data From #SudokuGrid Where Data is not null) B On A.col = B.col and A.n = B.Data Where B.data is null ) X On Z.col = X.col Inner Join ( Select A.grid, n From (Select distinct Grid, n From #SudokuGrid, @n) A Left Join (Select grid, Data From #SudokuGrid Where Data is not null) B On A.grid = B.grid and A.n = B.Data Where B.data is null ) W On Z.grid = W.grid Where Y.n = X.n and X.n = W.n Update #SudokuGrid Set Data = n From #SudokuGrid Z Inner Join ( Select Z.* From #options Z Inner Join ( Select grid, n From #options A Group By grid, n Having count(*) = 1 ) Y On Z.grid = Y.grid and Z.n = Y.n Union Select Z.* From #options Z Inner Join ( Select col, n From #options A Group By col, n Having count(*) = 1 ) Y On Z.col = Y.col and Z.n = Y.n Union Select Z.* From #options Z Inner Join ( Select row, n From #options A Group By row, n Having count(*) = 1 ) Y On Z.row = Y.row and Z.n = Y.n Union Select A.* From #options A Inner Join ( Select row, col From #options Group by row, col having count(*) = 1 ) B On A.row = B.row and A.col = B.col ) Y On Z.row = Y.row and Z.col = Y.col Set @currentGrid = null Select @currentGrid = isnull(@currentGrid,'') + isnull(convert(varchar,Data),' ') From #SudokuGrid Order by row, col /* --Step by step solution Select Step=@counter, Unsolved = count(*), @currentGrid From #SudokuGrid Where Data is null */ Select @Counter = @Counter + 1 End Select Step=@counter-1, Unsolved = count(*), @currentGrid From #SudokuGrid Where Data is null--Select * From #SudokuGrid CoreyCo-worker on children "...when I have children, I'm going to beat them. Not because their bad, but becuase I think it would be fun ..." |
|
|
Kristen
Test
22859 Posts |
Posted - 2006-01-04 : 08:08:56
|
"I don't think they have solved/proved the smallest number of hints necessary to make a solvable puzzle.Is 17 the smallest known still?"Haven't got the New Scientist in front of me, but IIRC the article said that 17 was the fewest possible number of hints, but that 17 hints didn't imply difficultly - I think their two examples were of Easy / Hard, but the article wasn't clear on why they gave two 17-hint examples.Kristen |
|
|
Next Page
|
|
|
|
|