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); }
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); }
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); }
public SolverPoolSlimRwLock(ISolverPool inner) { this.inner = inner; }
public SolverPoolDoubleBuffered(ISolverPool inner) { this.inner = inner; }
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); }
public abstract bool Evaluate(SolverState state, ISolverQueue queue, ISolverPool pool, ISolverPool solutionPool, SolverNode node);
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); }