private void NewSolutionChain(SolverState state, out bool solution, SolverNode newKid, SolverNode match) { solution = true; state.SolutionsNodesReverse ??= new List <SolutionChain>(); var pair = new SolutionChain { ForwardNode = newKid, ReverseNode = match, FoundUsing = this }; state.SolutionsNodesReverse.Add(pair); 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; }
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); }