示例#1
0
        public void DeadMap()
        {
            // Init
            var report = new TestReport();

            var stat = new StaticAnalysisMaps(TestLibrary.Default.Puzzle);
            var dead = DeadMapAnalysis.FindDeadMap(stat);

            Assert.NotNull(dead);
            report.WriteLine(dead);


            var expect = new TestReport(
                @"...........
....X......
...X....XX.
..X......X.
.X....X..X.
.........X.
....X....X.
........X..
..X....X...
..XXXXX....
...........");

            Assert.Equal(report, expect);
        }
示例#2
0
 /// <summary>
 /// Strong Constructor. Start with the dead map including all walls.
 /// </summary>
 /// <param name="goalMap"></param>
 /// <param name="wallMap"></param>
 public DeadMapState(SolverNode currentNode, Bitmap goalMap, Bitmap wallMap, DeadMapAnalysis deadMapAnalysis)
     : this(goalMap, wallMap, deadMapAnalysis)
 {
     this.crateMap = currentNode.CrateMap;
     this.moveMap = currentNode.MoveMap;
     this.dynamicNode = currentNode;
 }
示例#3
0
        public void Box()
        {
            // Init
            var report = new TestReport();

            var puz = Puzzle.Builder.FromLines(new[]
            {
                "#####",
                "#...#",
                "#...#",
                "#...#",
                "#####"
            });

            var stat = new StaticAnalysisMaps(puz);

            var dead = DeadMapAnalysis.FindDeadMap(stat);

            Assert.NotNull(dead);
            report.WriteLine(dead);

            Assert.Equal(new TestReport(
                             @".....
.XXX.
.X.X.
.XXX.
....."), report);
        }
示例#4
0
        public void Regression2()
        {
            // Init
            var report = new TestReport();

            var puz = Puzzle.Builder.FromLines(new[]
            {
                "################",
                "#..............#",
                "#..............#",
                "#.############.#",
                "#..............#",
                "################"
            });

            var stat = new StaticAnalysisMaps(puz);
            var dead = DeadMapAnalysis.FindDeadMap(stat);

            Assert.NotNull(dead);
            report.WriteLine(dead);

            //            Assert.That(report, Is.EqualTo(new TestReport(
            //@"...........
            //...........
            //...........
            //.......X...
            //...........
            //...........
            //.......X...
            //...X..X....
            //...........
            //...........
            //..........."
            //
        }
示例#5
0
        /// <summary>
        /// Strong Constructor. Start with the dead map including all walls.
        /// </summary>
        /// <param name="goalMap"></param>
        /// <param name="wallMap"></param>
        public DeadMapState(Bitmap goalMap, Bitmap wallMap, DeadMapAnalysis deadMapAnalysis)
            : base("Dead Map", wallMap.Size)
        {
            this.goalMap = goalMap;
            this.wallMap = wallMap;
            this.deadMapAnalysis = deadMapAnalysis;

            this.mapSize = wallMap.Size;

            if (goalMap == null) throw new ArgumentNullException("goalMap");
            if (wallMap == null) throw new ArgumentNullException("goalMap");
            if (deadMapAnalysis == null) throw new ArgumentNullException("deadMapAnalysis");
        }
示例#6
0
        public void DynamicDeadMap()
        {
            // Init
            var p = Puzzle.Builder.FromLines(
                new[]
            {
                "##########",
                "#...XX...#",
                "#...X#...#",
                "#.P......#",
                "##########"
            });
            var stat = new StaticAnalysisMaps(p);

            Assert.True(DeadMapAnalysis.DynamicCheck(stat, StateMaps.Create(p)));


            p = Puzzle.Builder.FromLines(
                new[]
            {
                "##########",
                "#...#X...#",
                "#...X#...#",
                "#.P......#",
                "##########"
            });
            stat = new StaticAnalysisMaps(p);
            Assert.True(DeadMapAnalysis.DynamicCheck(stat, StateMaps.Create(p)));

            p = Puzzle.Builder.FromLines(
                new[]
            {
                "##########",
                "#...##...#",
                "#...XX...#",
                "#.P......#",
                "##########"
            });
            stat = new StaticAnalysisMaps(p);
            Assert.True(DeadMapAnalysis.DynamicCheck(stat, StateMaps.Create(p)));

            p = Puzzle.Builder.FromLines(
                new[]
            {
                "##########",
                "#........#",
                "#...XX...#",
                "#...##...#",
                "#.P......#",
                "##########"
            });
            stat = new StaticAnalysisMaps(p);
            Assert.True(DeadMapAnalysis.DynamicCheck(stat, StateMaps.Create(p)));

            p = Puzzle.Builder.FromLines(
                new[]
            {
                "##########",
                "#........#",
                "#...XX...#",
                "#...X#...#",
                "#.P......#",
                "##########"
            });
            stat = new StaticAnalysisMaps(p);
            Assert.True(DeadMapAnalysis.DynamicCheck(stat, StateMaps.Create(p)));



            p = Puzzle.Builder.FromLines(
                new[]
            {
                "##########",
                "#........#",
                "#...$$...#",
                "#...X#...#",
                "#.P......#",
                "##########"
            });
            stat = new StaticAnalysisMaps(p);
            Assert.True(DeadMapAnalysis.DynamicCheck(stat, StateMaps.Create(p)));

            p = Puzzle.Builder.FromLines(
                new[]
            {
                "##########",
                "#........#",
                "#...$$...#",
                "#...#X...#",
                "#.P......#",
                "##########"
            });
            stat = new StaticAnalysisMaps(p);
            Assert.True(DeadMapAnalysis.DynamicCheck(stat, StateMaps.Create(p)));

            p = Puzzle.Builder.FromLines(
                new[]
            {
                "##########",
                "#........#",
                "#...#X...#",
                "#...$$...#",
                "#.P......#",
                "##########"
            });
            stat = new StaticAnalysisMaps(p);
            Assert.True(DeadMapAnalysis.DynamicCheck(stat, StateMaps.Create(p)));


            // NOT_DEAD
            p = Puzzle.Builder.FromLines(
                new[]
            {
                "##########",
                "#........#",
                "#...$$...#",
                "#...$#...#",
                "#.P......#",
                "##########"
            });
            stat = new StaticAnalysisMaps(p);
            Assert.False(DeadMapAnalysis.DynamicCheck(stat, StateMaps.Create(p)));
        }
 /// <summary>
 /// Build the 'DeadMap' for all positions on which a crate will make the puzzle unsolvable
 /// </summary>
 private void BuildDeadMap()
 {
     DeadMapAnalysis anal = new DeadMapAnalysis();
     DeadMapState deadMapResult = anal.BuildDeadMap(null, goalMap, wallMap, controller.Strategy);
     deadMap = deadMapResult;
     cornerMap = deadMapResult.CornerMap;
     recessMap = deadMapResult.RecessMap;
 }
示例#8
0
        private bool EvaluateValidPush(
            SolverState state,
            ISolverPool pool,
            ISolverPool reversePool,
            SolverNode node,
            VectorInt2 pp,
            VectorInt2 ppp,
            VectorInt2 p,
            VectorInt2 push,
            List <SolverNode> toEnqueue,
            ref bool solution)
        {
            state.Statistics.TotalNodes++;


            var newKid = nodeFactory.CreateFromPush(node, node.CrateMap, state.StaticMaps.WallMap, p, pp, ppp, push);

            // Cycle Check: Does this node exist already?
            var dup = pool.FindMatch(newKid);

            if (dup != null)
            {
                if (object.ReferenceEquals(dup, newKid))
                {
                    throw new InvalidDataException();
                }
                if (dup.SolverNodeId == newKid.SolverNodeId)
                {
                    throw new InvalidDataException();
                }

                // Duplicate
                newKid.Status = SolverNodeStatus.Duplicate;
                state.Statistics.Duplicates++;

                if (state.Command.DuplicateMode == DuplicateMode.AddAsChild)
                {
                    node.Add(newKid);
                    newKid.Duplicate = dup;
                }
                else if (state.Command.DuplicateMode == DuplicateMode.ReuseInPool)
                {
                    nodeFactory.ReturnInstance(newKid); // Add to pool for later re-use?
                }
                else // DuplicateMode.Discard
                {
                }
            }
            else
            {
                node.Add(newKid);

                // If there is a reverse solver, checks its pool for a match, hence a Forward <-> Reverse chain, hence a solution
                var match = reversePool?.FindMatch(newKid);
                if (match != null)
                {
                    // Solution!
                    NewSolutionChain(state, out solution, newKid, match);

                    if (state.Command.ExitConditions.StopOnSolution)
                    {
                        return(true);
                    }
                }
                else
                {
                    if (DeadMapAnalysis.DynamicCheck(state.StaticMaps, node))
                    {
                        newKid.Status = SolverNodeStatus.Dead;
                        state.Statistics.TotalDead++;
                    }
                    else
                    {
                        toEnqueue.Add(newKid);

                        if (newKid.IsSolutionForward(state.StaticMaps))
                        {
                            // Solution
                            solution = true;
                            state.SolutionsNodes.Add(newKid);
                            state.Command.Debug.Raise(this, SolverDebug.Solution, newKid);
                            foreach (var n in newKid.PathToRoot())
                            {
                                n.Status = SolverNodeStatus.SolutionPath;
                            }
                            newKid.Status = SolverNodeStatus.Solution;

                            if (state.Command.ExitConditions.StopOnSolution)
                            {
                                return(true);
                            }
                        }
                    }
                }
            }

            return(false);
        }
示例#9
0
        private bool EvaluateValidPull(
            SolverState state,
            ISolverPool myPool,
            ISolverPool solutionPool,
            SolverNode node,
            VectorInt2 pc,
            VectorInt2 p,
            VectorInt2 pp,
            List <SolverNode> toEnqueue,
            ref bool solution)
        {
            state.Statistics.TotalNodes++;


            var newKid = nodeFactory.CreateFromPull(node, node.CrateMap, state.StaticMaps.WallMap, pc, p, pp);


            // Cycle Check: Does this node exist already?
            var dup = myPool.FindMatch(newKid);

            if (dup != null)
            {
                if (object.ReferenceEquals(dup, newKid))
                {
                    throw new InvalidDataException();
                }
                if (dup.SolverNodeId == newKid.SolverNodeId)
                {
                    throw new InvalidDataException();
                }

                // Duplicate
                newKid.Status = SolverNodeStatus.Duplicate;
                state.Statistics.Duplicates++;

                if (state.Command.DuplicateMode == DuplicateMode.AddAsChild)
                {
                    node.Add(newKid);
                    newKid.Duplicate = dup;
                }
                else if (state.Command.DuplicateMode == DuplicateMode.ReuseInPool)
                {
                    nodeFactory.ReturnInstance(newKid); // Add to pool for later re-use?
                }
                else // DuplicateMode.Discard
                {
                }
            }
            else
            {
                var match = solutionPool?.FindMatch(newKid);
                if (match != null)
                {
                    // Add to tree / itterator
                    node.Add(newKid);

                    // Solution
                    state.SolutionsNodesReverse ??= new List <SolutionChain>();
                    var pair = new SolutionChain
                    {
                        ForwardNode = match,
                        ReverseNode = newKid,
                        FoundUsing  = this
                    };
                    state.SolutionsNodesReverse.Add(pair);
                    solution = true;
                    state.Command.Debug.Raise(this, SolverDebug.Solution, pair);

                    foreach (var n in newKid.PathToRoot().Union(match.PathToRoot()))
                    {
                        n.Status = SolverNodeStatus.SolutionPath;
                    }
                    newKid.Status = SolverNodeStatus.Solution;
                    match.Status  = SolverNodeStatus.Solution;
                    if (state.Command.ExitConditions.StopOnSolution)
                    {
                        return(true);
                    }
                }
                else
                {
                    // Add to tree / iterator
                    node.Add(newKid);  // Thread-safe: As all kids get created in this method (forward / reverse)

                    if (DeadMapAnalysis.DynamicCheck(state.StaticMaps, node))
                    {
                        newKid.Status = SolverNodeStatus.Dead;
                    }
                    else
                    {
                        toEnqueue.Add(newKid);
                        if (newKid.IsSolutionReverse(state.StaticMaps))
                        {
                            // Possible Solution: Did we start in a valid position
                            if (CheckValidSolutions(state, newKid))
                            {
                                state.SolutionsNodes.Add(newKid);
                                state.Command.Debug.Raise(this, SolverDebug.Solution, newKid);
                                solution = true;

                                foreach (var n in newKid.PathToRoot())
                                {
                                    n.Status = SolverNodeStatus.SolutionPath;
                                }
                                newKid.Status = SolverNodeStatus.Solution;
                            }
                            else
                            {
                                // We started in the wrong place; ignore and continue
                            }
                        }
                    }
                }
            }

            return(false);
        }
示例#10
0
        private bool EvaluateValidPull(
            SolverState state,
            ISolverPool pool,
            ISolverPool solutionPool,
            SolverNode node,
            VectorInt2 pc,
            VectorInt2 p,
            VectorInt2 pp,
            List <SolverNode> toEnqueue,
            List <SolverNode> toPool,
            ref bool solution)
        {
            state.Statistics.TotalNodes++;


            var newKid = nodeFactory.CreateFromPull(node, node.CrateMap, state.StaticMaps.WallMap, pc, p, pp);

            if (state.Command.Inspector != null && state.Command.Inspector(newKid))
            {
                state.Command.Report?.WriteLine(newKid.ToString());
            }

            // Cycle Check: Does this node exist already?
            var dup = pool.FindMatch(newKid);

            if (SafeMode && dup == null)
            {
                dup = ConfirmDupLookup(pool, node, toEnqueue, newKid); // Fix or Throw
            }
            if (dup != null)
            {
                if (object.ReferenceEquals(dup, newKid))
                {
                    throw new InvalidDataException();
                }
                if (dup.SolverNodeId == newKid.SolverNodeId)
                {
                    throw new InvalidDataException();
                }

                // Duplicate
                newKid.Status = SolverNodeStatus.Duplicate;
                state.Statistics.Duplicates++;

                if (state.Command.DuplicateMode == DuplicateMode.AddAsChild)
                {
                    node.Add(newKid);
                    if (newKid is ISolverNodeDuplicateLink dupLink)
                    {
                        dupLink.Duplicate = dup;
                    }
                }
                else if (state.Command.DuplicateMode == DuplicateMode.ReuseInPool)
                {
                    nodeFactory.ReturnInstance(newKid); // Add to pool for later re-use?
                }
                else // DuplicateMode.Discard
                {
                }
            }
            else
            {
                // These two should always be the same
                node.Add(newKid); toPool.Add(newKid);

                // If there is a reverse solver, checks its pool for a match, hence a Forward <-> Reverse chain, hence a solution
                var match = solutionPool?.FindMatch(newKid);
                if (match != null)
                {
                    // Solution
                    state.SolutionsNodesReverse ??= new List <SolutionChain>();
                    var pair = new SolutionChain
                    {
                        ForwardNode = match,
                        ReverseNode = newKid,
                        FoundUsing  = this
                    };
                    state.SolutionsNodesReverse.Add(pair);
                    solution = true;
                    state.Command.Debug.Raise(this, SolverDebug.Solution, pair);

                    foreach (var n in newKid.PathToRoot().Union(match.PathToRoot()))
                    {
                        n.Status = SolverNodeStatus.SolutionPath;
                    }
                    newKid.Status = SolverNodeStatus.Solution;
                    match.Status  = SolverNodeStatus.Solution;
                    if (state.Command.ExitConditions.StopOnSolution)
                    {
                        return(true);
                    }
                }
                else
                {
                    if (DeadMapAnalysis.DynamicCheck(state.StaticMaps, node))
                    {
                        newKid.Status = SolverNodeStatus.Dead;
                    }
                    else
                    {
                        toEnqueue.Add(newKid);
                        if (newKid.IsSolutionReverse(state.StaticMaps))
                        {
                            // Possible Solution: Did we start in a valid position
                            if (CheckValidSolutions(state, newKid))
                            {
                                state.SolutionsNodes.Add(newKid);
                                state.Command.Debug.Raise(this, SolverDebug.Solution, newKid);
                                solution = true;

                                foreach (var n in newKid.PathToRoot())
                                {
                                    n.Status = SolverNodeStatus.SolutionPath;
                                }
                                newKid.Status = SolverNodeStatus.Solution;
                            }
                            else
                            {
                                // We started in the wrong place; ignore and continue
                            }
                        }
                    }
                }
            }

            return(false);
        }
示例#11
0
        /// <summary>
        /// Build the 'DeadMap' for all positions on which a crate will make the puzzle unsolvable
        /// </summary>
        private void BuildDeadMap()
        {
            // Perform Recess Analysis
            RecessAnalysis recessAnalysis = new RecessAnalysis();
            Bitmap TMPrecessMap;

            // Corners
            cornerMap = recessAnalysis.FindCorners(this);

            // Recesses
            recessAnalysis.FindRecesses(this, out recesses, out TMPrecessMap);
            recessMap = new SolverBitmap("RecessMap", TMPrecessMap);

            // Build Dead Map
            deadMapAnalysis = new DeadMapAnalysis(this);
            DeadMapState deadMapResult = deadMapAnalysis.BuildDeadMap(null, goalMap, wallMap);
            deadMap = deadMapResult;

            // TODO: This is a little rough, it needs to be reworked into 'DynamicPreProcesses' or similar
            DeadMapAnalysis.LateRuleInit();
        }