示例#1
0
        protected SolverNode?ConfirmDupLookup(ISolverPool pool, SolverNode node, List <SolverNode> toEnqueue, SolverNode newKid)
        {
            if (SafeMode)
            {
                var root = node.Root();
                foreach (var nn in root.Recurse())
                {
                    if (nn.Equals(newKid))
                    {
                        if (nn.CompareTo(newKid) != 0)
                        {
                            throw new InvalidOperationException();
                        }

                        var sizes = $"Tree:{root.CountRecursive()} vs. Pool:{pool.Statistics.TotalNodes}";

                        var shouldExist = pool.FindMatch(nn);
                        var shoudNotBeFound_ButWeWantItToBe = pool.FindMatch(newKid);
                        var message =
                            $"This is an indication the Pool is not threadsafe/or has a bad binarySearch\n" +
                            $"{sizes}\n" +
                            $"Dup:{toEnqueue.Count()}: ({nn}; pool={shouldExist}) <-> ({newKid}) != {shoudNotBeFound_ButWeWantItToBe} [{pool.TypeDescriptor}]";
                        //throw new Exception(message);
                        return(nn);
                    }
                }

                return(null);
            }
            return(null);
        }
示例#2
0
        public override bool Evaluate(
            SolverState state,
            ISolverQueue queue,
            ISolverPool pool,
            ISolverPool solutionPool,
            SolverNode node)
        {
            if (node.HasChildren)
            {
                throw new InvalidOperationException();
            }


            node.Status = SolverNodeStatus.Evaluting;
            var toEnqueue = new List <SolverNode>(); // TODO: Could be reused
            var toPool    = new List <SolverNode>(); // TODO: Could be reused

            var solution = false;

            foreach (var move in node.MoveMap.TruePositions())
            {
                foreach (var dir in VectorInt2.Directions)
                {
                    var p   = move;
                    var pp  = p + dir;
                    var ppp = pp + dir;
                    if (node.CrateMap[pp] &&                                 // crate to push
                        state.StaticMaps.FloorMap[ppp] && !node.CrateMap[ppp] && // into free space?
                        !state.StaticMaps.DeadMap[ppp])                      // Valid Push
                    {
                        EvaluateValidPush(state, pool, solutionPool, node, pp, ppp, p, dir, toEnqueue, toPool, ref solution);
                    }
                }
            }

            if (solution)
            {
                node.Status = SolverNodeStatus.SolutionPath;
            }
            else if (node.HasChildren)
            {
                node.Status = SolverNodeStatus.Evaluted;
                state.Statistics.TotalDead += node.CheckDead();    // Children may be evaluated as dead already
            }
            else
            {
                node.Status = SolverNodeStatus.Dead;
                state.Statistics.TotalDead++;
                if (node.Parent != null)
                {
                    state.Statistics.TotalDead += node.Parent.CheckDead();
                }
            }

            queue.Enqueue(toEnqueue);
            pool.Add(toPool);

            return(solution);
        }
示例#3
0
        public bool Evaluate(SolverState state, ISolverQueue queue, ISolverPool myPool,
                             ISolverPool solutionPool, SolverNode node)
        {
            if (node.HasChildren)
            {
                throw new InvalidOperationException();
            }

            node.Status = SolverNodeStatus.Evaluting;

            var solution  = false;
            var toEnqueue = new List <SolverNode>();

            foreach (var move in node.MoveMap.TruePositions())
            {
                foreach (var dir in VectorInt2.Directions)
                {
                    var p  = move;
                    var pc = p + dir;
                    var pp = p - dir;
                    if (node.CrateMap[pc] && // crate to push
                        state.StaticMaps.FloorMap[pp] && !node.CrateMap[p] &&
                        !CheckDeadReverse(state, pp))
                    {
                        EvaluateValidPull(state, myPool, solutionPool, node, pc, p, pp, toEnqueue, ref solution);
                    }
                }
            }

            if (solution)
            {
                node.Status = SolverNodeStatus.SolutionPath;
            }
            else if (node.HasChildren)
            {
                node.Status = SolverNodeStatus.Evaluted;
                state.Statistics.TotalDead += node.CheckDead(); // Children may be evaluated as dead already
            }
            else
            {
                node.Status = SolverNodeStatus.Dead;
                state.Statistics.TotalDead++;
                if (node.Parent != null)
                {
                    state.Statistics.TotalDead += node.Parent.CheckDead();
                }
            }


            queue.Enqueue(toEnqueue);
            myPool.Add(toEnqueue);

            return(solution);
        }
示例#4
0
 public SolverPoolSlimRwLock(ISolverPool inner)
 {
     this.inner = inner;
 }
 public SolverPoolDoubleBuffered(ISolverPool inner)
 {
     this.inner = inner;
 }
示例#6
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);
        }
示例#7
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);
        }
示例#8
0
 public abstract bool Evaluate(SolverState state, ISolverQueue queue, ISolverPool pool, ISolverPool solutionPool, SolverNode node);
示例#9
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);
        }