コード例 #1
0
ファイル: CPSolver.cs プロジェクト: arashout/SudokuSolveCP
        /// <summary>
        /// Eliminate will remove the value from the tile and propagate changes via calls to Assign
        /// if there is only a single value remaining
        /// NOTE: This method mutates the CPBoard cpb parameter
        /// </summary>
        /// <param name="cpb"></param>
        /// <param name="tile"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        static public bool Eliminate(CPBoard cpb, int tileIndex, string value)
        {
            var values = cpb.Get(tileIndex);

            CDebug.Assert(values.Length > 0, "values.Length > 0");

            if (values.Length == 1)
            {
                // Reached a contradiction, eliminating this value will leave the tile EMPTY!
                if (values == value)
                {
                    return(false);
                }
                // Value has already been eliminated from this tile
                return(true);
            }

            var newValues = values.Replace(value, "");

            cpb.Set(tileIndex, newValues);
            // If there is only one possible value after the change
            // Call assign to propagate changes
            if (newValues.Length == 1)
            {
                return(Assign(cpb, tileIndex, newValues));
            }

            return(true);
        }
コード例 #2
0
ファイル: CPSolver.cs プロジェクト: arashout/SudokuSolveCP
        /// <summary>
        /// Function that initializes the internal representation of the constraint propagotion board
        /// by relating all the tiles to each other via their units
        /// Each tile will have 20 peers comprised of the row, column and square peers
        /// </summary>
        static private void populatePeers()
        {
            var indices = Enumerable.Range(0, Const.N);
            // Helper function to reduce code duplication
            // The index is for determining the offset in the array,
            // basically row units are first 9, columns are second 9, squares are third 9
            Action <HashSet <int>, int> relatePeers = (peers, unitIndex) => {
                foreach (var peerIndex in peers)
                {
                    // Except statement is to exclude self from the relation
                    Peers[peerIndex] = Peers[peerIndex].Union(peers).Except(new int[] { peerIndex }).ToHashSet();
                    Units[unitIndex] = peers;
                }
            };

            foreach (var i in indices)
            {
                var rowPeers = (from c in indices select Utils.CalculateTileIndex(i, c)).ToHashSet();
                relatePeers(rowPeers, i);

                var columnPeers = (from r in indices select Utils.CalculateTileIndex(r, i)).ToHashSet();
                relatePeers(columnPeers, i + Const.N);

                int rs          = i / Const.W;
                int cs          = i % Const.W;
                var subRows     = Enumerable.Range(0, Const.W).Select(j => rs * Const.W + j);
                var subColumns  = Enumerable.Range(0, Const.W).Select(j => cs * Const.W + j);
                var squarePeers = (from r in subRows from c in subColumns select Utils.CalculateTileIndex(r, c)).ToHashSet();
                relatePeers(squarePeers, i + Const.N * 2);

                CDebug.Assert(Peers[i].Count == 20, $"Should be 20 peers each tile- {string.Join(',', Peers[i])}");
            }
        }
コード例 #3
0
ファイル: CPSolver.cs プロジェクト: arashout/SudokuSolveCP
        /// <summary>
        /// Exhaustively try all possible values for the tiles, using constraints to
        /// reduce the search space
        /// </summary>
        /// <param name="cpb"></param>
        /// <param name="depth"></param> Parameter debugging and curiousity
        /// <returns></returns>
        static private SearchResult search(CPBoard cpb, int depth)
        {
            var freeTile = cpb.GetFreeTile();

            // No free tile available
            if (freeTile.Value == null)
            {
                return(new SearchResult(cpb, IsSolved(cpb)));
            }
            var possibleValues = freeTile.Value;

            foreach (var c in possibleValues)
            {
                // Make a copy in case we reach contradiction and need to revert back
                var  copy      = cpb.Copy();
                bool didAssign = Assign(copy, freeTile.Key, c.ToString());
                CDebug.Assert(copy.Get(freeTile.Key) != cpb.Get(freeTile.Key), "Original CPB mutated!");
                if (didAssign)
                {
                    SearchResult sr = search(copy, depth + 1);
                    if (sr.DidSolve)
                    {
                        return(sr);
                    }
                }
            }
            return(new SearchResult(cpb, false));
        }
コード例 #4
0
ファイル: CPSolver.cs プロジェクト: arashout/SudokuSolveCP
        public CPBoard(string board)
        {
            var indices = Enumerable.Range(0, Const.N);

            CDebug.Assert(board.Length == Const.N2, "board.Length == Const.N2");
            for (int i = 0; i < board.Length; i++)
            {
                int n = Utils.parseChar(board[i]);
                if (n != 0)
                {
                    Tiles[i] = n.ToString();
                }
                else
                {
                    Tiles[i] = string.Join("", indices.Select((num) => num + 1));
                }
            }
        }
コード例 #5
0
ファイル: CPSolver.cs プロジェクト: arashout/SudokuSolveCP
        /// <summary>
        /// Assign a single value to the tile, propagate the changes via calls to Eliminate
        /// NOTE: Method mutates the CPBoard cpb parameter
        /// </summary>
        /// <param name="cpb"></param>
        /// <param name="tileIndex"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        static public bool Assign(CPBoard cpb, int tileIndex, string value)
        {
            CDebug.Assert(value.Length == 1, "Cannot assign multiple values");
            var values = cpb.Get(tileIndex);

            // Cannot assign a value that is a not possible value of the tile
            if (!values.Contains(value))
            {
                return(false);
            }

            // Attempt to eliminate values from peers
            cpb.Set(tileIndex, value);
            foreach (var peer in Peers[tileIndex])
            {
                if (!Eliminate(cpb, peer, value))
                {
                    return(false);
                }
            }

            return(true);
        }