Exemplo n.º 1
0
        public bool dancingLinksAlg()
        {
            if (columns.Count == 0)
            {
                return(true);
            }

            int minCount = columns.Min(x => x.columnMemberCount);

            if (minCount <= 0)
            {
                return(false);
            }

            DancingLinksColumnHeader c = columns.Where(x => x.columnMemberCount == minCount).ToArray()[0];
            int count = c.columnMemberCount;
            DancingLinksNode curNode = c.firstEntry;


            //Outer loop iterates through rows intersecting the column

            //Inside this, we look at a given row. Iterate through the columns intersecting that row.


            while (count > 0)
            {
                #region Removal_and_Test
                DancingLinksNode curColPivot = curNode.right;

                while (curColPivot != curNode)
                {
                    DancingLinksNode curRowPivot = curColPivot.down;

                    while (curRowPivot != curColPivot)
                    {
                        #region Remove_rows_Except_Pivot_Row
                        DancingLinksNode curRemNode = curRowPivot.right;
                        while (curRemNode != curRowPivot)
                        {
                            curRemNode.up.down = curRemNode.down;
                            curRemNode.down.up = curRemNode.up;

                            curRemNode.header.columnMemberCount--;

                            curRemNode = curRemNode.right;
                        }

                        rows.Remove(rowLookUp[curRowPivot.row]);
                        #endregion

                        //curRowPivot.right.left = curRowPivot.left;
                        //curRowPivot.left.right = curRowPivot.right;

                        curRowPivot = curRowPivot.down;
                    }

                    columns.Remove(curColPivot.header);

                    //We must remove the Pivot Row as well.
                    //Notice that we do not remove the Pivot Row from the rows list. This is intentional.
                    curColPivot.up.down = curColPivot.down;
                    curColPivot.down.up = curColPivot.up;

                    curColPivot = curColPivot.right;
                }

                //Lastly, we remove the pivot column.
                columns.Remove(curNode.header);

                curNode.left.right = curNode.right;
                curNode.right.left = curNode.left;

                DancingLinksNode colRemNode = curNode.down;
                while (colRemNode != curNode)
                {
                    colRemNode.left.right = colRemNode.right;
                    colRemNode.right.left = colRemNode.left;

                    colRemNode = colRemNode.down;
                }



                if (dancingLinksAlg())
                {
                    return(true);
                }

                #endregion

                #region Readd
                else
                {
                    //If removing this row didn't work, backtrack and undo all those row and column removals.

                    columns.Add(curNode.header);

                    curNode.right.left = curNode;
                    curNode.left.right = curNode;


                    DancingLinksNode colAddNode = curNode.down;
                    while (colAddNode != curNode)
                    {
                        colAddNode.left.right = colAddNode.right;
                        colAddNode.right.left = colAddNode.left;

                        colAddNode = colAddNode.down;
                    }

                    //Now, we follow the links into the inner rows and columns to restore them as well.
                    curColPivot = curNode.right;

                    while (curColPivot != curNode)
                    {
                        DancingLinksNode curRowPivot = curColPivot.down;

                        while (curRowPivot != curColPivot)
                        {
                            #region Add_rows_Except_Pivot_Row
                            DancingLinksNode curAddNode = curRowPivot.right;
                            while (curAddNode != curRowPivot)
                            {
                                curAddNode.up.down = curAddNode;
                                curAddNode.down.up = curAddNode;

                                curAddNode.header.columnMemberCount++;

                                curAddNode = curAddNode.right;
                            }

                            rows.Add(rowLookUp[curRowPivot.row]);
                            #endregion

                            //curRowPivot.right.left = curRowPivot.left;
                            //curRowPivot.left.right = curRowPivot.right;

                            curRowPivot = curRowPivot.down;
                        }

                        columns.Add(curColPivot.header);

                        //We must Add the Pivot Row as well.
                        curColPivot.up.down = curColPivot;
                        curColPivot.down.up = curColPivot;

                        curColPivot = curColPivot.right;
                    }
                }
                #endregion

                curNode = curNode.down;
                count--;
            }

            return(false);
        }
