|
View previous topic :: View next topic |
Author |
Message |
| rwaddilove
| Joined: 17 Mar 2006 | Posts: 5 | : | | Items |
|
Posted: Fri Mar 17, 2006 12:02 pm Post subject: Four line sudoku solver |
|
|
Sudoku puzzles can be solved with just 4 lines of code. Here's it is:
1 sp(cell(ptr))=(sp(cell(ptr)) + 1) mod 10
2 if sp(cell(ptr))=0 then ptr=ptr+1:goto 1
3 if countnum(cell(ptr))=3 then ptr=ptr-1
4 if ptr>-1 then goto 1
Of course, it needs a bit of explanation. This is a brute force method, but it is so short and simple that it is very fast. You need to create two arrays and a pointer like this:
sp(80) is the sudoku puzzle - 9 x 9 grid, 81 cells, numbered 0-80
cell(80) is a list of blank cells - when you read in the puzzle, store the blank cell numbers here
ptr=points to the last blank cell in the list
One other thing you need is a countnum() function. This counts how many times a number appears. It should appear once in a row, once in a column and once in a block, hence the if countnum()=3 then...
That's it. You want to see some real code? Here it is in Visual Basic - I dislike goto so the structured version is a little longer:
Code: |
While ptr > -1
sp(cell(ptr)) = (sp(cell(ptr)) + 1) Mod 10
If sp(cell(ptr)) = 0 Then
ptr = ptr + 1
Else
If CountNum(cell(ptr)) = 3 Then ptr = ptr - 1
End If
Wend
|
That's the main program loop that solves the puzzle in sp() - just print out the array afterwards to see the solution. The CountNum() function just counts the occurances like this:
Code: |
Function CountNum(ByVal n As Integer) As Integer
Dim i, j, k, r, c As Integer
k = 0 'count
'check the row and column
r = n \ 9 'row 0-8
c = n Mod 9 'column 0-8
For i = 0 To 8
If sp(r * 9 + i) = sp(n) Then k = k + 1 'row
If sp(c + i * 9) = sp(n) Then k = k + 1 'column
Next
'check the block
c = 3 * (c \ 3) 'left column of block 0/3/6
r = 3 * (r \ 3) 'top row of block 0/3/6
For i = 0 To 2
For j = c To c + 2
If sp((r + i) * 9 + j) = sp(n) Then k = k + 1
Next
Next
CountNum = k
End Function
|
This function could be made faster by checking the row and exiting if there's more than one, then checking the column and exiting if more than one, then checking the block. It would save some checking. However, it seems fast enough as it is. VB isn't particularly quick, but simple puzzles are solved instantaneously and the hard ones only take 5 or 10 seconds. |
|
Back to top |
|
|
| rwaddilove
| Joined: 17 Mar 2006 | Posts: 5 | : | | Items |
|
Posted: Sun Mar 19, 2006 9:34 am Post subject: The difference a compiler makes... |
|
|
I tracked down the hardest puzzle I could find on this board and ran it through the Visual Basic program above. It took about 40 seconds to solve. Removing the For...Next loops in the CountNum function and writing out the code in full reduced this to 9 seconds, which is quite a saving.
However, seeing other people talking of solving puzzles in milliseconds left me slightly disappinted to say the least.
I copied the code from VB and pasted it into Blitz Basic. Hardly any changes were required to get it working and when I ran the same puzzle, it was solved in around 700 milliseconds. It just shows what a difference the compiler makes.
I wonder if C would be even faster?
Can anyone write in assembly language these days? Presumably this would be the ultimate, but I've not done this since the days when everything was Z80 or 6502 powered. |
|
Back to top |
|
|
| tarek
| Joined: 31 Dec 2005 | Posts: 153 | : | Location: London, UK | Items |
|
Posted: Sun Mar 19, 2006 11:33 am Post subject: |
|
|
I actually had one of those,
It was revolutinary in its time as it had a whole 1KB of memory....which then can be expanded to a " 16 KB " memory, I wouldn't have thought that it would withstand DLX or even brute force to be honest
Tarek |
|
Back to top |
|
|
| rwaddilove
| Joined: 17 Mar 2006 | Posts: 5 | : | | Items |
|
Posted: Sun Mar 19, 2006 1:30 pm Post subject: Down memory lane |
|
|
You're thinking of the ZX-81, I think. I was just talking about the Z80 processor in general, which was used in several different computers. You could quite easily write a soduku solver for the ZX-81 because it requires very little memory and only about 20 or 30 lines of Basic. Mind you, it would take about 3 days to come up with a solution! Anyone want to try this with a ZX-81 emulator? |
|
Back to top |
|
|
| LangPol
| Joined: 20 Mar 2006 | Posts: 6 | : | | Items |
|
Posted: Mon Mar 20, 2006 2:18 pm Post subject: Re: Four line sudoku solver |
|
|
Never, ever, throw out something like that. It sounds like a challenge.
Here's a Perl version, not mine, andall you need is the array A:
use integer;@A=split//,<>;sub R{for$i(0..80){next if$A[$i];my%t=map{$_/9
==$i/9||$_%9==$i%9||$_/27==$i/27&&$_%9/3==$i%9/3?$A[$_]:0=>1}0..80;R($A[
$i]=$_)for grep{!$t{$_}}1..9;return$A[$i]=0}die@A}R
3 lines. |
|
Back to top |
|
|
| foxglove
| Joined: 04 Feb 2006 | Posts: 42 | : | Location: Portugal | Items |
|
Posted: Mon Mar 27, 2006 6:34 pm Post subject: Re: Four line sudoku solver |
|
|
rwaddilove wrote: | Sudoku puzzles can be solved with just 4 lines of code. |
You are right, but...
Here is a very fast to solve:
Code: |
9 . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
|
and here one that takes a looong time to solve:
Code: |
4 . 7 9 . . . . 3
. 1 2 . 6 . 5 7 9
. . . . . . . 8 .
. . . . . 7 . . .
3 5 . . 8 . . 6 7
. . . 5 . . . . .
. 9 . . . . . . .
6 8 4 . 9 . . 3 .
2 . . . . 3 6 . 4
|
so, to be really right, you should say: proper Sudoku puzzles can be solved with just 4 lines of code. |
|
Back to top |
|
|
| elroy
| Joined: 16 Mar 2006 | Posts: 6 | : | | Items |
|
Posted: Sat Apr 01, 2006 7:19 pm Post subject: |
|
|
rwaddilove fm elroy:
Even in VB, your cute algorithm can be speeded 60 times faster * - and be smaller - if done in the "quise" of machine-language & bit-manipulation as you inclined:
Your complete VB routine, for example, could evolve to following, requiring just initial setup of its arrays (for which, further below at bottom, an illustrative example/working macro [Excel] is also submitted)
Code: | Sub SolveIt(S%(),L%(),p%,rq%(),cq%(),bq%(),M%()): Dim r%,c%,b%,t%,u%,q%
While p > 0: r = L(p, 0): c = L(p, 1): b = L(p, 2): t = S(r, c) '<cell info
u = t: q = rq(r) Or cq(c) Or bq(b): DO: If u = 0 Then u = 1 Else u = u + u
Loop While u And q: If u > 256 Then u = 0: p = p + 1 Else p = p - 1
S(r, c) = u '<update cell (S) to new value, also update the 3 queues>
t = (u - t): rq(r) = rq(r) + t: cq(c) = cq(c) + t: bq(b) = bq(b) + t
Wend: End Sub 'puzzle completely solved 'notes: M not used here
| Cells/Queues: Cell-vals (1-9) are stored as unique bit in 9-bit word (ie, 8 = b8, w/ only 1 bit "on" at any time), whereas a candidate Queue, in essence, is an "extra" cell for each row/col and box but with any combination of its 9 bits "on" any time, representing all current cell-values in that row/col/box: In above, the (nine) "row" queues for example are the array rq().. The target-cell value is "incremented" (by doubling) until a "hole" is found in combined bit-mask of the three applicable queues or until so forced from 9 to 0 (no bit on).
Even faster (130%) is the following:
Code: | Sub SolveIt(S%(), L%(), p%,rq%(),cq%(),bq%(),M%()) :Dim r%,c%,b%,t%,u%,q%
While p > 0: r = L(p, 0): c = L(p, 1): b = L(p, 2): t = S(r, c) '<cell info
q = t + t + (t > 0) Or rq(r) Or cq(c) Or bq(b) '<candidate mask
u = M(q, 0): p = p + M(q, 1): S(r, c) = u: '<lookup new val & pointer dir
t = (u - t): rq(r) = rq(r) + t: cq(c) = cq(c) + t: bq(b) = bq(b) + t
Wend: End Sub 'puzzle solved. '(notes: true=(-1); t+t-1 = t +any lower bits)
| Here M is lookup table of pre-calc'd candidate-solution/pointer-control (analogous to rom-mapped processing) which eliminates serial incrementing (table-generator is included in same import/export-macro (Excel) below); Yes, expression "t+t+(t>0)" in above could also be similarly pre-mapped (function of t) but buys no VB speed.
<>
** And I know as you know, an important speed-player (factor of 3) in high-level like VB is that all possible variables/arrays in highly-repetitive routines are assuredly/PROPERLY declared As Integer (or %).. so perhaps maybe the above isn't really 60 times faster but only 21 times or so - just meant to draw some important attention to that -- and now here's example Excel-based puzzle import/exporter (host program): Code: | Sub MacroImportExportPuzzleFmToWorksheet() '(1st nine rows/cols of wksht):
Dim S%(8, 8), L%(81, 3), rq%(8), cq%(8), bq%(8), p%, r%, c%, b%, t, x%, y%
Dim M%(511, 1) 'make table(for wherever used): candidate & pointer resolver
For y = 0 To 511: x = 1: While x And y: x = x + x: Wend: x = x And 511 _
: M%(y, 0) = x: M%(y, 1) = 1 + 2 * (x > 0): Next '(true = -1 in basic)
For Each t In [A1:I9] 'make list L = row/col/box of each (0)cell(target t)
r = t.Row - 1: c = t.Column - 1: b = (r \ 3) * 3 + c \ 3 'b =box# 0-8
If t = 0 Then x = 0: p = p + 1: L(p, 0) = r: L(p, 1) = c: L(p, 2) = b _
Else x = 2 ^ (t - 1) '(x = t as a mapped binary-bit (b1-b9)
S(r, c) = x: rq(r) = rq(r) Or x: cq(c) = cq(c) Or x: bq(b) = bq(b) Or x
Next: Call SolveIt(S, L, p, rq, cq, bq, M) '<GO SOLVE WHOLE PUZZLE
For Each t In [A1:I9]: Let x = S(t.Row - 1, t.Column - 1): Let y = 10
While (x > 0): x = x + x And 511: y = y - 1: Wend: t.Value = y 'send it
Next: End Sub '(S=puzzle; rq/cq/bq = canditate-queue for each row/col/box)
| NOTE: Worksheet-cells in Excel (especially if originally imported to wksht as text) stubbornly aren't always recognized numeric even if one tries to reformat them, test by seeing if they can be made to show a decimal format.
<>
Your basic simple algorthm is a handy speedy no-nonsense little guy - can also check unigueness/validity, etc, easily imbedded in any higher host analytic-program. Thanks for sharing it.
I wonder what your Blitz Basic could further make of this?
Elroy
Last edited by elroy on Sun Apr 02, 2006 4:55 am; edited 8 times in total |
|
Back to top |
|
|
| elroy
| Joined: 16 Mar 2006 | Posts: 6 | : | | Items |
|
Posted: Sat Apr 01, 2006 7:40 pm Post subject: |
|
|
BTW here's a good valid test-puzzle - Vidarino's old "Monster #2:
Code: | |8..|4..|6..|
|.3.|.6.|.7.|
|..7|...|..2|
|---+---+---|
|1..|6..|3..|
|.7.|.4.|.8.|
|..3|..9|..6|
|---+---+---|
|...|8..|4..|
|.9.|.5.|.2.|
|..1|...|..5| | elroy |
|
Back to top |
|
|
| Agent Allen
| Joined: 01 Oct 2005 | Posts: 34 | : | | Items |
|
Posted: Sun Apr 02, 2006 9:00 pm Post subject: Re: Four line sudoku solver |
|
|
LangPol wrote: | Never, ever, throw out something like that. It sounds like a challenge.
|
Emulator, pah! Surely someone has got a ZX81 under their bed they can blow the dust off?
You should find it under your Adam and the Ants T-Shirt and next to your Starsky & Hutch toy car!
Alternatively, I see ZX81's fetch about £30.00 on eBay.
They cost about £70.00 originally!
Not a collectors item just yet...
Go on someone... _________________ Agent A |
|
Back to top |
|
|
| docnzok
| Joined: 10 Apr 2006 | Posts: 1 | : | | Items |
|
Posted: Mon Apr 10, 2006 8:34 pm Post subject: Testing your theory |
|
|
Hey,
I am trying to test your code in VB, but am having trouble accessing the array member that is stored with the pointer.
Can you send me the code that you used to declare the pointer and then how you access that memory location.
I am in sync with everything else you are doing.
Thanks
I declare the pointer like this.
Dim ptr As Long
The set it like this
ptr = VarPtr(cell(x))
I get a memory address correctly using this technique but when I try to reference the ptr using your code:
sp(cell(ptr))
I get out of range because the memory address is way higher than the original cell(80) declaration.
Thanks |
|
Back to top |
|
|
| Germanboy
| Joined: 10 May 2006 | Posts: 1 | : | | Items |
|
Posted: Wed May 10, 2006 11:29 am Post subject: complete source code |
|
|
who can send me the complete source code (all parts zipped)? iI cannot understand the whole code from rwaddilove!
Thanks
Germanboy |
|
Back to top |
|
|
| Lunatic
| Joined: 11 Mar 2007 | Posts: 166 | : | Location: Ghent - Belgium | Items |
|
Posted: Wed Mar 14, 2007 10:24 pm Post subject: |
|
|
I've put a small VB6 program on my website to test any sudoku if it has one, more then one or no solution at all. The program is based on the code from rwaddilove.
Since this is my first posting in this forum, I'm not allowed to post any URL, so contact me if you want me to send the zipped source code.
Greetz,
Lunatic |
|
Back to top |
|
|
| Pat
| Joined: 06 Sep 2006 | Posts: 128 | : | | Items |
|
Posted: Fri Mar 16, 2007 9:48 am Post subject: re: Website |
|
|
Lunatic wrote: |
Since this is my first posting in this forum, I'm not allowed to post any URL
|
but you are allowed to indicate the URL of your Website --
in your Profile !
|
|
Back to top |
|
|
| Lunatic
| Joined: 11 Mar 2007 | Posts: 166 | : | Location: Ghent - Belgium | Items |
|
Posted: Thu Mar 22, 2007 11:28 pm Post subject: |
|
|
Ok, I have rearranged my website so that the zipped file of the sudoku test can be downloaded easely.
I also added my website's url at my profile. Choose "English" and then "Sudoku". You'll find a screenshot of the little program and a link to download.
I've included some basic solving techniques in the sudoku uniqueness tester, to assist solving (pre-solve) before the brute force solving. There's an evil sudoku in .txt format in the zipped file (to be dragged 'n' dropped). There are some additional lines added at the brute force routines, so one can see the brute force at work on screen, but this will slow down the proces. You can even dowload my own sudoku programm 'MPQ Sudoku' from my website.
Have fun. _________________ Marc
~~~<><~~~<><~~~<><~~~<><~~~ |
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
Igloo Theme Version 1.0 :: Created By: Andrew Charron
|