public void DeadMap() { // Init var report = new TestReport(); var stat = new StaticAnalysisMaps(TestLibrary.Default.Puzzle); var dead = DeadMapAnalysis.FindDeadMap(stat); Assert.NotNull(dead); report.WriteLine(dead); var expect = new TestReport( @"........... ....X...... ...X....XX. ..X......X. .X....X..X. .........X. ....X....X. ........X.. ..X....X... ..XXXXX.... ..........."); Assert.Equal(report, expect); }
/// <summary> /// Strong Constructor. Start with the dead map including all walls. /// </summary> /// <param name="goalMap"></param> /// <param name="wallMap"></param> public DeadMapState(SolverNode currentNode, Bitmap goalMap, Bitmap wallMap, DeadMapAnalysis deadMapAnalysis) : this(goalMap, wallMap, deadMapAnalysis) { this.crateMap = currentNode.CrateMap; this.moveMap = currentNode.MoveMap; this.dynamicNode = currentNode; }
public void Box() { // Init var report = new TestReport(); var puz = Puzzle.Builder.FromLines(new[] { "#####", "#...#", "#...#", "#...#", "#####" }); var stat = new StaticAnalysisMaps(puz); var dead = DeadMapAnalysis.FindDeadMap(stat); Assert.NotNull(dead); report.WriteLine(dead); Assert.Equal(new TestReport( @"..... .XXX. .X.X. .XXX. ....."), report); }
public void Regression2() { // Init var report = new TestReport(); var puz = Puzzle.Builder.FromLines(new[] { "################", "#..............#", "#..............#", "#.############.#", "#..............#", "################" }); var stat = new StaticAnalysisMaps(puz); var dead = DeadMapAnalysis.FindDeadMap(stat); Assert.NotNull(dead); report.WriteLine(dead); // Assert.That(report, Is.EqualTo(new TestReport( //@"........... //........... //........... //.......X... //........... //........... //.......X... //...X..X.... //........... //........... //..........." // }
/// <summary> /// Strong Constructor. Start with the dead map including all walls. /// </summary> /// <param name="goalMap"></param> /// <param name="wallMap"></param> public DeadMapState(Bitmap goalMap, Bitmap wallMap, DeadMapAnalysis deadMapAnalysis) : base("Dead Map", wallMap.Size) { this.goalMap = goalMap; this.wallMap = wallMap; this.deadMapAnalysis = deadMapAnalysis; this.mapSize = wallMap.Size; if (goalMap == null) throw new ArgumentNullException("goalMap"); if (wallMap == null) throw new ArgumentNullException("goalMap"); if (deadMapAnalysis == null) throw new ArgumentNullException("deadMapAnalysis"); }
public void DynamicDeadMap() { // Init var p = Puzzle.Builder.FromLines( new[] { "##########", "#...XX...#", "#...X#...#", "#.P......#", "##########" }); var stat = new StaticAnalysisMaps(p); Assert.True(DeadMapAnalysis.DynamicCheck(stat, StateMaps.Create(p))); p = Puzzle.Builder.FromLines( new[] { "##########", "#...#X...#", "#...X#...#", "#.P......#", "##########" }); stat = new StaticAnalysisMaps(p); Assert.True(DeadMapAnalysis.DynamicCheck(stat, StateMaps.Create(p))); p = Puzzle.Builder.FromLines( new[] { "##########", "#...##...#", "#...XX...#", "#.P......#", "##########" }); stat = new StaticAnalysisMaps(p); Assert.True(DeadMapAnalysis.DynamicCheck(stat, StateMaps.Create(p))); p = Puzzle.Builder.FromLines( new[] { "##########", "#........#", "#...XX...#", "#...##...#", "#.P......#", "##########" }); stat = new StaticAnalysisMaps(p); Assert.True(DeadMapAnalysis.DynamicCheck(stat, StateMaps.Create(p))); p = Puzzle.Builder.FromLines( new[] { "##########", "#........#", "#...XX...#", "#...X#...#", "#.P......#", "##########" }); stat = new StaticAnalysisMaps(p); Assert.True(DeadMapAnalysis.DynamicCheck(stat, StateMaps.Create(p))); p = Puzzle.Builder.FromLines( new[] { "##########", "#........#", "#...$$...#", "#...X#...#", "#.P......#", "##########" }); stat = new StaticAnalysisMaps(p); Assert.True(DeadMapAnalysis.DynamicCheck(stat, StateMaps.Create(p))); p = Puzzle.Builder.FromLines( new[] { "##########", "#........#", "#...$$...#", "#...#X...#", "#.P......#", "##########" }); stat = new StaticAnalysisMaps(p); Assert.True(DeadMapAnalysis.DynamicCheck(stat, StateMaps.Create(p))); p = Puzzle.Builder.FromLines( new[] { "##########", "#........#", "#...#X...#", "#...$$...#", "#.P......#", "##########" }); stat = new StaticAnalysisMaps(p); Assert.True(DeadMapAnalysis.DynamicCheck(stat, StateMaps.Create(p))); // NOT_DEAD p = Puzzle.Builder.FromLines( new[] { "##########", "#........#", "#...$$...#", "#...$#...#", "#.P......#", "##########" }); stat = new StaticAnalysisMaps(p); Assert.False(DeadMapAnalysis.DynamicCheck(stat, StateMaps.Create(p))); }
/// <summary> /// Build the 'DeadMap' for all positions on which a crate will make the puzzle unsolvable /// </summary> private void BuildDeadMap() { DeadMapAnalysis anal = new DeadMapAnalysis(); DeadMapState deadMapResult = anal.BuildDeadMap(null, goalMap, wallMap, controller.Strategy); deadMap = deadMapResult; cornerMap = deadMapResult.CornerMap; recessMap = deadMapResult.RecessMap; }
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); }
/// <summary> /// Build the 'DeadMap' for all positions on which a crate will make the puzzle unsolvable /// </summary> private void BuildDeadMap() { // Perform Recess Analysis RecessAnalysis recessAnalysis = new RecessAnalysis(); Bitmap TMPrecessMap; // Corners cornerMap = recessAnalysis.FindCorners(this); // Recesses recessAnalysis.FindRecesses(this, out recesses, out TMPrecessMap); recessMap = new SolverBitmap("RecessMap", TMPrecessMap); // Build Dead Map deadMapAnalysis = new DeadMapAnalysis(this); DeadMapState deadMapResult = deadMapAnalysis.BuildDeadMap(null, goalMap, wallMap); deadMap = deadMapResult; // TODO: This is a little rough, it needs to be reworked into 'DynamicPreProcesses' or similar DeadMapAnalysis.LateRuleInit(); }