Ejemplo n.º 1
0
        public bool Solve(IStatusUpdater updater, int nSeconds)
        {
            m_updater        = updater;
            m_dtNextUpdate   = System.DateTime.Now.AddSeconds(nSeconds);
            m_nUpdateSeconds = nSeconds;
            m_nIterations    = 0;
            //return SolveAt(0, 0);
            bool bSolved = SolveIterate();

            updater.UpdateStatus();
            return(bSolved);
        }
Ejemplo n.º 2
0
        public bool Solve(IStatusUpdater updater, int nSeconds)
        {
            m_updater        = updater;
            m_dtNextUpdate   = System.DateTime.Now.AddSeconds(nSeconds);
            m_nUpdateSeconds = nSeconds;
            m_nIterations    = 0;
            //return SolveAt(0, 0);
            bool bSolved = SolveIterate();

            updater.UpdateStatus();
            MessageBox.Show(string.Format("Number of iterations: {0}", m_nIterations));
            return(bSolved);
        }
Ejemplo n.º 3
0
        private bool SolveIterate()
        {
            m_nIterations++;

            if (System.DateTime.Now > m_dtNextUpdate)
            {
                m_updater.UpdateStatus();
                m_dtNextUpdate = System.DateTime.Now.AddSeconds(m_nUpdateSeconds);
            }

            // find out what is the best element to work on
            int nRow, nCol, nOpts, baLegals;
            int nBestRow = -1, nBestCol = -1, nBestOpts = 100, baBestLegals = 0;

            for (nRow = 0; nRow < m_nRows; nRow++)
            {
                nOpts = 100;
                for (nCol = 0; nCol < m_nCols; nCol++)
                {
                    if (this[nRow, nCol].Value != Element.Unknown)
                    {
                        continue;
                    }
                    baLegals = FindOptions(nRow, nCol, out nOpts);
                    if (nOpts < nBestOpts)
                    {
                        nBestRow     = nRow;
                        nBestCol     = nCol;
                        nBestOpts    = nOpts;
                        baBestLegals = baLegals;
                    }

                    if (nOpts == 0)
                    {
                        return(false); // found contradiction
                    }
                    if (nOpts == 1)
                    {
                        break;
                    }
                }
                if (nOpts == 1)
                {
                    break;
                }
            }

            // ending condition
            if (nBestOpts == 100)
            {
                // we're done
                return(true);
            }

            // work on the best element
            for (int curValue = 9; curValue >= 1; curValue--)
            {
                if ((baBestLegals & (1 << curValue)) == 0)
                {
                    continue; // illegal option
                }
                this[nBestRow, nBestCol].Value = curValue;

                // recurse
                if (SolveIterate())
                {
                    return(true);
                }
            }

            // couldn't find any solution
            this[nBestRow, nBestCol].Value = Element.Unknown;
            return(false);
        }