Exemplo n.º 2
0
        public DancingLinks(SudokuGrid s)
        {
            rowLookUp = new Dictionary <Triple <int>, SudokuRowHeader>();


            if (s.Validate())
            {
                columns = new List <DancingLinksColumnHeader>();
                rows    = new List <SudokuRowHeader>();


                //Initialise blank Sudoku Grid.


                for (int i = 1; i <= 9; i++)
                {
                    for (int j = 1; j <= 9; j++)
                    {
                        columns.Add(new DancingLinksColumnHeader(new Tuple <int, int>(i, j), DancingLinksColumnHeader.ColumnType.Cell));
                        columns.Add(new DancingLinksColumnHeader(new Tuple <int, int>(i, j), DancingLinksColumnHeader.ColumnType.Row));
                        columns.Add(new DancingLinksColumnHeader(new Tuple <int, int>(i, j), DancingLinksColumnHeader.ColumnType.Square));
                        columns.Add(new DancingLinksColumnHeader(new Tuple <int, int>(i, j), DancingLinksColumnHeader.ColumnType.Column));


                        for (int k = 1; k <= 9; k++)
                        {
                            SudokuRowHeader r = new SudokuRowHeader(new Triple <int>(i, j, k));
                            rows.Add(r);
                            rowLookUp.Add(new Triple <int>(i, j, k), r);
                        }
                    }
                }

                //Convention: for cell numbers, x is the row and y is the column. This is reversed for square numbering. This is an artefact of how I am visualising the objects.

                //Column Linking
                foreach (DancingLinksColumnHeader column in columns)
                {
                    column.columnMemberCount = 9;

                    if (column.type == DancingLinksColumnHeader.ColumnType.Cell)
                    {
                        int content;
                        if (int.TryParse(s.boxes[column.constraintNum.Item1 - 1, column.constraintNum.Item2 - 1].Text, out content))
                        {
                            column.columnMemberCount = 1;
                            column.firstEntry        = new DancingLinksNode(column, column.constraintNum.Item1, column.constraintNum.Item2, content);

                            column.firstEntry.up   = column.firstEntry;
                            column.firstEntry.down = column.firstEntry;

                            if (rowLookUp.ContainsKey(new Triple <int>(column.constraintNum.Item1, column.constraintNum.Item2, content)))
                            {
                                rowLookUp[new Triple <int>(column.constraintNum.Item1, column.constraintNum.Item2, content)].firstNode.left.right = column.firstEntry;
                                rowLookUp[new Triple <int>(column.constraintNum.Item1, column.constraintNum.Item2, content)].firstNode.left       = column.firstEntry;
                            }
                            else
                            {
                                SudokuRowHeader r = new SudokuRowHeader(new Triple <int>(column.constraintNum.Item1, column.constraintNum.Item2, content));
                                rows.Add(r);
                                rowLookUp.Add(new Triple <int>(column.constraintNum.Item1, column.constraintNum.Item2, content), r);

                                r.firstNode = column.firstEntry;
                            }
                        }
                        else
                        {
                            column.firstEntry = new DancingLinksNode(column, column.constraintNum.Item1, column.constraintNum.Item2, 1);

                            DancingLinksNode curNode = column.firstEntry;

                            if (rowLookUp.ContainsKey(new Triple <int>(column.constraintNum.Item1, column.constraintNum.Item2, 1)))
                            {
                                rowLookUp[new Triple <int>(column.constraintNum.Item1, column.constraintNum.Item2, 1)].firstNode.left.right = curNode;
                                rowLookUp[new Triple <int>(column.constraintNum.Item1, column.constraintNum.Item2, 1)].firstNode.left       = curNode;
                            }
                            else
                            {
                                SudokuRowHeader r = new SudokuRowHeader(new Triple <int>(column.constraintNum.Item1, column.constraintNum.Item2, 1));
                                rows.Add(r);
                                rowLookUp.Add(new Triple <int>(column.constraintNum.Item1, column.constraintNum.Item2, 1), r);

                                r.firstNode = curNode;
                            }


                            for (int i = 2; i <= 9; i++)
                            {
                                curNode.down    = new DancingLinksNode(column, column.constraintNum.Item1, column.constraintNum.Item2, i);
                                curNode.down.up = curNode;
                                curNode         = curNode.down;

                                if (i == 9)
                                {
                                    column.firstEntry.up = curNode;
                                    curNode.down         = column.firstEntry;
                                }

                                if (rowLookUp.ContainsKey(new Triple <int>(column.constraintNum.Item1, column.constraintNum.Item2, i)))
                                {
                                    rowLookUp[new Triple <int>(column.constraintNum.Item1, column.constraintNum.Item2, i)].firstNode.left.right = curNode;
                                    rowLookUp[new Triple <int>(column.constraintNum.Item1, column.constraintNum.Item2, i)].firstNode.left       = curNode;
                                }
                                else
                                {
                                    SudokuRowHeader r = new SudokuRowHeader(new Triple <int>(column.constraintNum.Item1, column.constraintNum.Item2, i));
                                    rows.Add(r);
                                    rowLookUp.Add(new Triple <int>(column.constraintNum.Item1, column.constraintNum.Item2, i), r);

                                    r.firstNode = curNode;
                                }
                            }
                        }
                    }

                    if (column.type == DancingLinksColumnHeader.ColumnType.Column)
                    {
                        int  content;
                        int  rowNum     = 0;
                        bool isInColumn = false;

                        for (int i = 1; i <= 9 && !isInColumn; i++)
                        {
                            if (int.TryParse(s.boxes[i - 1, column.constraintNum.Item1 - 1].Text, out content))
                            {
                                if (content == column.constraintNum.Item2)
                                {
                                    isInColumn = true;
                                }
                                rowNum = i;
                            }
                        }

                        if (isInColumn)
                        {
                            column.columnMemberCount = 1;

                            column.firstEntry      = new DancingLinksNode(column, rowNum, column.constraintNum.Item1, column.constraintNum.Item2);
                            column.firstEntry.up   = column.firstEntry;
                            column.firstEntry.down = column.firstEntry;
                        }
                        else
                        {
                            column.firstEntry = new DancingLinksNode(column, 1, column.constraintNum.Item1, column.constraintNum.Item2);

                            DancingLinksNode curNode = column.firstEntry;


                            for (int i = 2; i <= 9; i++)
                            {
                                curNode.down    = new DancingLinksNode(column, i, column.constraintNum.Item1, column.constraintNum.Item2);
                                curNode.down.up = curNode;
                                curNode         = curNode.down;

                                if (i == 9)
                                {
                                    column.firstEntry.up = curNode;
                                    curNode.down         = column.firstEntry;
                                }
                            }
                        }
                    }

                    if (column.type == DancingLinksColumnHeader.ColumnType.Row)
                    {
                        int  content;
                        int  colNum     = 0;
                        bool isInColumn = false;

                        for (int i = 1; i <= 9 && !isInColumn; i++)
                        {
                            if (int.TryParse(s.boxes[column.constraintNum.Item1 - 1, i - 1].Text, out content))
                            {
                                if (content == column.constraintNum.Item2)
                                {
                                    isInColumn = true;
                                }
                                colNum = i;
                            }
                        }

                        if (isInColumn)
                        {
                            column.columnMemberCount = 1;

                            column.firstEntry      = new DancingLinksNode(column, column.constraintNum.Item1, colNum, column.constraintNum.Item2);
                            column.firstEntry.up   = column.firstEntry;
                            column.firstEntry.down = column.firstEntry;
                        }
                        else
                        {
                            column.firstEntry = new DancingLinksNode(column, column.constraintNum.Item1, 1, column.constraintNum.Item2);

                            DancingLinksNode curNode = column.firstEntry;


                            for (int i = 2; i <= 9; i++)
                            {
                                curNode.down    = new DancingLinksNode(column, column.constraintNum.Item1, i, column.constraintNum.Item2);
                                curNode.down.up = curNode;
                                curNode         = curNode.down;

                                if (i == 9)
                                {
                                    column.firstEntry.up = curNode;
                                    curNode.down         = column.firstEntry;
                                }
                            }
                        }
                    }

                    if (column.type == DancingLinksColumnHeader.ColumnType.Square)
                    {
                        int squareX = column.constraintNum.Item1 % 3 - 1;
                        if (squareX < 0)
                        {
                            squareX += 3;
                        }
                        int squareY = (column.constraintNum.Item1 - (squareX + 1)) / 3;

                        int rowNum = 0;
                        int colNum = 0;

                        bool isInSquare = false;

                        for (int i = 1; i <= 3; i++)
                        {
                            for (int j = 1; j <= 3; j++)
                            {
                                int content;

                                if (int.TryParse(s.boxes[squareY * 3 + i - 1, squareX * 3 + j - 1].Text, out content))
                                {
                                    if (content == column.constraintNum.Item2)
                                    {
                                        isInSquare = true;

                                        rowNum = squareY * 3 + i;
                                        colNum = squareX * 3 + j;
                                    }
                                }
                            }
                        }

                        if (isInSquare)
                        {
                            column.columnMemberCount = 1;

                            column.firstEntry = new DancingLinksNode(column, rowNum, colNum, column.constraintNum.Item2);


                            column.firstEntry.up   = column.firstEntry;
                            column.firstEntry.down = column.firstEntry;
                        }
                        else
                        {
                            column.firstEntry = new DancingLinksNode(column, squareY * 3 + 1, squareX * 3 + 1, column.constraintNum.Item2);
                            DancingLinksNode curNode = column.firstEntry;


                            for (int i = 1; i <= 3; i++)
                            {
                                for (int j = 1; j <= 3; j++)
                                {
                                    if (i != 1 || j != 1)
                                    {
                                        curNode.down    = new DancingLinksNode(column, squareY * 3 + i, squareX * 3 + j, column.constraintNum.Item2);
                                        curNode.down.up = curNode;
                                        curNode         = curNode.down;
                                    }

                                    if (i == 3 && j == 3)
                                    {
                                        column.firstEntry.up = curNode;
                                        curNode.down         = column.firstEntry;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }