public void Init(TilePropagator propagator) { tileSet = propagator.CreateTileSet(Tiles); endPointTileSet = EndPointTiles != null?propagator.CreateTileSet(EndPointTiles) : null; graph = PathConstraintUtils.CreateGraph(propagator.Topology); }
public void Init(TilePropagator propagator) { ISet <Tile> actualTiles; ISet <Tile> actualEndPointTiles; if (TileRotation != null) { actualTiles = new HashSet <Tile>(TileRotation.RotateAll(Tiles)); actualEndPointTiles = EndPointTiles == null ? null : new HashSet <Tile>(TileRotation.RotateAll(EndPointTiles)); } else { actualTiles = Tiles; actualEndPointTiles = EndPointTiles; } tileSet = propagator.CreateTileSet(actualTiles); selectedTracker = propagator.CreateSelectedTracker(tileSet); endPointTileSet = EndPointTiles != null?propagator.CreateTileSet(actualEndPointTiles) : null; endPointSelectedTracker = EndPointTiles != null?propagator.CreateSelectedTracker(endPointTileSet) : null; graph = PathConstraintUtils.CreateGraph(propagator.Topology); Check(propagator, true); }
public void Check(TilePropagator propagator) { var topology = propagator.Topology; var indices = topology.Width * topology.Height * topology.Depth; // Initialize couldBePath and mustBePath based on wave possibilities var couldBePath = new bool[indices]; var mustBePath = new bool[indices]; for (int i = 0; i < indices; i++) { topology.GetCoord(i, out var x, out var y, out var z); propagator.GetBannedSelected(x, y, z, tileSet, out var isBanned, out var isSelected); couldBePath[i] = !isBanned; mustBePath[i] = isSelected; } // Select relevant cells, i.e. those that must be connected. bool[] relevant; if (EndPoints == null) { relevant = mustBePath; } else { relevant = new bool[indices]; if (EndPoints.Length == 0) { return; } foreach (var endPoint in EndPoints) { var index = topology.GetIndex(endPoint.X, endPoint.Y, endPoint.Z); relevant[index] = true; } } var walkable = couldBePath; var isArticulation = PathConstraintUtils.GetArticulationPoints(graph, walkable, relevant); if (isArticulation == null) { propagator.SetContradiction(); return; } // All articulation points must be paths, // So ban any other possibilities for (var i = 0; i < indices; i++) { if (isArticulation[i]) { topology.GetCoord(i, out var x, out var y, out var z); propagator.Select(x, y, z, tileSet); } } }
public void Check(TilePropagator propagator) { pathView.Update(); var info = PathConstraintUtils.GetArticulationPoints(pathView.Graph, pathView.CouldBePath, pathView.MustBeRelevant); var isArticulation = info.IsArticulation; for (var i = 0; i < pathView.Graph.NodeCount; i++) { if (isArticulation[i]) { propagator.SetContradiction("Loop constraint found articulation point.", this); return; } } }
public PathView(PathSpec spec, TilePropagator propagator) { if (spec.TileRotation != null) { tiles = new HashSet <Tile>(spec.TileRotation.RotateAll(spec.Tiles)); endPointTiles = spec.RelevantTiles == null ? null : new HashSet <Tile>(spec.TileRotation.RotateAll(spec.RelevantTiles)); } else { tiles = spec.Tiles; endPointTiles = spec.RelevantTiles; } tileSet = propagator.CreateTileSet(tiles); selectedTracker = propagator.CreateSelectedTracker(tileSet); Graph = PathConstraintUtils.CreateGraph(propagator.Topology); this.propagator = propagator; CouldBePath = new bool[propagator.Topology.IndexCount]; MustBePath = new bool[propagator.Topology.IndexCount]; hasEndPoints = spec.RelevantCells != null || spec.RelevantTiles != null; if (hasEndPoints) { CouldBeRelevant = new bool[propagator.Topology.IndexCount]; MustBeRelevant = new bool[propagator.Topology.IndexCount]; endPointIndices = spec.RelevantCells == null ? null : spec.RelevantCells.Select(p => propagator.Topology.GetIndex(p.X, p.Y, p.Z)).ToList(); endPointTileSet = spec.RelevantTiles != null?propagator.CreateTileSet(endPointTiles) : null; endPointSelectedTracker = spec.RelevantTiles != null?propagator.CreateSelectedTracker(endPointTileSet) : null; } else { CouldBeRelevant = CouldBePath; MustBeRelevant = MustBePath; endPointTileSet = tileSet; } }
public void Check(TilePropagator propagator) { pathView.Update(); var info = PathConstraintUtils.GetArticulationPoints(pathView.Graph, pathView.CouldBePath, pathView.MustBeRelevant); var isArticulation = info.IsArticulation; if (info.ComponentCount > 1) { propagator.SetContradiction(); return; } // All articulation points must be paths, // So ban any other possibilities for (var i = 0; i < pathView.Graph.NodeCount; i++) { if (isArticulation[i] && !pathView.MustBePath[i]) { pathView.SelectPath(i); } } // Any path tiles / EndPointTiles not in the connected component aren't safe to add. // Disabled for now, unclear exactly when it is needed if (info.ComponentCount > 0) { var component = info.Component; for (int i = 0; i < pathView.Graph.NodeCount; i++) { if (component[i] == null && pathView.CouldBeRelevant[i]) { pathView.BanRelevant(i); } } } }
private void Check(TilePropagator propagator, bool init) { var topology = propagator.Topology; var indices = topology.IndexCount; // Initialize couldBePath and mustBePath based on wave possibilities var couldBePath = new bool[indices]; var mustBePath = new bool[indices]; for (int i = 0; i < indices; i++) { var ts = selectedTracker.GetQuadstate(i); couldBePath[i] = ts.Possible(); mustBePath[i] = ts.IsYes(); } // Select relevant cells, i.e. those that must be connected. var hasEndPoints = EndPoints != null || EndPointTiles != null; bool[] relevant; if (!hasEndPoints) { relevant = mustBePath; } else { relevant = new bool[indices]; var relevantCount = 0; if (EndPoints != null) { foreach (var endPoint in EndPoints) { var index = topology.GetIndex(endPoint.X, endPoint.Y, endPoint.Z); relevant[index] = true; relevantCount++; } } if (EndPointTiles != null) { for (int i = 0; i < indices; i++) { if (endPointSelectedTracker.IsSelected(i)) { relevant[i] = true; relevantCount++; } } } if (relevantCount == 0) { // Nothing to do. return; } } if (init) { for (int i = 0; i < indices; i++) { if (relevant[i]) { topology.GetCoord(i, out var x, out var y, out var z); propagator.Select(x, y, z, tileSet); } } } var walkable = couldBePath; var info = PathConstraintUtils.GetArticulationPoints(graph, walkable, relevant); var isArticulation = info.IsArticulation; if (info.ComponentCount > 1) { propagator.SetContradiction("Path constraint found multiple components", this); return; } // All articulation points must be paths, // So ban any other possibilities for (var i = 0; i < indices; i++) { if (isArticulation[i] && !mustBePath[i]) { topology.GetCoord(i, out var x, out var y, out var z); propagator.Select(x, y, z, tileSet); } } // Any path tiles / EndPointTiles not in the connected component aren't safe to add. if (info.ComponentCount > 0) { var component = info.Component; var actualEndPointTileSet = hasEndPoints ? endPointTileSet : tileSet; if (actualEndPointTileSet != null) { for (int i = 0; i < indices; i++) { if (component[i] == null) { topology.GetCoord(i, out var x, out var y, out var z); propagator.Ban(x, y, z, actualEndPointTileSet); } } } } }
private void Check(TilePropagator propagator, bool init) { var topology = propagator.Topology; var indices = topology.Width * topology.Height * topology.Depth; var nodesPerIndex = topology.DirectionsCount + 1; // Initialize couldBePath and mustBePath based on wave possibilities var couldBePath = new bool[indices * nodesPerIndex]; var mustBePath = new bool[indices * nodesPerIndex]; var exitMustBePath = new bool[indices * nodesPerIndex]; foreach (var kv in trackerByExit) { var exit = kv.Key; var tracker = kv.Value; for (int i = 0; i < indices; i++) { var ts = tracker.GetQuadstate(i); couldBePath[i * nodesPerIndex + 1 + (int)exit] = ts.Possible(); // Cannot put this in mustBePath these points can be disconnected, depending on topology mask exitMustBePath[i * nodesPerIndex + 1 + (int)exit] = ts.IsYes(); } } for (int i = 0; i < indices; i++) { var pathTs = pathSelectedTracker.GetQuadstate(i); couldBePath[i * nodesPerIndex] = pathTs.Possible(); mustBePath[i * nodesPerIndex] = pathTs.IsYes(); } // Select relevant cells, i.e. those that must be connected. var hasEndPoints = EndPoints != null || EndPointTiles != null; bool[] relevant; if (!hasEndPoints) { // Basically equivalent to EndPoints = pathTileSet relevant = mustBePath; } else { relevant = new bool[indices * nodesPerIndex]; var relevantCount = 0; if (EndPoints != null) { foreach (var endPoint in EndPoints) { var index = topology.GetIndex(endPoint.X, endPoint.Y, endPoint.Z); relevant[index * nodesPerIndex] = true; relevantCount++; } } if (EndPointTiles != null) { for (int i = 0; i < indices; i++) { if (endPointSelectedTracker.IsSelected(i)) { relevant[i * nodesPerIndex] = true; relevantCount++; } } } if (relevantCount == 0) { // Nothing to do. return; } } if (init) { for (int i = 0; i < indices; i++) { if (relevant[i * nodesPerIndex]) { topology.GetCoord(i, out var x, out var y, out var z); propagator.Select(x, y, z, pathTileSet); } } } var walkable = couldBePath; var info = PathConstraintUtils.GetArticulationPoints(graph, walkable, relevant); var isArticulation = info.IsArticulation; if (info.ComponentCount > 1) { propagator.SetContradiction("Edged path constraint found multiple connected components.", this); return; } // All articulation points must be paths, // So ban any other possibilities for (var i = 0; i < indices; i++) { topology.GetCoord(i, out var x, out var y, out var z); if (isArticulation[i * nodesPerIndex] && !mustBePath[i * nodesPerIndex]) { propagator.Select(x, y, z, pathTileSet); } for (var d = 0; d < topology.DirectionsCount; d++) { if (isArticulation[i * nodesPerIndex + 1 + d] && !exitMustBePath[i * nodesPerIndex + 1 + d]) { if (tilesByExit.TryGetValue((Direction)d, out var exitTiles)) { propagator.Select(x, y, z, exitTiles); } } } } // Any path tiles / EndPointTiles not in the connected component aren't safe to add. if (info.ComponentCount > 0) { var component = info.Component; var actualEndPointTileSet = hasEndPoints ? endPointTileSet : pathTileSet; if (actualEndPointTileSet != null) { for (int i = 0; i < indices; i++) { if (component[i * nodesPerIndex] == null) { topology.GetCoord(i, out var x, out var y, out var z); propagator.Ban(x, y, z, actualEndPointTileSet); } } } } }
public void Check(TilePropagator propagator) { var topology = propagator.Topology; var indices = topology.Width * topology.Height * topology.Depth; // Initialize couldBePath and mustBePath based on wave possibilities var couldBePath = new bool[indices]; var mustBePath = new bool[indices]; for (int i = 0; i < indices; i++) { var ts = selectedTracker.GetTristate(i); couldBePath[i] = ts.Possible(); mustBePath[i] = ts.IsYes(); } // Select relevant cells, i.e. those that must be connected. bool[] relevant; if (EndPoints == null && EndPointTiles == null) { relevant = mustBePath; } else { relevant = new bool[indices]; var relevantCount = 0; if (EndPoints != null) { foreach (var endPoint in EndPoints) { var index = topology.GetIndex(endPoint.X, endPoint.Y, endPoint.Z); relevant[index] = true; relevantCount++; } } if (EndPointTiles != null) { for (int i = 0; i < indices; i++) { if (endPointSelectedTracker.IsSelected(i)) { relevant[i] = true; relevantCount++; } } } if (relevantCount == 0) { // Nothing to do. return; } } var walkable = couldBePath; var component = EndPointTiles != null ? new bool[indices] : null; var isArticulation = PathConstraintUtils.GetArticulationPoints(graph, walkable, relevant, component); if (isArticulation == null) { propagator.SetContradiction(); return; } // All articulation points must be paths, // So ban any other possibilities for (var i = 0; i < indices; i++) { if (isArticulation[i] && !mustBePath[i]) { topology.GetCoord(i, out var x, out var y, out var z); propagator.Select(x, y, z, tileSet); } } // Any EndPointTiles not in the connected component aren't safe to add if (EndPointTiles != null) { for (int i = 0; i < indices; i++) { if (!component[i]) { topology.GetCoord(i, out var x, out var y, out var z); propagator.Ban(x, y, z, endPointTileSet); } } } }
public void Check(TilePropagator propagator) { var topology = propagator.Topology; var indices = topology.Width * topology.Height * topology.Depth; var nodesPerIndex = topology.DirectionsCount + 1; // Initialize couldBePath and mustBePath based on wave possibilities var couldBePath = new bool[indices * nodesPerIndex]; var mustBePath = new bool[indices * nodesPerIndex]; var exitMustBePath = new bool[indices * nodesPerIndex]; foreach (var kv in trackerByExit) { var exit = kv.Key; var tracker = kv.Value; for (int i = 0; i < indices; i++) { var ts = tracker.GetTristate(i); couldBePath[i * nodesPerIndex + 1 + (int)exit] = ts.Possible(); // Cannot put this in mustBePath these points can be disconnected, depending on topology mask exitMustBePath[i * nodesPerIndex + 1 + (int)exit] = ts.IsYes(); } } for (int i = 0; i < indices; i++) { var pathTs = pathSelectedTracker.GetTristate(i); couldBePath[i * nodesPerIndex] = pathTs.Possible(); mustBePath[i * nodesPerIndex] = pathTs.IsYes(); } // Select relevant cells, i.e. those that must be connected. bool[] relevant; if (EndPoints == null && EndPointTiles == null) { relevant = mustBePath; } else { relevant = new bool[indices * nodesPerIndex]; var relevantCount = 0; if (EndPoints != null) { foreach (var endPoint in EndPoints) { var index = topology.GetIndex(endPoint.X, endPoint.Y, endPoint.Z); relevant[index * nodesPerIndex] = true; relevantCount++; } } if (EndPointTiles != null) { for (int i = 0; i < indices; i++) { if (endPointSelectedTracker.IsSelected(i)) { relevant[i * nodesPerIndex] = true; relevantCount++; } } } if (relevantCount == 0) { // Nothing to do. return; } } var walkable = couldBePath; var component = EndPointTiles != null ? new bool[indices] : null; var isArticulation = PathConstraintUtils.GetArticulationPoints(graph, walkable, relevant, component); if (isArticulation == null) { propagator.SetContradiction(); return; } // All articulation points must be paths, // So ban any other possibilities for (var i = 0; i < indices; i++) { topology.GetCoord(i, out var x, out var y, out var z); if (isArticulation[i * nodesPerIndex] && !mustBePath[i * nodesPerIndex]) { propagator.Select(x, y, z, pathTileSet); } for (var d = 0; d < topology.DirectionsCount; d++) { if (isArticulation[i * nodesPerIndex + 1 + d] && !exitMustBePath[i * nodesPerIndex + 1 + d]) { propagator.Select(x, y, z, tilesByExit[(Direction)d]); } } } // Any EndPointTiles not in the connected component aren't safe to add if (EndPointTiles != null) { for (int i = 0; i < indices; i++) { if (!component[i * nodesPerIndex]) { topology.GetCoord(i, out var x, out var y, out var z); propagator.Ban(x, y, z, endPointTileSet); } } } }
public void Init(TilePropagator propagator) { tileSet = propagator.CreateTileSet(Tiles); graph = PathConstraintUtils.CreateGraph(propagator.Topology); }
public void Check(TilePropagator propagator) { var topology = propagator.Topology; var indices = topology.Width * topology.Height * topology.Depth; // TODO: This shouldn't be too hard to implement if (topology.Directions.Type != Topo.DirectionSetType.Cartesian2d) { throw new Exception("EdgedPathConstraint only supported for Cartesiant2d"); } var nodesPerIndex = topology.Directions.Count + 1; // Initialize couldBePath and mustBePath based on wave possibilities var couldBePath = new bool[indices * nodesPerIndex]; var mustBePath = new bool[indices * nodesPerIndex]; for (int i = 0; i < indices; i++) { topology.GetCoord(i, out var x, out var y, out var z); couldBePath[i * nodesPerIndex] = false; foreach (var kv in actualExits) { var tile = kv.Key; var exits = kv.Value; propagator.GetBannedSelected(x, y, z, tile, out var isBanned, out var isSelected); if (!isBanned) { couldBePath[i * nodesPerIndex] = true; foreach (var exit in exits) { couldBePath[i * nodesPerIndex + 1 + (int)exit] = true; } } } // TODO: There's probably a more efficient way to do this propagator.GetBannedSelected(x, y, z, pathTileSet, out var allIsBanned, out var allIsSelected); mustBePath[i * nodesPerIndex] = allIsSelected; } // Select relevant cells, i.e. those that must be connected. bool[] relevant; if (EndPoints == null && EndPointTiles == null) { relevant = mustBePath; } else { relevant = new bool[indices * nodesPerIndex]; var relevantCount = 0; if (EndPoints != null) { foreach (var endPoint in EndPoints) { var index = topology.GetIndex(endPoint.X, endPoint.Y, endPoint.Z); relevant[index * nodesPerIndex] = true; relevantCount++; } } if (EndPointTiles != null) { for (int i = 0; i < indices; i++) { topology.GetCoord(i, out var x, out var y, out var z); propagator.GetBannedSelected(x, y, z, endPointTileSet, out var isBanned, out var isSelected); if (isSelected) { relevant[i * nodesPerIndex] = true; relevantCount++; } } } if (relevantCount == 0) { // Nothing to do. return; } } var walkable = couldBePath; var component = EndPointTiles != null ? new bool[indices] : null; var isArticulation = PathConstraintUtils.GetArticulationPoints(graph, walkable, relevant, component); if (isArticulation == null) { propagator.SetContradiction(); return; } // All articulation points must be paths, // So ban any other possibilities for (var i = 0; i < indices; i++) { topology.GetCoord(i, out var x, out var y, out var z); if (isArticulation[i * nodesPerIndex]) { propagator.Select(x, y, z, pathTileSet); } for (var d = 0; d < topology.Directions.Count; d++) { if (isArticulation[i * nodesPerIndex + 1 + d]) { propagator.Select(x, y, z, tilesByExit[(Direction)d]); } } } // Any EndPointTiles not in the connected component aren't safe to add if (EndPointTiles != null) { for (int i = 0; i < indices; i++) { if (!component[i * nodesPerIndex]) { topology.GetCoord(i, out var x, out var y, out var z); propagator.Ban(x, y, z, endPointTileSet); } } } }