How to Start a Software Company 2.0

by Richard Rodger

       
 
Sudoku, Part Three

With the sudoku program I hacked together in the last post, I was able to solve the Irish Independent's Super Sudoku for three weeks running. But then, disaster! It turns out that sudoku puzzles can be pretty fiendish - they are still solvable with a very small set of given numbers.

So my initial logic, just continuously removing numbers that could not possibly be in a cell, did not solve all sudokus. Time for a rethink. After staring at the unsolved output for a while, it occurred to me that sometimes you end up with a set of cells in a vertical, horizontal or home square that are all unsolved, but where only one cell contains a certain number. So lets say the top three cells on the left are 123, 234, 234, with all others in the top row solved. Well then the top left cell must be 1. There are no other possibilities, it's the only place for that number. Now we're suckin' diesel.

For some reason, I think of this new operation as "reducing" the cell possibilities, so henceforth to the code:

sub reduceHome {
  my @cell = @{shift()};
  my $prow = shift;
  my $pcol = shift;

  my $valbin = $cell[$prow][$pcol];
  if( 1 == keys(%{$valbin}) ) {
    return;
  }

  my $foundval;
  for my $val (keys(%{$valbin})) {

    my $found = 0;
    for( my $r = $sqsize*floor($prow / $sqsize); 
         $r < $sqsize*floor(($prow+$sqsize) / $sqsize); 
         $r++ ) {

      for( my $c = $sqsize*floor($pcol / $sqsize); 
           $c < $sqsize*floor(($pcol+$sqsize) / $sqsize); 
           $c++ ) {

        if( $prow != $r || $pcol != $c ) {
          my $testbin = $cell[$r][$c];

          if( "" ne ${$testbin}{$val} ) {
            $found = 1;
          }
        }
      }
    }
    if( !$found ) {
      $foundval = $val;
      last;
    }
  }

  if( "" ne $foundval ) {
    for my $val (keys(%{$valbin})) {
      if( $val ne $foundval ) { 
        delete(${$valbin}{ $val });
      }
    }
  }
}

Yikes. Well what does this monstrosity do? Again I plead guilty to all charges of hacking and offer this code as final proof that Perl is meant to be written, not read. So this just runs through all the cells in the home square of a given cell: $prow, $pcol. The ugly nested for loop in the middle does that by keeping us within the bounds of the home square. So if we're cell 2,2 in a 3x3 sudoku, the home square is defined as all the cells in the range 0,0 - 3,3.

Now, as we run through the cells, if we come across a value $foundval, that is only in one cell, then we can delete all the other numbers from that cell. That's what the last for loop does in a rather pointless way - why not just create a new map with just one entry? I don't know, I was cut-n-pasting I guess.

This operation is also performed horizontally and vertically, so our main loop now does all this:

excludeHome(\@cell,$rowI,$colI);
excludeVertical(\@cell,$rowI,$colI);
excludeHorizontal(\@cell,$rowI,$colI);
reduceHome(\@cell,$rowI,$colI);
reduceVertical(\@cell,$rowI,$colI);
reduceHorizontal(\@cell,$rowI,$colI);

I'd say that's efficient alright. So did this help? You bet! I got another two weeks out of this baby. But, yeah, you guessed, still not enough. Even this code won't solve all sudokus. There's another trick that I came up with though, and we'll look at that the next time.

This post is part of a series on a Perl Suduko solver.

@ 05:04 PM GMT+00:00 [ comments [5] ]   email this   links to this

If you liked this entry, please consider bookmarking it &mdash Thanks!
Bookmark Sudoku, Part Three at del.icio.us Digg Sudoku, Part Three at Digg.com Bookmark Sudoku, Part Three at reddit.com Bookmark Sudoku, Part Three at YahooMyWeb Bookmark Sudoku, Part Three at Spurl.net Bookmark Sudoku, Part Three at Simpy.com Bookmark Polyphasic Mutants at NewsVine Blink this Sudoku, Part Three at blinklist.com Bookmark Sudoku, Part Three at Furl.net Fark Sudoku, Part Three at Fark.com

 
 
