Sudoku Programmers Forum Index

 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister   ProfileProfile   Log inLog in          Games  Calendar

Log in to check your private messagesLog in to check your private messages   

OO approach to solving

 
Post new topic   Reply to topic    Sudoku Programmers Forum Index -> Programming sudoku
View previous topic :: View next topic  
Author Message
Aidy

Joined: 26 Jul 2005
Posts: 2
:

Items
PostPosted: Tue Jul 26, 2005 6:54 pm    Post subject: OO approach to solving Reply with quote

(this is in c# but the principals apply to any OO language)

Most solvers I've seen so far use a multi-dimensional 9x9 array to store the grid. For the ones that don't use pure brute force this has resulted in some rules being written three times, one for rows, one for columns and one for blocks.

I took a slightly different object orientated approach to storing the grid. At the heart it still relies on a multidimensional arrays, however there is a "block" object which is a 3x3 array of "cell" objects. The "grid" object is then a 3x3 array of "block" objects.

By holding the data in such a way it has made some rule processing easier. For any rule that works on a set of nine numbers be it a row, column or block, I have it work on just a number set of 9 numbers. So to apply a rule to a row I get a number set from the row on the grid and apply the rule to that number set. If the rule is to work on a column then I create a number set from the column and apply the rule to that number set. Similarly if it is to apply to a block a get a number set from the block and apply the rule. As the rule is working on the number set and *not* a row/column/block the rule code is completely generic and the same code can be used on all three.

My Grid object calls three sub-routines to apply row/column/block specific rules;

Code:

ReCalculateBlocks();
ReCalculateRows();
ReCalculateColumns();

....

private void ReCalculateBlocks()
{
   // Loop through each block in the 3x3 grid
   for (int i = 0; i < 3; i++)
   {
      for (int j = 0; j < 3; j++)
      {
         // Create a new number set to hold the block values
         NumberSet numberSet = new NumberSet();
         // Add the relevant block's numbers to the number set
         numberSet.AddBlock (this.blocks[i,j]);
         // Tell the number set to recalculate.
         // This will apply the number set specific rules to it
         numberSet.ReCalculate();
      }
   }
}

private void ReCalculateRows()
{
   // Loop for each row
   for (int i = 0; i < 9; i++)
   {
      // Get that row as a number set
      NumberSet numberSet = GetRow(i);
      // Tell the number set to recalculate.
      // This will apply the number set specific rules to it
      numberSet.ReCalculate();
   }
}

private void ReCalculateColumns()
{
   // Loop for each column
   for (int j = 0; j < 9; j++)
   {
      // Get that column as a number set
      NumberSet numberSet = GetColumn(j);
      // Tell the number set to recalculate.
      // This will apply the number set specific rules to it
      numberSet.ReCalculate();
   }
}



This is the recalculate code. As you can see it is totally unaware if the number set it is working on is a row, column or block. This abstraction lets us write the rule only once for a set of generic 9 numbers.

Code:

public void ReCalculate()
{
   // Pass this number set to the SolvedNumbers class
   // If a number in the row is a solved number then it will be
   // removed as a possibility from other cells in that number set
   SolvedNumbers.CheckNumberSet (this);

   // Pass this number set to the NumberPairs class
   // If two cells contain the same number pair only then each
   // number in the pair must be in one of those cells so remove
   // those numbers from the possibilility list of other cells
   // in the set
   NumberPairs pairs = new NumberPairs(this);

   // Pass this number set to the NumberPairs class
   // If there are N numbers in N subgroups remove the possibility
   // that any other number apart from ones in the group can be
   // possible
   UniqueSubset.CheckNumberSet(this);

}


To introduce a new rule we code it into a class that applies the rule to the number set then add it to the list of rules in the ReCalculate class.

Not all rules work only on a row/column/block so if it is applied to the whole grid it is invoked via the grid's ReCalculate method;

Code:

ReCalculateBlocks();
ReCalculateRows();
ReCalculateColumns();

XWing.CheckGrid(this);


So for each iteration we recalculate each row/column/block, then we apply the grid-specific rules in much the same way. Each rule has its own class and this time we pass the whole grid to the class. In my demo the only grid-wide algorithm I have implemented is the X-Wing algorithm, but if more are written they will just slot in below the Xwing one.

As I mentioned before, each block is an array of "cell" objects. Each cell is a list of possible numbers and it provides methods for adding possibilities, removing them and setting a final solution if it becomes known.

Code:

public class Cell
{
   private ArrayList possible = new ArrayList(9);
   
   public Cell()
   {
      for (int i = 1; i<10; i++)
         possible.Add(i);
   }

   public ArrayList PossibleNumbers
   {
      get
      {
         return this.possible;
      }
   }

   public string PossibleNumbersDisplay
   {
      get
      {
         string ret = "";

         foreach (int number in this.possible)
            ret = string.Concat(ret, " ", number.ToString());

         return ret.Trim();
      }
   }

   public void RemovePossible (int number)
   {
      possible.Remove(number);
   }

   public void AddPossible (int number)
   {
      if (!possible.Contains(number))
         possible.Add(number);
   }

   public void MakeSolution (int number)
   {
      possible.Clear();
      if (number > 0 && number < 10)
         possible.Add (number);
   }

   public void RemovePossible (params int[] numbers)
   {
      foreach (int number in numbers)
         possible.Remove(number);
   }


As you can see from the constructor (Public Cell) upon creation it automatically sets itself has having 1-9 as possible solutions. As our algorithms find numbers that it is possible to eliminate it simply calls the RemovePossible method of the cell in question.
Back to top
View user's profile Send private message
Michael Kennett

Joined: 21 Jul 2005
Posts: 11
:
Location: Adelaide, South Australia

Items
PostPosted: Fri Jul 29, 2005 7:34 am    Post subject: Reply with quote

Hi Aidy,

Another way of achieving what you want (generic functions for processing rows/columns/blocks) is to use function pointers in C. For example, here is a (edited) snippet of code I've written:

Code:
#define INDEX(row,col)          (9*(row)+(col))

static
int
idx_row( int el, int idx )      /* Index within a row */
{
    return INDEX( el, idx );
}

static
int
idx_column( int el, int idx )   /* Index within a column */
{
    return INDEX( idx, el );
}

static
int
idx_block( int el, int idx )    /* Index within a block */
{
    return INDEX( 3 * ( el / 3 ) + idx / 3, 3 * ( el % 3 ) + idx % 3 );
}

/* Find all squares with a single digit allowed -- do not mutate board */
static
void
singles( int el, int (*idx_fn)( int, int ), int hintcode )
{
    int i, j, idx;

    count_set_digits( el, idx_fn );

    for( i = 0 ; i < 9 ; ++i )
    {
        if( 1 == counts[ i ] )
        {
            /* Digit 'i+1' appears just once in the element */
            for( j = 0 ; j < 9 ; ++j )
            {
                idx = (*idx_fn)( el, j );
                if( !DISALLOWED( idx, i + 1 ) && idx_possible < 81 )
                    possible[ idx_possible++ ] = SET_INDEX( idx )
                                               | SET_DIGIT( i + 1 )
                                               | hintcode;
            }
        }
        if( 8 == digits[ i ] )
        {
            /* 8 digits are masked at this position - just one remaining */
            idx = (*idx_fn)( el, i );
            for( j = 1 ; j <= 9 ; ++j )
                if( 0 == ( STATE( idx ) & DIGIT_STATE( j ) ) && idx_possible < 81 )
                    possible[ idx_possible++ ] = SET_INDEX( idx )
                                               | SET_DIGIT( j )
                                               | hintcode;
        }
    }
}

/* Find, and return the number of, moves possible
 */
static
int
findmoves( void )
{
    int i;

    idx_possible = 0;
    for( i = 0 ; i < 9 ; ++i )
    {
        singles( i, idx_row, HINT_ROW );
        singles( i, idx_column, HINT_COLUMN );
        singles( i, idx_block, HINT_BLOCK );
    }
    return idx_possible;
}


Hopefully the above snippet illustrates the idea. The processing (for finding squares that can contain only one digit) is controlled by the index function.

Regards, Michael
Back to top
View user's profile Send private message Visit poster's website
dxc31202

Joined: 06 Oct 2005
Posts: 1
:
Location: London

Items
PostPosted: Thu Oct 06, 2005 4:24 pm    Post subject: Re: OO approach to solving Reply with quote

Hi,

This looks like an excellent method, I was using a similar idea in an object approach for my next gen solver only I had a section, row and column class. I do think that this approach cuts down on a lot of issues though

I would be very interested to see how you solved the various checks with this 3x3 method for rows and columns, is there any chance of seeing the complete code ?

This is my first gen code, written in VB.Net about a year ago and very procedural. This can be made into a standalone DLL just pass in a an 8 by 8 grid and it returns a completed one (if it can) and seems to solve most puzzles I've given it and it's pretty quick too
Code:
Imports System.Text

Namespace Soduko

    Public Class Puzzle

        Private Shared mWork(8, 8) As Integer      ' This is our working puzzle
        Private Shared Candidates(8, 8) As String ' potential entries for each cell

        Public Property Grid() As Integer(,)
            Get
                Return mWork
            End Get
            Set(ByVal Value As Integer(,))
                mWork = Value
            End Set
        End Property

        Public Shared Function Solve(ByVal pGrid(,) As Integer) As Integer(,)
            mWork = pGrid
            Return Solve()
        End Function

        Public Shared Function Solve() As Integer(,)
            Dim completed As Integer
            Dim lastCompleted As Integer
            Do
                ' Reset the completed flag
                completed = 0
                ' calculate the potential values for each cell
                For row As Integer = 0 To 8
                    For col As Integer = 0 To 8
                        If mWork(row, col) <> 0 Then
                            Candidates(row, col) = mWork(row, col).ToString
                        Else
                            Candidates(row, col) = GetCandidates(row, col)
                        End If
                    Next
                Next

                For row As Integer = 0 To 8
                    For col As Integer = 0 To 8
                        If mWork(row, col) = 0 Then
                            RemoveImpossibleCandidatesByRow(row, col)
                        End If
                    Next
                Next
                For row As Integer = 0 To 8
                    For col As Integer = 0 To 8
                        If mWork(row, col) = 0 Then
                            RemoveImpossibleCandidatesByCol(row, col)
                        End If
                    Next
                Next

                ' Check to see if the puzzle is complete
                For row As Integer = 0 To 8
                    For col As Integer = 0 To 8
                        If Len(Candidates(row, col)) = 1 Then
                            completed = completed + 1
                            If mWork(row, col) = 0 Then
                                mWork(row, col) = CInt(Candidates(row, col))
                            End If
                        End If
                    Next
                Next
                ' Try and make each cell unique
                For row As Integer = 0 To 8
                    For col As Integer = 0 To 8
                        FindUniqueValues(row, col)
                    Next
                Next
                ' If the we didn't fill in any more cells then we can't complete this puzzle
                If lastCompleted = completed Then
                    Throw New Exception("Can't solve this puzzle.")
                End If
                ' Remember how many we completed last time
                lastCompleted = completed
                ' If we completed 80 cells then the puzzle is complete
            Loop Until completed > 80
            ' Return the solved puzzle
            Return mWork
        End Function
        '
        ' calculate the potential values that can appear in each cell
        ' To do this create a scratch pad containing the numbers 1 through 9
        ' Then look in each direction and try to eliminate numbers
        ' finally return the scratch pad containing potential candidates
        '
        Private Shared Function GetCandidates(ByVal row As Integer, ByVal col As Integer) As String
            Dim r As Integer = Segment(row)
            Dim c As Integer = Segment(col)
            Dim Candidates As String = ScratchArea(1, 9)

            If mWork(row, col) = 0 Then
                ' First Check the miniblock (i.e. the 3x3 segment)
                For i As Integer = 0 To 2
                    For j As Integer = 0 To 2
                        If mWork(r + i, c + j) <> 0 Then
                            Candidates = RemoveChar(Candidates, mWork(r + i, c + j).ToString)
                        End If
                    Next
                Next

                ' Now look along each column for this row
                For i As Integer = 0 To 8
                    If InStr(Candidates, mWork(row, i)) > 0 Then
                        If mWork(row, i) <> 0 Then
                            Candidates = RemoveChar(Candidates, mWork(row, i).ToString)
                        End If
                    End If
                Next

                ' Finally look along each row for this column
                For i As Integer = 0 To 8
                    If InStr(Candidates, mWork(i, col)) > 0 Then
                        If mWork(i, col) <> 0 Then
                            Candidates = RemoveChar(Candidates, mWork(i, col).ToString)
                        End If
                    End If
                Next
            Else
                ' We've hit lucky, so set the candidates to be the single value
                Candidates = mWork(row, col).ToString
            End If
            Return Candidates
        End Function
        '
        ' Remove the given character (c) from a string
        '
        Private Shared Function RemoveChar(ByVal Text As String, ByVal c As String) As String
            Dim ValueAt As Integer
            ValueAt = InStr(Text, c)
            If ValueAt = 0 Then
                Return Text
            Else
                Return Text.Substring(0, ValueAt - 1) & Text.Substring(ValueAt, Text.Length - ValueAt)
            End If
        End Function

        Private Shared Function FindUniqueValues(ByVal row As Integer, ByVal col As Integer) As Integer
            CheckMiniblock(Segment(row), Segment(col))
            CheckColumnsByRow(row)
            CheckRowsByColumn(col)
        End Function

        Private Shared Sub CheckMiniblock(ByVal row As Integer, ByVal col As Integer)
            Dim potential As String
            Dim count As Integer

            For n As Integer = 1 To 9
                count = 0
                For i As Integer = 0 To 2
                    For j As Integer = 0 To 2
                        If InStr(Candidates(row + i, col + j), n.ToString) > 0 _
                            And Candidates(row + i, col + j).Length > 1 _
                            Or mWork(row + i, col + j) = n Then

                            count = count + 1
                        End If
                    Next
                Next

                If count = 1 Then
                    For i As Integer = 0 To 2
                        For j As Integer = 0 To 2
                            If InStr(Candidates(row + i, col + j), n.ToString) > 0 _
                                And Candidates(row + i, col + j).Length > 1 _
                                Or mWork(row + i, col + j) = n Then

                                If mWork(row + i, col + j) = 0 Then
                                    mWork(row + i, col + j) = n
                                    Exit Sub
                                End If
                            End If
                        Next
                    Next
                End If
            Next
        End Sub

        Private Shared Sub CheckColumnsByRow(ByVal row As Integer)
            Dim potential As String
            Dim count As Integer
            For n As Integer = 1 To 9
                count = 0
                For i As Integer = 0 To 8
                    If InStr(Candidates(row, i), n.ToString) > 0 _
                        And Candidates(row, i).Length > 1 _
                        Or mWork(row, i) = n Then

                        count = count + 1
                    End If
                Next
                If count = 1 Then
                    For i As Integer = 0 To 8
                        If InStr(Candidates(row, i), n.ToString) > 0 _
                            And Candidates(row, i).Length > 1 _
                            Or mWork(row, i) = n Then

                            If mWork(row, i) = 0 Then
                                mWork(row, i) = n
                                Exit Sub
                            End If
                        End If
                    Next
                End If
            Next
        End Sub

        Private Shared Sub CheckRowsByColumn(ByVal col As Integer)
            Dim potential As String
            Dim count As Integer
            For n As Integer = 1 To 9
                count = 0
                For i As Integer = 0 To 8
                    If InStr(Candidates(i, col), n.ToString) > 0 _
                        And Candidates(i, col).Length > 1 _
                        Or mWork(i, col) = n Then

                        count = count + 1
                    End If
                Next
                If count = 1 Then
                    For i As Integer = 0 To 8
                        If InStr(Candidates(i, col), n.ToString) > 0 _
                            And Candidates(i, col).Length > 1 _
                            Or mWork(i, col) = n Then

                            If mWork(i, col) = 0 Then
                                mWork(i, col) = n
                                Exit Sub
                            End If
                        End If
                    Next
                End If
            Next
        End Sub

        ' Remove impossible combinations by row
        ' This is where three candidate entries in a minblock row only produce three possible numbers
        ' in this case we can remove the numbers from the other candidates in the miniblock
        Private Shared Function RemoveImpossibleCandidatesByRow(ByVal row As Integer, ByVal col As Integer) As String
            Dim rowCandidates(9) As String
            Dim tmp As String
            Dim i As Integer
            Dim j As Integer
            Dim n As Integer
            Dim cnt As Integer
            Dim R As Integer
            Dim c As Integer
            Dim newCandidates As String
            R = Segment(row)
            c = Segment(col)

            For i = 0 To 2
                For j = 1 To Len(Candidates(R, c + i))
                    rowCandidates(CInt(Mid$(Candidates(R, c + i), j, 1))) = Mid$(Candidates(R, c + i), j, 1)
                Next
            Next
            For i = 1 To 9
                If rowCandidates(i) <> "" Then
                    tmp = tmp & rowCandidates(i)
                End If
            Next
            For i = 0 To 2
                If mWork(R, c + i) = 0 Then
                    cnt = cnt + 1
                End If
            Next
            If cnt = Len(tmp) Then
                For i = 0 To 2
                    If R + i <> R Then
                        For j = 0 To 2
                            newCandidates = Candidates(R + i, c + j)
                            For n = 1 To Len(Candidates(R + i, c + j))
                                If InStr(1, tmp, Mid$(Candidates(R + i, c + j), n, 1)) <> 0 Then
                                    newCandidates = RemoveChar(newCandidates, Mid$(Candidates(R + i, c + j), n, 1))
                                End If
                            Next
                            Candidates(R + i, c + j) = newCandidates
                        Next
                    End If
                Next
            End If

        End Function

        ' Remove impossible combinations by column
        ' This is where three candidate entries in a minblock column only produce three possible numbers
        ' in this case we can remove the numbers from the other candidates in the miniblock
        Private Shared Function RemoveImpossibleCandidatesByCol(ByVal row As Integer, ByVal col As Integer) As String
            Dim colCandidates(9) As String
            Dim tmp As String
            Dim i As Integer
            Dim j As Integer
            Dim n As Integer
            Dim cnt As Integer
            Dim R As Integer
            Dim c As Integer
            Dim newCandidates As String
            R = Segment(row)
            c = Segment(col)

            For i = 0 To 2
                For j = 1 To Len(Candidates(R + i, c))
                    colCandidates(CInt(Mid$(Candidates(R + i, c), j, 1))) = Mid$(Candidates(R + i, c), j, 1)
                Next
            Next
            For i = 1 To 9
                If colCandidates(i) <> "" Then
                    tmp = tmp & colCandidates(i)
                End If
            Next
            For i = 0 To 2
                If mWork(R + i, c) = 0 Then
                    cnt = cnt + 1
                End If
            Next
            If cnt = Len(tmp) Then
                For i = 0 To 2
                    If c + i <> c Then
                        For j = 0 To 2
                            newCandidates = Candidates(R + j, c + i)
                            For n = 1 To Len(Candidates(R + j, c + i))
                                If InStr(1, tmp, Mid$(Candidates(R + j, c + i), n, 1)) <> 0 Then
                                    newCandidates = RemoveChar(newCandidates, Mid$(Candidates(R + j, c + i), n, 1))
                                End If
                            Next
                            Candidates(R + j, c + i) = newCandidates
                        Next
                    End If
                Next
            End If

        End Function

        '
        ' Convert the global coordinate to the miniblock coordinate (i.e. 0, 1 or 2 = 0, 3, 4 or 5 = 3, 6, 7 or 8 = 6)
        '
        Private Shared Function Segment(ByVal r As Integer) As Integer
            Return (Int(r / 3) + 1) * 3 - 3
        End Function
        '
        ' Create a scratch area of consecutive numbers
        '
        Private Shared Function ScratchArea(ByVal numberFrom As Integer, ByVal numberTo As Integer) As String
            Dim scratch As New StringBuilder
            For i As Integer = numberFrom To numberTo
                scratch.Append(i.ToString)
            Next
            Return scratch.ToString
        End Function
    End Class
End Namespace
Back to top
View user's profile Send private message
Ruud
Site Admin
Joined: 17 Sep 2005
Posts: 708
:
Location: Netherlands

Items
PostPosted: Thu Oct 06, 2005 7:03 pm    Post subject: Reply with quote

Looks like I found a few soul mates here Very Happy

I've written my solver completely object based. Here are some of the classes I use:

Grid (overall status, all Houses and Cells are properties)
GridValue (keeps stats per value in the grid, maintains Templates)
Template (represents a valid distribution of a single digit in the grid)

House (row, column or box, maintains bitmaps for cells & values filled or available to solver methods)
HouseValue (keeps track of candidate cells for a value in a house)

Segment (intersection of a box and row or column)
SegmentValue (handles status and effects for box-box and box-row/column interactions)

Cell (amongst the properties are 3 Houses and 9 CellValues
CellValue (takes care of elimination effects per value)
CellPainter (takes care of coloring, drawing, markup, etc.)

Alle of these objects are interlinked.

Grid.Row[4].Cell[5].Value[8] equals Grid.Cell[4,5].Value[8]

Cell, HouseValue and CellValue all implement the INode interface, so they can be used in the DLX solver without building a separate set of columns and rows.

For solving, other classes are defined:

Log, LogEntry (for solver log)

Solver (base class, keeps track of timing, repeated solving and status)
- HumanSolver (for human-style methods)
- LinkDancer (for fast solving)
- TemplateSolver (another fast variant)
- TrialAndErrorSolver (just for the sake having it...)

Each of the grid status objects also has a Backup class, to save the state for the Trial & Error solver.

BitMask (for accessing arrays when handling bitmaps)

Several other (smaller) classes that play a minor role in the program.

I do not use Collections or ArrayLists. They have nice features, but it turns out that they are much slower than strong types arrays.

Also, I never use Exceptions for error trapping in the solvers. There is an unacceptable delay on the first exception, probably because of the JIT compiler. I hope MS has fixed that in their 2005 release.
Back to top
View user's profile Send private message Visit poster's website
Lummox JR

Joined: 07 Sep 2005
Posts: 202
:

Items
PostPosted: Fri Oct 07, 2005 12:26 am    Post subject: Reply with quote

I've found the rows and columns from dancing links to be a great way to represent constraints and candidates. Most of the tests are quite simple to run in a loop across a set of the columns, and you can mark any rows which represent candidates to eliminate.
Back to top
View user's profile Send private message
dukuso

Joined: 14 Jul 2005
Posts: 424
:
Location: germany

Items
PostPosted: Fri Oct 07, 2005 1:16 am    Post subject: Reply with quote

I find the whole terminology and representation with the
columns and rows of the exact-cover matrix easier
and clearer than thinking with the 9*9 grid.

Maybe even all contraint programming with the
alldifferent constraints should be converted to
exact cover first !?! I found nothing about this
on the web.
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Lummox JR

Joined: 07 Sep 2005
Posts: 202
:

Items
PostPosted: Fri Oct 07, 2005 1:39 am    Post subject: Reply with quote

Indeed using the DLX-style constraints opens up a lot of easier avenues for understanding puzzles. Many simple tests like pointing pairs and box-line intersections, for instance, are drastically easier with this method than by trying to wrestle with a grid.

I had originally attempted a solver using bit flags for everything, but I learned very quickly that it was too much trouble to keep up with. To represent each form of constraint required multiple arrays, and modifying one array required modifying another in a different way. Keeping them in sync was an insanely difficult task.
Back to top
View user's profile Send private message
dukuso

Joined: 14 Jul 2005
Posts: 424
:
Location: germany

Items
PostPosted: Fri Oct 07, 2005 2:29 am    Post subject: Reply with quote

I don't care so much about sudoku-specific technics.
My methods should also work for similar puzzles,QWH-instances,
or larger sudokus or just other binary exact cover matrices.
Once I have the n*m matrix, I'd like to forget
where it came from
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Lummox JR

Joined: 07 Sep 2005
Posts: 202
:

Items
PostPosted: Fri Oct 07, 2005 3:56 am    Post subject: Reply with quote

Interesting. Most advanced sudoku techniques do work better if you remember the grid from time to time, but some will definitely work in any n*m.

The logic behind pointing pairs and box-line intersections, for example, should actually work for any pair of constraint types with a common element. That is, here it's looking for a column in one of the house-digit sections of the n*m (that is, in the latter 243 columns), where all the choices in that column also share another common column; other rows in the second column can be eliminated. You could apply this technique to any exact cover problem.

But then, these methods will only take you so far. Sudoku techniques like coloring do benefit from the DLX approach, but you still need a grid.
Back to top
View user's profile Send private message
dukuso

Joined: 14 Jul 2005
Posts: 424
:
Location: germany

Items
PostPosted: Fri Oct 07, 2005 6:35 am    Post subject: Reply with quote

-----------------------------------------------------------------------
treating all 324 constraints the same way and speaking about
the 729*324 binary exact-cover matrix instead :



for a row r let Nc[r] be the set of adjacent columns
for a column c let Nr[c] be the set of adjacent rows
for a column c let Nc[c] be the set of adjacent columns
for a row r let Nr[r] be the set of adjacent rows
for a column c let V[c]=|Nr[c]| be the size of c


a row and a column are considered adjacent, iff there is a one
in their intersection

two rows(columns) are considered adjacent, iff there is a valid
column(row) adjacent to both

|Nc[r]| is always 4 in sudoku. |Nr[c]| is at most 9 ,
|Nr[r]| is at most 29 , |Nc[c]| is at most 35


The task is to find a column c of minimum size.
Then backtrack through all its adjacent rows r,
delete all rows and columns in Nr[r] and Nc[r]
and continue until no more columns are left.

If there are several columns of minimum size
(usually size=2 in sudoku) we should refine the search, but how ?


to generalize to any n*m binary matrix :
we could also search for maximal bipartite subgraphs of
{rows} x {columns} to identify the rows,columns,blocks


I would not be surprised if what we find here with sudoku could
also have useful applications with e.g. solving QWH
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    Sudoku Programmers Forum Index -> Programming sudoku All times are GMT
Page 1 of 1

 
Jump to:  
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
Sudoku Programmers topic RSS feed 


Powered by phpBB © 2001, 2005 phpBB Group

Igloo Theme Version 1.0 :: Created By: Andrew Charron