public void TestInitializeConstraints()
        {
            // This board is solvable from the constraints alone
            var cpb = new CPBoard(bSolvableByCP);

            Assert.True(CPSolver.InitializeConstraints(cpb));
            Assert.True(CPSolver.IsSolved(cpb));

            cpb = new CPBoard(bInvalid);
            Assert.False(CPSolver.InitializeConstraints(cpb));

            cpb = new CPBoard(bEmpty);
            Assert.True(CPSolver.InitializeConstraints(cpb));
            for (int i = 0; i < Const.N2; i++)
            {
                Assert.Equal("123456789", cpb.Get(i));
            }

            cpb = new CPBoard("1234" + bEmpty.Remove(0, 4));
            CPSolver.InitializeConstraints(cpb);
            Assert.Equal("1", cpb.Get(0));
            Assert.Equal("2", cpb.Get(1));
            Assert.Equal("3", cpb.Get(2));
            Assert.Equal("4", cpb.Get(3));
            Assert.Equal("56789", cpb.Get(4));

            // TODO: Double check results
            cpb = new CPBoard(bSolvable);
            CPSolver.InitializeConstraints(cpb);
            Assert.Equal("1458", cpb.Get(2));
        }
        public void TestSolve()
        {
            var cpb = new CPBoard(bSolvableByCP);
            var sr  = CPSolver.Solve(cpb);

            Assert.True(sr.DidSolve);
            Assert.True(CPSolver.IsSolved(sr.CPB));

            cpb = new CPBoard(bSolved);
            sr  = CPSolver.Solve(cpb);
            Assert.True(sr.DidSolve);
            Assert.Equal("7", cpb.Get(0));
            Assert.True(CPSolver.IsSolved(sr.CPB));

            // Double check results
            cpb = new CPBoard(bSolvable);
            sr  = CPSolver.Solve(cpb);
            Assert.True(sr.DidSolve);
            Assert.True(CPSolver.IsSolved(sr.CPB));

            cpb = new CPBoard(bEmpty);
            sr  = CPSolver.Solve(cpb);
            Assert.True(sr.DidSolve);
            Assert.True(CPSolver.IsSolved(sr.CPB));
        }
Beispiel #3
0
        /// <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);
        }
Beispiel #4
0
        /// <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));
        }
        public void TestBasicEliminate()
        {
            var cpb = new CPBoard(bEmpty);

            CPSolver.Eliminate(cpb, 0, "1");
            Assert.Equal("23456789", cpb.Get(0));
        }
Beispiel #6
0
 /// <summary>
 /// Helper function for the search function
 /// </summary>
 /// <param name="cpb"></param>
 /// <returns></returns>
 static public SearchResult Solve(CPBoard cpb)
 {
     if (!InitializeConstraints(cpb))
     {
         return(new SearchResult(cpb, false));
     }
     return(search(cpb, 0));
 }
Beispiel #7
0
 /// <summary>
 /// For a the puzzle to be solved, each tile within a unit must have distinct value
 /// A unit is either:
 /// - a row (1x9)
 /// - a column (9x1)
 /// - a square (3x3)
 /// </summary>
 /// <returns></returns>
 static public bool IsSolved(CPBoard cpb)
 {
     foreach (var unit in Units)
     {
         var values = string.Join("", unit.Select(tileIndex => cpb.Get(tileIndex)));
         if (values.Distinct().Count() != values.Count())
         {
             return(false);
         }
     }
     return(true);
 }
        public void TestIsSolved()
        {
            var cpb = new CPBoard(bSolvableByCP);

            Assert.False(CPSolver.IsSolved(cpb));

            cpb = new CPBoard(bSolved);
            Assert.True(CPSolver.IsSolved(cpb));

            cpb = new CPBoard(bInvalid);
            Assert.False(CPSolver.IsSolved(cpb));
        }
        public void TestFreeTile()
        {
            var cpb = new CPBoard(bSolvableByCP);
            var ft  = cpb.GetFreeTile();

            Assert.Equal(0, ft.Key);
            Assert.Equal("123456789", ft.Value);  // No elimination has occured yet

            cpb = new CPBoard(bSolved);
            ft  = cpb.GetFreeTile();
            Assert.Equal(0, ft.Key);  // TODO: Really need maybe type, 0 is not a good default
            Assert.Null(ft.Value);
        }
Beispiel #10
0
        public void TestCopy()
        {
            var     cpb  = new CPBoard(bSolvableByCP);
            CPBoard copy = cpb.Copy();

            // Changing original does not mutate copy
            Assert.NotEqual("4", copy.Get(0));
            cpb.Set(0, "4");
            Assert.NotEqual("4", copy.Get(0));

            // Chaning copy does not change original
            Assert.NotEqual("2", cpb.Get(1));
            copy.Set(1, "2");
            Assert.NotEqual("2", cpb.Get(1));
        }
Beispiel #11
0
 /// <summary>
 /// This function should be called on a initially "unconstrained" CPBoard
 /// before the solving step, however it is not set to private because
 /// it is fun to see the incremental effects of constraining values before searching
 /// </summary>
 /// <param name="cpb"></param>
 /// <returns></returns>
 static internal bool InitializeConstraints(CPBoard cpb)
 {
     for (int i = 0; i < Const.N2; i++)
     {
         var value = cpb.Get(i);
         if (value.Length == 1)
         {
             if (!Assign(cpb, i, value))
             {
                 return(false);
             }
         }
     }
     return(true);
 }