Ejemplo n.º 4
0
        private bool SolveAt(int nRow, int nCol)
        {
            if (System.DateTime.Now > m_dtNextUpdate)
            {
                m_updater.UpdateStatus();
                m_dtNextUpdate = System.DateTime.Now.AddSeconds(m_nUpdateSeconds);
            }

            if (nCol == m_nCols)
            {
                nCol = 0;
                nRow++;
            }

            if (nRow == m_nRows && nCol == 0)
            {
                // complete!
                return(true);
            }

            // if we are in a sum-type element, then advance to next element
            if (!this[nRow, nCol].HasValue)
            {
                return(SolveAt(nRow, nCol + 1));
            }

            // we are in a value-type element. see if we can make it work.
            // first, find information about the current column and row.
            int nColStart, nColEnd, nColSum; //NB: nColStart is the ROW in which the current column starts!
            int nRowStart, nRowEnd, nRowSum; //NB: nRowStart is the COLUMN in which the current row starts!

            // find the row in which the current column starts
            for (nColStart = nRow; this[nColStart - 1, nCol].HasValue; nColStart--)
            {
                ;
            }
            // find the row in which the current column ends
            for (nColEnd = nRow; nColEnd < m_nRows - 1 && this[nColEnd + 1, nCol].HasValue; nColEnd++)
            {
                ;
            }
            // find the column in which the current row starts
            for (nRowStart = nCol; this[nRow, nRowStart - 1].HasValue; nRowStart--)
            {
                ;
            }
            // find the column in which the current row ends
            for (nRowEnd = nCol; nRowEnd < m_nCols - 1 && this[nRow, nRowEnd + 1].HasValue; nRowEnd++)
            {
                ;
            }
            // find the expected sums for the current row and column
            nColSum = this[nColStart - 1, nCol].SumDown;
            nRowSum = this[nRow, nRowStart - 1].SumRight;
            Debug.Assert(nColSum != Element.Unused);
            Debug.Assert(nRowSum != Element.Unused);

            // find illegal values for the current element.
            // these are stored in the bitarray illegalValues:
            // value i is illegal iff bit i is 1
            int illegalValues = 0;

            // stage 1: must not appear in the current column
            // (we also use this pass to calculate the column sum so far)
            int colsum = 0;

            for (int i = nColStart; i < nRow; i++)
            {
                int valHere = this[i, nCol].Value;
                illegalValues |= (1 << valHere);
                colsum        += valHere;
            }

            // stage 2: must not appear in the current row
            // (we also use this pass to calculate the row sum so far)
            int rowsum = 0;

            for (int i = nRowStart; i < nCol; i++)
            {
                int valHere = this[nRow, i].Value;
                illegalValues |= (1 << valHere);
                rowsum        += valHere;
            }

            int curValue = 0;

            // if we are in the last element of the column/row, we must behave differently,
            // since there is only one possible value here
            if (nCol == nRowEnd)
            {
                curValue = nRowSum - rowsum;
                if (curValue < 1 || curValue > 9)
                {
                    return(false);
                }
            }
            if (nRow == nColEnd)
            {
                int required = nColSum - colsum;
                if (required < 1 || required > 9)
                {
                    return(false);
                }
                if (curValue == 0)
                {
                    curValue = required;
                }
                else
                {
                    if (curValue != required)
                    {
                        // contradiction between row and column requirements; we failed
                        return(false);
                    }
                    else
                    {
                        // row and column requirements agree; continue
                    }
                }
            }

            if (curValue != 0)
            {
                // we have a row or column requirement; see if the required value is legal
                if ((illegalValues & (1 << curValue)) == 0)
                {
                    // digit doesn't yet appear
                    if (colsum + curValue <= nColSum)
                    {
                        // digit doesn't exceed expected column sum
                        if (rowsum + curValue <= nRowSum)
                        {
                            // digit doesn't exceed expected row sum

                            // set value in current cell
                            this[nRow, nCol].Value = curValue;

                            // recurse
                            if (SolveAt(nRow, nCol + 1))
                            {
                                // success!
                                return(true);
                            }
                            else
                            {
                                // this doesn't work; we failed
                            }
                        }
                    }
                }
            }
            else
            {
                // no row or column requirements; check all legal possibilities

                for (curValue = 9; curValue >= 1; curValue--)
                {
                    // see if this value is legal
                    if ((illegalValues & (1 << curValue)) != 0)
                    {
                        continue; // digit already appears in current row or column
                    }
                    if (colsum + curValue > nColSum)
                    {
                        continue; // exceeded expected column sum
                    }
                    if (rowsum + curValue > nRowSum)
                    {
                        continue; // exceeded expected row sum
                    }
                    // set value in current cell
                    this[nRow, nCol].Value = curValue;

                    // recurse
                    if (SolveAt(nRow, nCol + 1))
                    {
                        // success!
                        return(true);
                    }
                    else
                    {
                        // that didn't work, try the next one
                    }
                }
            }

            // nothing worked;
            // let's clear the field so the higher recursion level can try again
            this[nRow, nCol].Value = Element.Unknown;
            return(false);
        }