/// <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; }
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 SolverNode?FindMatch(SolverNode node) { var i = block.BinarySearch(node, SolverNode.ComparerInstanceFull); if (i < 0) { return(null); } return(block[i]); }
public void Add(SolverNode node) { try { locker.EnterWriteLock(); inner.Add(node); } finally { locker.ExitWriteLock(); } }
public override SolverNode FindMatch(SolverNode node) { try { locker.EnterReadLock(); return base.FindMatch(node); } finally { locker.ExitReadLock(); } }
public override void Add(SolverNode node) { try { locker.EnterWriteLock(); base.AddInnerBuffer(node); } finally { locker.ExitWriteLock(); } }
private IEnumerable <SolverNode> Generate(int count, int width, int height) { Random r = new Random(); for (var x = 0; x < count; x++) { var n = new SolverNode(null, new VectorInt2(), new VectorInt2(), new Bitmap(width, height), new Bitmap(width, height) ); for (var y = 0; y < width * height / 4; y++) { n.CrateMap[r.Next(0, width), r.Next(0, height)] = true; n.MoveMap[r.Next(0, width), r.Next(0, height)] = true; } yield return(n); } }
// Better memory usage, does not creat an array of all nodes public void WriteTree(BinaryWriter bw, SolverNode root) { var count = root.CountRecursive(); WriteHeader(bw, root.MoveMap.Size, count); int cc = 0; foreach (var node in root.Recurse()) { Write(bw, node); cc++; } if (cc != count) { throw new Exception($"Invalid Counts: Count: {count} vs {cc} vs {root.Recurse().Count()}"); } }
public void SingleNode() { var d = Puzzle.Builder.DefaultTestPuzzle(); var n = new SolverNode(null, d.Player.Position, VectorInt2.Left, d.ToMap(d.Definition.AllCrates), d.ToMap(d.Definition.AllFloors)); var mem = new MemoryStream(); var writer = new BinaryNodeSerializer(); using (var sw = new BinaryWriter(mem, Encoding.Unicode, true)) { writer.Write(sw, n); } mem.Seek(0, SeekOrigin.Begin); using (var sr = new BinaryReader(mem)) { var temp = writer.Read(sr); Assert.Equal(n.SolverNodeId, temp.SolverNodeId); Assert.Equal(0, temp.ParentId); Assert.Equal(n.PlayerBefore.X, temp.PlayerBeforeX); Assert.Equal(n.PlayerBefore.Y, temp.PlayerBeforeY); Assert.Equal(n.Push.X, temp.PushX); Assert.Equal(n.Push.Y, temp.PushY); Assert.Equal(n.Status, (SolverNodeStatus)temp.Status); var c = n.CrateMap is BitmapByteSeq bs ? bs : new BitmapByteSeq(n.CrateMap); Assert.Equal(c.GetArray(), temp.Crate); var m = n.MoveMap is BitmapByteSeq ms ? ms : new BitmapByteSeq(n.MoveMap); Assert.Equal(m.GetArray(), temp.Move); } }
public void Write(BinaryWriter sw, SolverNode n) { sw.Write(n.SolverNodeId); sw.Write(n.Parent?.SolverNodeId ?? 0); sw.Write(n.PlayerBefore.X); sw.Write(n.PlayerBefore.Y); sw.Write(n.Push.X); sw.Write(n.Push.Y); sw.Write((byte)n.Status); sw.Write(n.GetHashCode()); var c = n.CrateMap is BitmapByteSeq bs ? bs : new BitmapByteSeq(n.CrateMap); var cc = c.GetArray(); sw.Write(cc.Length); sw.Write(cc); var m = n.MoveMap is BitmapByteSeq ms ? ms : new BitmapByteSeq(n.MoveMap); var mm = m.GetArray(); sw.Write(mm.Length); sw.Write(mm); }
int IndexOf(List<SolverNode> list, SolverNode node) { for (int cc=0; cc<list.Count; cc++) { if (object.ReferenceEquals(list[cc], node)) return cc; } return -1; }
public NodeListVisualisationElement(NodeListVisualisation parent, SolverNode node) { this.node = node; this.owner = parent; }
private void RecursiveSolve(SolverNode node, List<Matrix> solutions) { List<Cell> emptyCells = ListEmptyCells(node.MatrixState); if (node.MatrixState.HasSolution && !node.MatrixState.IsResolved) { foreach (Cell emptyCell in emptyCells) { CalculatePossibilities(emptyCell, node.MatrixState); if (emptyCell.Possibilities.Count == 1) { int foundedValue = emptyCell.Possibilities[0]; emptyCell.Value = foundedValue; node.MatrixState.LoadValue(emptyCell.Coordinates, emptyCell.Value); if (ValueAdded != null) ValueAdded(this, new ValueChangedEventArgs(node.MatrixState)); RecursiveSolve(node, solutions); if (solutions.Count == solutions.Capacity) break; if (!node.MatrixState.HasSolution) { node.Dispose(); node = null; break; } } } } if (emptyCells.Count == 0 && !node.MatrixState.IsResolved) { node.MatrixState.IsResolved = true; if (!solutions.Contains(node.MatrixState, Matrix.Comparer) && solutions.Count < solutions.Capacity) solutions.Add(node.MatrixState); } else { if (node != null && node.ChildNodes.Count == 0 && !node.MatrixState.IsResolved && node.MatrixState.HasSolution) { List<Cell> orderedEmptyCells = (from emptyCell in emptyCells orderby emptyCell.Possibilities.Count select emptyCell).ToList(); if (orderedEmptyCells.Count > 0) { Cell lessPossibilitiesCell = orderedEmptyCells[0]; if (lessPossibilitiesCell.Possibilities.Count > 0) { foreach (int possibility in lessPossibilitiesCell.Possibilities) { Matrix possibleState = new Matrix(node.MatrixState); possibleState.LoadValue(lessPossibilitiesCell.Coordinates, possibility); if (ValueAdded != null) ValueAdded(this, new ValueChangedEventArgs(possibleState)); node.ChildNodes.Add(new SolverNode(possibleState)); } int noSolutionCount = 0; foreach (SolverNode childNode in node.ChildNodes) { RecursiveSolve(childNode, solutions); if (solutions.Count == solutions.Capacity) break; if (!node.MatrixState.HasSolution) { node.Dispose(); node = null; break; } if (!childNode.MatrixState.HasSolution) { noSolutionCount++; } } if (node.ChildNodes.Count > 0 && node.ChildNodes.Count == noSolutionCount && !node.MatrixState.IsResolved) { node.MatrixState.HasSolution = false; if (ValueRemoved != null) ValueRemoved(this, new ValueChangedEventArgs(node.MatrixState)); } } else { node.MatrixState.HasSolution = false; if (ValueRemoved != null) ValueRemoved(this, new ValueChangedEventArgs(node.MatrixState)); } } else { node.MatrixState.HasSolution = false; if (ValueRemoved != null) ValueRemoved(this, new ValueChangedEventArgs(node.MatrixState)); } } } }
/// <summary> /// Get the logical postiion for a node /// </summary> /// <param name="node"></param> /// <returns></returns> public VectorInt GetLogicalPosition(SolverNode node) { int idx = IndexOf(nodes, node); if (idx < 0) return VectorInt.Null; return new VectorInt(idx % maxCellWidth, idx / maxCellWidth); }
protected Pen GetPen(SolverNode node) { if (node != null) { if (node.IsStateEvaluated) return new Pen(Color.Blue); if (node.IsChildrenEvaluated) return new Pen(Color.Orange); } return new Pen(Color.Gray); }
public ReuseTreeSolverQueue(SolverNode root) { this.root = root; }
/// <summary> /// Check if two node are a match /// </summary> /// <param name="lhs"></param> /// <param name="rhs"></param> /// <returns></returns> private bool ChainMatch(SolverNode lhs, SolverNode rhs) { if (lhs == null) return false; if (rhs == null) return false; // Question: Are the cratemaps equal enough? Or do we need the move map too? return (lhs.CrateMap == rhs.CrateMap && lhs.MoveMap == rhs.MoveMap && lhs.MoveMap != null); }
/// <summary> /// Retrive a display element for the corrosponding domain node /// </summary> /// <param name="node"></param> /// <returns></returns> public RootPathElement this[SolverNode node] { get { return elements.Find(delegate(RootPathElement item) { return item.Node == node; }); } }
/// <summary> /// Register a new node for stats /// </summary> /// <param name="node"></param> public void NewNode(SolverNode node) { if (node == null) return; if (node.IsForward) { if (BestNodesFwd.Count == 0 || node.Weighting > BestNodesFwd.Last.Value.Weighting) { InsertSorted(BestNodesFwd, node); } } else { if (BestNodesRev.Count == 0 || node.Weighting > BestNodesRev.Last.Value.Weighting) { InsertSorted(BestNodesRev, node); } } }
private void InsertSorted(LinkedList<SolverNode> list, SolverNode node) { lock(list) { if (list.Count == 0) { list.AddFirst(node); return; } LinkedListNode<SolverNode> current = list.First; while (current != null && current.Value.Weighting >= node.Weighting) { current = current.Next; } if (current == null) { if (list.Count < MaxBestNodes) { list.AddLast(node); return; } return; } // Add list.AddBefore(current, node); // Check max length if (list.Count > MaxBestNodes) { list.RemoveLast(); } } }
public RootPathElement(RootPathVisualisation owner, SolverNode node) { this.owner = owner; this.node = node; }
public SolverNode FindMatch(SolverNode node) { try { locker.EnterReadLock(); return inner.FindMatch(node); } finally { locker.ExitReadLock(); } }
protected Brush GetBrush(SolverNode node) { if (node != null) { switch (node.Status) { case (SolverNodeStates.None): // Try something else if (node.Weighting != 0) { int green = (int)(node.Weighting * 50); return new SolidBrush(Color.FromArgb(0, green % 255, 0)); } return new SolidBrush(Color.Cornsilk); case (SolverNodeStates.Duplicate): return new SolidBrush(Color.DarkGray); case (SolverNodeStates.Solution): return new SolidBrush(Color.Cyan); case (SolverNodeStates.SolutionPath): return new SolidBrush(Color.LightCyan); case (SolverNodeStates.Dead): return new SolidBrush(Color.Black); case (SolverNodeStates.DeadChildren): return new SolidBrush(Color.DarkRed); } } return new SolidBrush(Color.Purple); }
/// <summary> /// Select a SPECIFIC node and display its details /// </summary> /// <param name="solverNode"></param> private void BindNode(SolverNode solverNode) { if (solverNode == null) return; SokobanMap build = BuildCurrentMap(solverNode); if (build != null) { BitmapViewer.Layer puzzleLayer = new BitmapViewer.Layer(); puzzleLayer.Name = "Puzzle"; puzzleLayer.Map = build; puzzleLayer.Order = 0; puzzleLayer.IsVisible = true; bitmapViewerNodeMaps.SetLayer(puzzleLayer).IsVisible = true; } if (solverNode.MoveMap != null) { SolverBitmap move = new SolverBitmap("MoveMap", solverNode.MoveMap); bitmapViewerNodeMaps.SetLayer(move, new SolidBrush(Color.FromArgb(120, Color.Green))).IsVisible = true; } if (solverNode.DeadMap != null) { bitmapViewerNodeMaps.SetLayer(solverNode.DeadMap, new SolidBrush(Color.FromArgb(120, Color.Black))).IsVisible = true; } // Build details SolverLabelList txt = solverNode.GetDisplayData(); ReportXHTML reportCurrent = new ReportXHTML("Node Details"); reportCurrent.SetCSSInline(FileManager.GetContent("$html\\style.css")); reportCurrent.Add(txt.ToHTML()); if (build != null) { reportCurrent.Add(string.Format("<code><pre>{0}</pre></code>", build.ToString())); } webBrowserNodeCurrent.DocumentText = reportCurrent.ToString(); bitmapViewerNodeMaps.Render(); RootPathVisualisation localVis = new RootPathVisualisation(new SizeInt(16, 16), controller); localVis.RenderCanvas = new RectangleInt(0, 0, visualisationContainerLocalNodes.Width - 30, visualisationContainerLocalNodes.Height - 30); localVis.Init(solverNode); visualisationContainerLocalNodes.ClearImage(); visualisationContainerLocalNodes.Visualisation = localVis; visualisationContainerLocalNodes.Render(); }
/// <summary> /// Check in the forward solver if a reverse node is found. Ie look for a cross-over, hence solution. /// </summary> /// <param name="reverseNode"></param> /// <returns></returns> public bool CheckChainForward(SolverNode reverseNode) { if (stats != null) { stats.NewNode(reverseNode); } if (strategy == null) return false; SolverNode match = strategy.CheckDuplicate(reverseNode); if (match != null) { debugReport.Append("Found a forward chain {0}<->{1}", match.NodeID, reverseNode.NodeID); match.Status = SolverNodeStates.SolutionChain; reverseNode.Status = SolverNodeStates.SolutionChain; state = States.CompleteSolution; // Set the link property reverseNode.ChainSolutionLink = match; match.ChainSolutionLink = reverseNode; return true; } return false; }
private SokobanMap BuildCurrentMap(SolverNode node) { SokobanMap result = new SokobanMap(); result.Init(node.CrateMap.Size); for (int cx = 0; cx < result.Size.Width; cx++) for (int cy = 0; cy < result.Size.Height; cy++) { if (controller.StaticAnalysis.WallMap[cx, cy]) result[cx, cy] = CellStates.Wall; if (controller.StaticAnalysis.FloorMap[cx, cy]) result[cx, cy] = CellStates.Floor; if (controller.StaticAnalysis.GoalMap[cx, cy]) result.SetState(new VectorInt(cx, cy), Cell.Goal); if (node.CrateMap[cx, cy]) result.SetState(new VectorInt(cx, cy), Cell.Crate); result.SetState(node.PlayerPosition, Cell.Player); } return result; }
public SolverTree(Matrix mainMatrix) { Root = new SolverNode(mainMatrix); }
/// <summary> /// Initialise the elements /// </summary> /// <param name="current"></param> public void Init(SolverNode current) { elements = new List<RootPathElement>(); bands = new List<List<RootPathElement>>(); int maxDepth = 0; int currentDepth = 10; List<RootPathElement> currentBand; for (int cc = 0; cc < currentDepth + 2; cc++) { bands.Add(new List<RootPathElement>()); } while (currentDepth >= maxDepth && current != null) { // Add RootPathElement newElement = new RootPathElement(this, current); newElement.OnPath = true; elements.Add(newElement); bands[currentDepth].Add(newElement); // Add all children if (current.TreeNode.HasChildren) { foreach (SolverNode child in current.TreeNode.ChildrenData) { if (!Exists(child)) { RootPathElement childElement = new RootPathElement(this, child); elements.Add(childElement); bands[currentDepth + 1].Add(childElement); } } } if (current.TreeNode.Parent != null) { current = current.TreeNode.Parent.Data; } else { current = null; } currentDepth--; } foreach (List<RootPathElement> band in bands) { // Insert path back in the middle RootPathElement path = band.Find(delegate(RootPathElement element) { return element.OnPath; }); if (path != null) { band.Remove(path); band.Insert(band.Count/2, path); } } }
protected Brush GetBrush(SolverNode node) { if (node != null) { switch (node.Status) { case (SolverNodeStates.None): float weighting = node.Weighting; if (weighting < 0) { return new SolidBrush(Color.DarkGray); } if (weighting == 0) { new SolidBrush(Color.Cornsilk); } if (owner.controller.Stats.WeightingMax.ValueTotal > 0) { int min = 50; int max = 250; int value = Convert.ToInt32(weighting / owner.controller.Stats.WeightingMax.ValueTotal * (float)max); return new SolidBrush(Color.FromArgb(50, value, 50)); } return new SolidBrush(Color.Cornsilk); case (SolverNodeStates.Duplicate): return new SolidBrush(Color.Brown); case (SolverNodeStates.Solution): return new SolidBrush(Color.Red); case (SolverNodeStates.SolutionPath): return new SolidBrush(Color.Red); case (SolverNodeStates.Dead): return new SolidBrush(Color.Pink); case (SolverNodeStates.DeadChildren): return new SolidBrush(Color.Pink); } } return new SolidBrush(Color.Purple); }
private bool Exists(SolverNode current) { return this[current] != null; }
public SolverNode Init(Puzzle puzzle, ISolverQueue queue) { var solution = puzzle.ToMap(puzzle.Definition.AllGoals); // START with a solution var walls = puzzle.ToMap(puzzle.Definition.Wall); // The is only one start, but MANY end soutions. Hence a single root is not a valid representation // We use a placeholder node (not an actualy move to hold solutions) var root = new SingleThreadedReverseSolver.SyntheticReverseNode() { CrateMap = puzzle.ToMap(puzzle.Definition.AllGoals), MoveMap = new Bitmap(puzzle.Width, puzzle.Height) }; foreach (var crateBefore in solution.TruePositions()) { foreach (var dir in VectorInt2.Directions) { // ss var posPlayer = crateBefore + dir; var posPlayerAfter = posPlayer + dir; var crateAfter = crateBefore + dir; // Remember: In reverse mode goals are crates, and crate may be floor if ((puzzle[posPlayer] == puzzle.Definition.Floor || puzzle[posPlayer] == puzzle.Definition.Player || puzzle[posPlayer] == puzzle.Definition.Crate ) && (puzzle[posPlayerAfter] == puzzle.Definition.Floor || puzzle[posPlayerAfter] == puzzle.Definition.Player || puzzle[posPlayer] == puzzle.Definition.Crate ) ) { var crate = new Bitmap(solution); crate[crateBefore] = false; crate[crateAfter] = true; var node = new SolverNode() { CrateBefore = crateBefore, CrateAfter = crateAfter, PlayerBefore = posPlayer, PlayerAfter = posPlayerAfter, CrateMap = crate, MoveMap = FloodFill.Fill(walls.BitwiseOR(crate), posPlayerAfter) }; if (node.MoveMap.Count > 0) { root.Add(node); queue.Enqueue(node); } } } } return root; }
string BestNodeToString(SolverNode node) { if (node.IsChildrenEvaluated) { return string.Format("<a href=\"app://node/{0}\"><b>{1:0.00}</b></a>", node.NodeID, node.Weighting); } return string.Format("<a href=\"app://node/{0}\">{1:0.00}</a>", node.NodeID, node.Weighting); }
private bool CheckValidSolutions(SolverCommandResult state, SolverNode posibleSolution) { var b = state.StaticMaps.WallMap.BitwiseOR(state.StaticMaps.CrateStart); var f = state.Command.Puzzle.Player.Position; var path = posibleSolution.PathToRoot(); path.Reverse(); var start = path[0]; var t = start.PlayerAfter; var first = PathFinder.Find(b, f, t); return first != null; }
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; }
public void Enqueue(SolverNode node) { Statistics.TotalNodes++; inner.Enqueue(node); }