Beispiel #12
0
        public void TestInvalidAssign()
        {
            var cpb = new CPBoard(bEmpty);

            CPSolver.Assign(cpb, 0, "1");

            Assert.False(CPSolver.Assign(cpb, 1, "1"), "Made invalid assignment!");
            Assert.Equal("23456789", cpb.Get(1));   // If assignment fails do not mutate CPBoard

            Assert.False(CPSolver.Assign(cpb, 0, "2"), "Assigned an impossible value");
            // Check that invalid assignment did not propagates
            foreach (var peerIndex in CPSolver.Peers[0])
            {
                Assert.Equal("23456789", cpb.Get(peerIndex));
            }
        }
Beispiel #13
0
        public void TestAssignEliminate()
        {
            var cpb = new CPBoard(bEmpty);

            CPSolver.Assign(cpb, 0, "1");
            Assert.Equal("1", cpb.Get(0));

            // Check assignment propagates
            foreach (var peerIndex in CPSolver.Peers[0])
            {
                Assert.Equal("23456789", cpb.Get(peerIndex));
            }
            // Check overlap elimination
            CPSolver.Assign(cpb, Const.N2 - 1, "9");                       // Last tile
            Assert.Equal("2345678", cpb.Get(Const.N - 1));                 // 8
            Assert.Equal("2345678", cpb.Get(Const.N * Const.N - Const.N)); // 72
        }
Beispiel #14
0
        /// <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);
        }
Beispiel #15
0
        /// <summary>
        /// Deep copy function that uses the private constructor
        /// Useful reverting calls from Assign and Eliminate
        /// Copy function is a convience function for the private constructor
        /// </summary>
        /// <returns></returns>
        public CPBoard Copy()
        {
            CPBoard copy = new CPBoard(Tiles);

            return(copy);
        }
Beispiel #16
0
        static void FakeMain(string[] args)
        {
            Console.WriteLine(string.Join(',', args));
            if (args.Length > 0)
            {
                IList <string> gridStrings = new List <string> ();
                string         line;

                string fileName             = @"puzzles.txt";
                System.IO.StreamReader file = new System.IO.StreamReader(fileName);
                while ((line = file.ReadLine()) != null)
                {
                    if (line.Contains("Grid"))
                    {
                        continue;
                    }
                    else
                    {
                        gridStrings.Add(line.Trim());
                    }
                    System.Console.WriteLine(line);
                }

                file.Close();
                System.Console.WriteLine("{0} in {1}", gridStrings.Count, fileName);

                // TODO: Do initial solve to reduce jitter
                Console.WriteLine("Starting benchmarking");
                var solveTimes = new List <double> (new double[gridStrings.Count]);

                Stopwatch sw            = new Stopwatch();
                int       numIterations = 10;

                for (int i = 0; i < numIterations; i++)
                {
                    for (int j = 0; j < gridStrings.Count; j++)
                    {
                        var cpb = new CPBoard(gridStrings[j]);
                        cpb.Print();
                        Console.WriteLine(new String('-', 20));

                        sw.Restart();
                        var sr = CPSolver.Solve(cpb);
                        sw.Stop();

                        double ticks        = sw.ElapsedTicks;
                        double seconds      = ticks / Stopwatch.Frequency;
                        double milliseconds = (ticks / Stopwatch.Frequency) * 1000;
                        solveTimes[j] += milliseconds;

                        if (!sr.DidSolve)
                        {
                            throw new Exception($"Could not solve:\n {cpb.ToString()}");
                        }

                        sr.CPB.Print();
                    }
                }

                var averageTimes = solveTimes.Select(st => st / numIterations).ToList();
                var averageTime  = averageTimes.Average();
                Console.WriteLine($"Average solve time was: {averageTime}");
                for (int i = 0; i < averageTimes.Count; i++)
                {
                    Console.WriteLine($"Grid {i} : {averageTimes[i]}");
                }
            }
            else
            {
                string line;
                // Handle piped input
                Console.SetIn(new System.IO.StreamReader(Console.OpenStandardInput(8192)));    // This will allow input >256 chars
                while (Console.In.Peek() != -1)
                {
                    line = Console.In.ReadLine();

                    if (line.Contains("Grid"))
                    {
                        var puzzleName = line;
                        Console.WriteLine($"Attempting ${puzzleName}");
                    }
                    else
                    {
                        var cpb = new CPBoard(line);
                        cpb.Print();
                        Console.WriteLine(new String('-', 20));

                        var sr = CPSolver.Solve(cpb);
                        if (!sr.DidSolve)
                        {
                            throw new Exception($"Could not solve:\n {cpb.ToString()}");
                        }
                        sr.CPB.Print();
                    }
                }
            }
        }
Beispiel #17
0
 public SearchResult(CPBoard cpb, bool didSolve)
 {
     CPB      = cpb;
     DidSolve = didSolve;
 }