Trackback URL: http://www.richardrodger.com/roller/trackback/richard/Weblog/sudoku_part_three
Comments:

Sounds like a "hidden single candidate" to me - http://www.angusj.com/sudoku/hints.php

Posted by Maik (212.79.22.193) on November 08, 2005 at 05:53 PM GMT+00:00
Website: http://www.blizzy.de #

You're only scratching the surface. This trick will get you a bit further but will still stall on more complex grids. I suggest you look up "naked pairs", "naked triplets" and "x wing". These are strategies that are indispensable if you want to be able to solve harder Sudokus. And there are many more (the Strategy design pattern comes in very handy for that, and you should seriously consider switching to a more humane language to Perl :-)).

--
Cedric

Posted by Cedric on November 08, 2005 at 11:36 PM GMT+00:00
Website: http://beust.com/weblog #

[note to self - don't bother playing the irish independent's version of sudoku, it would be no fun]

Posted by 62.252.0.11 on November 09, 2005 at 12:45 AM GMT+00:00 #

You're right Cedric - Perl gets nasty quite quickly. I wonder will I port it to Ruby or Python and see how that looks? Sounds like a job for a rainy afternoon.

I deliberately refrained from looking up sudoku hints when writing this as a sort of personal challenge. Afterwards I did some research and it seems that the best approach involes some scary graph traversal algorithms. That's fine, but I do want to see how far a simple approach can go.

Posted by Richard Rodger on November 09, 2005 at 10:31 AM GMT+00:00
Website: http://www.ricebridge.com #

You're going about this the hard way. Create an outer loop that looks at each VACANT cell on the board and, for that cell, calls the subroutine 'alternatives' (or whatever). The 'alternatives' sub looks at the list of integers 1 thru 9, and then eliminates from consideration any A) used elsewhere in the row of 9 the cell is in, B) used elsewhere in the column of 9 the cell is in, and C) used in the 'local' 3x3 matrix the cell is in. Have the 'alternatives' sub return the array of values that could still be used in the cell after you eliminate these others.

If the array returned is empty, stop ... that means nothing fits in this cell and you're at a dead-end. If the array returned has one value, place that value in the cell (so it is no longer VACANT), and then start over. Repeat until there are no VACANT cells.

Sometimes you'll get a board where the lowest number of alternatives is > 1 for any of the vacant cells, and then your program has to try each in turn. Recursion is well-supported in Perl and very useful here. Go to this Sudoku solver to see this approach in action.

Posted by Mark on November 13, 2005 at 02:22 PM GMT+00:00
Website: http://puzzles.vandine.biz #

Comments for this have been disabled. Please send me a mail if you want to comment and I will activate comments again.
 
YahooBloglines
NewsgatorMSN
Google Readerdel.icio.us FurlSubscribe with myFeedster
« November 2005 »
SunMonTueWedThuFriSat
  
5
12
13
19
20
21
24
26
27
   
       
Today

All | General | Java | Business | Fun | Perl | Rant | Ireland | Web
[This is a Roller site]
[Valid Atom 1.0] [Valid RSS]
Technology Blog Top Sites
Blogarama - The Blogs Directory

Blog Directory & Search engine

Blog Flux Directory
Irish Blogs
 View My Public Stats on MyBlogLog.com

Performancing
Enter your Email


Powered by FeedBlitz
Theme adapted from Sotto.
 
Ricebridge XML Manager
  • Convert XML to a table of data
  • Convert XML to CSV, and CSV to XML
  • High-speed, single-pass XPath
  • Memory-stable and fault-tolerant
  • Loads of documentation
  • Cut-and-paste code examples
  • Find a bug, get a gift cert
Ricebridge Java XML Manager Component


Ricebridge CSV Manager
  • Convert CSV to a table of data
  • Handle any type of delimited file
  • Memory-stable and fault-tolerant
  • Loads of documentation
  • Cut-and-paste code examples
  • Find a bug, get a gift cert
Ricebridge Java CSV Manager Component


Popular Posts

 Sign up for MyBlogLog.com
Alertra Website Monitoring Service
Get Chitika eMiniMalls
Solo Tees
BlogJet