private SolverNode Assemble( SolverNode parent, StagingSolverNode flat, ImmutableDictionary <int, StagingSolverNode> all, ImmutableDictionary <int, ImmutableArray <StagingSolverNode> > parents) { var n = new SolverNode(parent, new VectorInt2(flat.PlayerBeforeX, flat.PlayerBeforeY), new VectorInt2(flat.PushX, flat.PushY), flat.CrateMap, flat.MoveMap, flat.SolverNodeId ); n.Status = (SolverNodeStatus)flat.Status; if (parents.TryGetValue(flat.SolverNodeId, out var kids)) { foreach (var kid in kids) { n.Add(Assemble(n, kid, all, parents)); } } return(n); }
public bool Evaluate(SolverCommandResult state, ISolverQueue queue, ISolverNodeLookup myPool, ISolverNodeLookup 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 { if (state.StaticMaps.FloorMap[pp] && !node.CrateMap[p]) { if (!CheckDeadReverse(state, pp)) { var newKid = new SolverNode { PlayerBefore = p, PlayerAfter = pp, CrateBefore = pc, CrateAfter = p, CrateMap = new Bitmap(node.CrateMap), Evaluator = this, }; newKid.CrateMap[pc] = false; newKid.CrateMap[p] = true; var boundry = state.StaticMaps.WallMap.BitwiseOR(newKid.CrateMap); newKid.MoveMap = FloodFill.Fill(boundry, pp); newKid.Goals = newKid.CrateMap.BitwiseAND(state.StaticMaps.GoalMap).Count(); // Optimisation: PreCalc hash newKid.EnsureHash(); // Cycle Check: Does this node exist already? var dup = myPool.FindMatch(newKid); if (dup != null) { // NOTE: newKid is NOT added as a ChildNode (which means less memory usage) // Duplicate newKid.Status = SolverNodeStatus.Duplicate; state.Statistics.Duplicates++; if (IsDebugMode) { node.AddDuplicate(dup); } } else { SolverNode match = null; if (solutionPool != null) match = solutionPool.FindMatch(newKid); if (match != null) { // Add to tree / itterator node.Add(newKid); // Solution if (state.SolutionsWithReverse == null) state.SolutionsWithReverse = new List<SolutionChain>(); var pair = new SolutionChain() { ForwardNode = match, ReverseNode = newKid, FoundUsing = this }; state.SolutionsWithReverse.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 / itterator node.Add(newKid); if (DeadMapAnalysis.DynamicCheck(state.StaticMaps, node)) { newKid.Status = SolverNodeStatus.Dead; } else { toEnqueue.Add(newKid); if (newKid.CrateMap.BitwiseAND(state.StaticMaps.CrateStart).Equals(newKid.CrateMap)) { // Possible Solution: Did we start in a valid position if (CheckValidSolutions(state, newKid)) { state.Solutions.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 { newKid.Status = SolverNodeStatus.InvalidSolution; } } } } } } } } } } node.Status = node.HasChildren ? SolverNodeStatus.Evaluted : SolverNodeStatus.Dead; if (node.Status == SolverNodeStatus.Dead && node.Parent != null) { var p = (SolverNode)node.Parent; p.CheckDead(); } queue.Enqueue(toEnqueue); myPool.Add(toEnqueue); return solution; }