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); }
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); }
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); }
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); }