public void Check(TilePropagator propagator) { if (nearbyTracker1.NewlyVisited.Count != 0) { var newlyVisited = nearbyTracker1.NewlyVisited; nearbyTracker1.NewlyVisited = new HashSet <int>(); foreach (var index in newlyVisited) { propagator.Topology.GetCoord(index, out var x, out var y, out var z); propagator.Ban(x, y, z, tileset2); } } if (nearbyTracker2.NewlyVisited.Count != 0) { var newlyVisited = nearbyTracker2.NewlyVisited; nearbyTracker2.NewlyVisited = new HashSet <int>(); foreach (var index in newlyVisited) { propagator.Topology.GetCoord(index, out var x, out var y, out var z); propagator.Ban(x, y, z, tileset1); } } }
public void TestBannedSelected() { var a = new int[, ] { { 1, 2, 3 }, { 3, 1, 2 }, { 2, 3, 1 }, }; var model = AdjacentModel.Create(a, true); var topology = new GridTopology(10, 10, false); var propagator = new TilePropagator(model, topology); var tile1 = new Tile(1); var set1 = propagator.CreateTileSet(new[] { new Tile(1) }); var set12 = propagator.CreateTileSet(new[] { new Tile(1), new Tile(2) }); { propagator.GetBannedSelected(0, 0, 0, tile1, out var isBanned1, out var isSelected1); propagator.GetBannedSelected(0, 0, 0, set1, out var isBanned2, out var isSelected2); propagator.GetBannedSelected(0, 0, 0, set12, out var isBanned3, out var isSelected3); Assert.AreEqual(false, isBanned1); Assert.AreEqual(false, isBanned2); Assert.AreEqual(false, isBanned3); Assert.AreEqual(false, isSelected1); Assert.AreEqual(false, isSelected2); Assert.AreEqual(false, isSelected3); } propagator.Ban(0, 0, 0, new Tile(3)); { propagator.GetBannedSelected(0, 0, 0, tile1, out var isBanned1, out var isSelected1); propagator.GetBannedSelected(0, 0, 0, set1, out var isBanned2, out var isSelected2); propagator.GetBannedSelected(0, 0, 0, set12, out var isBanned3, out var isSelected3); Assert.AreEqual(false, isBanned1); Assert.AreEqual(false, isBanned2); Assert.AreEqual(false, isBanned3); Assert.AreEqual(false, isSelected1); Assert.AreEqual(false, isSelected2); Assert.AreEqual(true, isSelected3); } propagator.Ban(0, 0, 0, new Tile(1)); { propagator.GetBannedSelected(0, 0, 0, tile1, out var isBanned1, out var isSelected1); propagator.GetBannedSelected(0, 0, 0, set1, out var isBanned2, out var isSelected2); propagator.GetBannedSelected(0, 0, 0, set12, out var isBanned3, out var isSelected3); Assert.AreEqual(true, isBanned1); Assert.AreEqual(true, isBanned2); Assert.AreEqual(false, isBanned3); Assert.AreEqual(false, isSelected1); Assert.AreEqual(false, isSelected2); Assert.AreEqual(true, isSelected3); } }
public void BanPath(int node) { var(index, dir) = Unpack(node, GetNodesPerIndex()); topology.GetCoord(index, out var x, out var y, out var z); if (dir == null) { propagator.Ban(x, y, z, pathTileSet); } else { if (tileSetByExit.TryGetValue((Direction)dir, out var exitTiles)) { propagator.Ban(x, y, z, exitTiles); } } }
public void Check(TilePropagator propagator) { var topology = propagator.Topology; var width = topology.Width; var height = topology.Height; var depth = topology.Depth; var yesCount = countTracker.YesCount; var noCount = countTracker.NoCount; var maybeCount = countTracker.MaybeCount; if (Comparison == CountComparison.AtMost || Comparison == CountComparison.Exactly) { if (yesCount > Count) { // Already got too many, just fail propagator.SetContradiction(); return; } if (yesCount == Count && maybeCount > 0) { // We've reached the limit, ban any more foreach (var index in topology.GetIndices()) { var selected = selectedChangeTracker.GetQuadstate(index); if (selected.IsMaybe()) { propagator.Topology.GetCoord(index, out var x, out var y, out var z); propagator.Ban(x, y, z, tileSet); } } } } if (Comparison == CountComparison.AtLeast || Comparison == CountComparison.Exactly) { if (yesCount + maybeCount < Count) { // Already got too few, just fail propagator.SetContradiction(); return; } if (yesCount + maybeCount == Count && maybeCount > 0) { // We've reached the limit, select all the rest foreach (var index in topology.GetIndices()) { var selected = selectedChangeTracker.GetQuadstate(index); if (selected.IsMaybe()) { propagator.Topology.GetCoord(index, out var x, out var y, out var z); propagator.Select(x, y, z, tileSet); } } } } }
public Resolution Init(TilePropagator propagator) { var width = propagator.Topology.Width; var height = propagator.Topology.Height; var depth = propagator.Topology.Depth; for (var x = 0; x < width; x++) { var xmin = x == 0; var xmax = x == width - 1; for (var y = 0; y < height; y++) { var ymin = y == 0; var ymax = y == height - 1; for (var z = 0; z < depth; z++) { var zmin = z == 0; var zmax = z == depth - 1; var match = (Match(Sides, xmin, xmax, ymin, ymax, zmin, zmax) && !Match(ExcludeSides, xmin, xmax, ymin, ymax, zmin, zmax)) != InvertArea; if (match) { if (Ban) { var cellStatus = propagator.Ban(x, y, z, Tile); if (cellStatus != Resolution.Undecided) { return(cellStatus); } } else { var cellStatus = propagator.Select(x, y, z, Tile); if (cellStatus != Resolution.Undecided) { return(cellStatus); } } } } } } return(Resolution.Undecided); }
public void Init(TilePropagator propagator) { var tiles = propagator.CreateTileSet(Tiles); var width = propagator.Topology.Width; var height = propagator.Topology.Height; var depth = propagator.Topology.Depth; for (var x = 0; x < width; x++) { var xmin = x == 0; var xmax = x == width - 1; for (var y = 0; y < height; y++) { var ymin = y == 0; var ymax = y == height - 1; for (var z = 0; z < depth; z++) { var zmin = z == 0; var zmax = z == depth - 1; var match = (Match(Sides, xmin, xmax, ymin, ymax, zmin, zmax) && !Match(ExcludeSides, xmin, xmax, ymin, ymax, zmin, zmax)) != InvertArea; if (match) { if (Ban) { propagator.Ban(x, y, z, tiles); } else { propagator.Select(x, y, z, tiles); } } } } } }
public void Check(TilePropagator propagator) { var topology = propagator.Topology; foreach (var i in topology.Indicies) { topology.GetCoord(i, out var x, out var y, out var z); var x2 = topology.Width - 1 - x; foreach (var tile in propagator.TileModel.Tiles) { if (TileRotation.Rotate(tile, reflectX, out var tile2)) { if (propagator.IsBanned(x, y, z, tile) && !propagator.IsBanned(x2, y, z, tile2)) { propagator.Ban(x2, y, z, tile2); } } } } }
public void Check(TilePropagator propagator) { var topology = propagator.Topology; foreach (var i in changeTracker.GetChangedIndices()) { if (TryMapIndex(propagator, i, out var i2)) { topology.GetCoord(i, out var x, out var y, out var z); topology.GetCoord(i2, out var x2, out var y2, out var z2); foreach (var tile in propagator.TileModel.Tiles) { if (TryMapTile(tile, out var tile2)) { if (propagator.IsBanned(x, y, z, tile) && !propagator.IsBanned(x2, y, z, tile2)) { propagator.Ban(x2, y, z, tile2); } } } } } }
public void Check(TilePropagator propagator) { var topology = propagator.Topology.AsGridTopology(); var width = topology.Width; var height = topology.Height; var depth = topology.Depth; if (Axes == null || Axes.Contains(Axis.X)) { int y = 0, z = 0; var sm = new StateMachine((x) => propagator.Ban(x, y, z, tileSet), topology.PeriodicX, width, MaxCount); for (z = 0; z < depth; z++) { for (y = 0; y < height; y++) { sm.Reset(); for (var x = 0; x < width; x++) { var index = topology.GetIndex(x, y, z); if (sm.Next(x, selectedTracker.GetQuadstate(index))) { propagator.SetContradiction("Max consecutive constraint failed on x-axis", this); return; } } if (topology.PeriodicX) { for (var x = 0; x < MaxCount && x < width; x++) { var index = topology.GetIndex(x, y, z); if (sm.Next(x, selectedTracker.GetQuadstate(index))) { propagator.SetContradiction("Max consecutive constraint failed on x-axis", this); return; } } } } } } // Same thing as XAxis, just swizzled if (Axes == null || Axes.Contains(Axis.Y)) { int x = 0, z = 0; var sm = new StateMachine((y) => propagator.Ban(x, y, z, tileSet), topology.PeriodicY, height, MaxCount); for (z = 0; z < depth; z++) { for (x = 0; x < width; x++) { sm.Reset(); for (var y = 0; y < height; y++) { var index = topology.GetIndex(x, y, z); if (sm.Next(y, selectedTracker.GetQuadstate(index))) { propagator.SetContradiction("Max consecutive constraint failed on y-axis", this); return; } } if (topology.PeriodicY) { for (var y = 0; y < MaxCount && y < height; y++) { var index = topology.GetIndex(x, y, z); if (sm.Next(y, selectedTracker.GetQuadstate(index))) { propagator.SetContradiction("Max consecutive constraint failed on y-axis", this); return; } } } } } } // Same thing as XAxis, just swizzled if (Axes == null || Axes.Contains(Axis.Z)) { int x = 0, y = 0; var sm = new StateMachine((z) => propagator.Ban(x, y, z, tileSet), topology.PeriodicZ, depth, MaxCount); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { sm.Reset(); for (var z = 0; z < depth; z++) { var index = topology.GetIndex(x, y, z); if (sm.Next(z, selectedTracker.GetQuadstate(index))) { propagator.SetContradiction("Max consecutive constraint failed on x-axis", this); return; } } if (topology.PeriodicZ) { for (var z = 0; z < MaxCount && z < depth; z++) { var index = topology.GetIndex(x, y, z); if (sm.Next(z, selectedTracker.GetQuadstate(index))) { propagator.SetContradiction("Max consecutive constraint failed on x-axis", this); return; } } } } } } }
public void Init(TilePropagator propagator) { tileSet = propagator.CreateTileSet(Tiles); countTracker = new CountTracker(propagator.Topology); selectedChangeTracker = propagator.CreateSelectedChangeTracker(tileSet, countTracker); if (Eager) { // Naive implementation /* * // Pick Count random indices * var topology = propagator.Topology; * var pickedIndices = new List<int>(); * var remainingIndices = new List<int>(topology.Indicies); * for (var c = 0; c < Count; c++) * { * var pickedIndexIndex = (int)(propagator.RandomDouble() * remainingIndices.Count); * pickedIndices.Add(remainingIndices[pickedIndexIndex]); * remainingIndices[pickedIndexIndex] = remainingIndices[remainingIndices.Count - 1]; * remainingIndices.RemoveAt(remainingIndices.Count - 1); * } * // Ban or select tiles to ensure an appropriate count * if(Comparison == CountComparison.AtMost || Comparison == CountComparison.Exactly) * { * foreach (var i in remainingIndices) * { * topology.GetCoord(i, out var x, out var y, out var z); * propagator.Ban(x, y, z, tileSet); * } * } * if (Comparison == CountComparison.AtLeast || Comparison == CountComparison.Exactly) * { * foreach (var i in pickedIndices) * { * topology.GetCoord(i, out var x, out var y, out var z); * propagator.Select(x, y, z, tileSet); * } * } */ var topology = propagator.Topology; var width = topology.Width; var height = topology.Height; var depth = topology.Depth; var pickedIndices = new List <int>(); var remainingIndices = new List <int>(topology.GetIndices()); while (true) { var noCount = 0; var yesCount = 0; var maybeList = new List <int>(); for (var z = 0; z < depth; z++) { for (var y = 0; y < height; y++) { for (var x = 0; x < width; x++) { var index = topology.GetIndex(x, y, z); if (topology.ContainsIndex(index)) { var selected = selectedChangeTracker.GetQuadstate(index); if (selected.IsNo()) { noCount++; } if (selected.IsMaybe()) { maybeList.Add(index); } if (selected.IsYes()) { yesCount++; } } } } } var maybeCount = maybeList.Count; if (Comparison == CountComparison.AtMost) { if (yesCount > Count) { // Already got too many, just fail propagator.SetContradiction(); return; } if (yesCount == Count) { // We've reached the limit, ban any more and exit Check(propagator); return; } var pickedIndex = maybeList[(int)(propagator.RandomDouble() * maybeList.Count)]; topology.GetCoord(pickedIndex, out var x, out var y, out var z); propagator.Select(x, y, z, tileSet); } else if (Comparison == CountComparison.AtLeast || Comparison == CountComparison.Exactly) { if (yesCount + maybeCount < Count) { // Already got too few, just fail propagator.SetContradiction(); return; } if (yesCount + maybeCount == Count) { // We've reached the limit, ban any more and exit Check(propagator); return; } var pickedIndex = maybeList[(int)(propagator.RandomDouble() * maybeList.Count)]; topology.GetCoord(pickedIndex, out var x, out var y, out var z); propagator.Ban(x, y, z, tileSet); } } } }
public void Check(TilePropagator propagator) { var topology = propagator.Topology; var width = topology.Width; var height = topology.Height; var depth = topology.Depth; if (Axes == null || Axes.Contains(Axis.X)) { int y = 0, z = 0; var sm = new StateMachine((x) => propagator.Ban(x, y, z, tileSet), propagator.Topology.PeriodicX, width, MaxCount); for (z = 0; z < depth; z++) { for (y = 0; y < height; y++) { sm.Reset(); for (var x = 0; x < width; x++) { propagator.GetBannedSelected(x, y, z, tileSet, out var isBanned, out var isSelected); if (sm.Next(x, isBanned, isSelected)) { propagator.SetContradiction(); return; } } if (propagator.Topology.PeriodicX) { for (var x = 0; x < MaxCount && x < width; x++) { propagator.GetBannedSelected(x, y, z, tileSet, out var isBanned, out var isSelected); if (sm.Next(x, isBanned, isSelected)) { propagator.SetContradiction(); return; } } } } } } // Same thing as XAxis, just swizzled if (Axes == null || Axes.Contains(Axis.Y)) { int x = 0, z = 0; var sm = new StateMachine((y) => propagator.Ban(x, y, z, tileSet), propagator.Topology.PeriodicY, height, MaxCount); for (z = 0; z < depth; z++) { for (x = 0; x < width; x++) { sm.Reset(); for (var y = 0; y < height; y++) { propagator.GetBannedSelected(x, y, z, tileSet, out var isBanned, out var isSelected); if (sm.Next(y, isBanned, isSelected)) { propagator.SetContradiction(); return; } } if (propagator.Topology.PeriodicY) { for (var y = 0; y < MaxCount && y < height; y++) { propagator.GetBannedSelected(x, y, z, tileSet, out var isBanned, out var isSelected); if (sm.Next(y, isBanned, isSelected)) { propagator.SetContradiction(); return; } } } } } } // Same thing as XAxis, just swizzled if (Axes == null || Axes.Contains(Axis.Z)) { int x = 0, y = 0; var sm = new StateMachine((z) => propagator.Ban(x, y, z, tileSet), propagator.Topology.PeriodicZ, depth, MaxCount); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { sm.Reset(); for (var z = 0; z < depth; z++) { propagator.GetBannedSelected(x, y, z, tileSet, out var isBanned, out var isSelected); if (sm.Next(z, isBanned, isSelected)) { propagator.SetContradiction(); return; } } if (propagator.Topology.PeriodicZ) { for (var z = 0; z < MaxCount && z < depth; z++) { propagator.GetBannedSelected(x, y, z, tileSet, out var isBanned, out var isSelected); if (sm.Next(z, isBanned, isSelected)) { propagator.SetContradiction(); return; } } } } } } }
public void VisitIndex(int index, bool[] visited) { if (visited[index]) { return; } var visitedList = new List <int>(); var parityCount = 0; (int, Direction?)? amigLocation = null; var hasMultipleAmbiguous = false; var stack = new Stack <int>(); stack.Push(index); while (stack.Count > 0) { var i = stack.Pop(); if (visited[i]) { continue; } visited[i] = true; visitedList.Add(i); var isOdd = oddPathTracker?.GetQuadstate(i) ?? Quadstate.No; // Does this tile have undefined parity in number of exits if (isOdd.IsMaybe()) { // Ambiguous if (amigLocation != null) { hasMultipleAmbiguous = true; } else { amigLocation = (i, null); } } if (isOdd.IsYes()) { parityCount++; } for (var d = 0; d < topology.DirectionsCount; d++) { var direction = (Direction)d; var qs = pathView.TrackerByExit.TryGetValue(direction, out var tracker) ? tracker.GetQuadstate(i) : Quadstate.No; if (qs.IsYes()) { parityCount++; } if (qs.IsMaybe()) { if (topology.TryMove(i, direction, out var i2)) { // Need to include this cell in the region if (!visited[i2]) { stack.Push(i2); } } else { // If there's no corresponding tile to balance this one // then this exit is free to be path or not, altering parity if (amigLocation != null) { hasMultipleAmbiguous = true; } else { amigLocation = (i, direction); } } } } } // We've now fully explored this region if (hasMultipleAmbiguous) { // There's nothing we can say about this case. return; } if (amigLocation != null) { // There's exactly one ambiguous point, so set it to ensure even parity var(ambigIndex, ambigDirection) = amigLocation.Value; topology.GetCoord(ambigIndex, out var x, out var y, out var z); if (ambigDirection == null) { if (parityCount % 2 == 0) { propagator.Ban(x, y, z, oddPathTilesSet); } else { propagator.Select(x, y, z, oddPathTilesSet); } } else { if (parityCount % 2 == 0) { propagator.Ban(x, y, z, pathView.TileSetByExit[ambigDirection.Value]); } else { propagator.Select(x, y, z, pathView.TileSetByExit[ambigDirection.Value]); } } } else { if (parityCount % 2 == 0) { // This is fine } else { // This is not fine, and there's nothing ambiguous to patch things up propagator.SetContradiction(); } } }
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 Resolution 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, PathTiles, 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(Resolution.Undecided); } 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(topology, walkable, relevant); if (isArticulation == null) { return(Resolution.Contradiction); } // All articulation points must be paths, // So ban any other possibilities for (var i = 0; i < indices; i++) { if (!isArticulation[i]) { continue; } foreach (var tile in propagator.TileModel.TilesToPatterns.Select(x => x.Key)) { if (PathTiles.Contains(tile)) { continue; } topology.GetCoord(i, out var x, out var y, out var z); propagator.Ban(x, y, z, tile); } } return(Resolution.Undecided); }
public void BanPath(int index) { propagator.Topology.GetCoord(index, out var x, out var y, out var z); propagator.Ban(x, y, z, tileSet); }
public void Check(TilePropagator propagator) { var topology = propagator.Topology; var width = topology.Width; var height = topology.Height; var depth = topology.Depth; var noCount = 0; var yesCount = 0; var maybeCount = 0; for (var z = 0; z < depth; z++) { for (var y = 0; y < height; y++) { for (var x = 0; x < width; x++) { var index = topology.GetIndex(x, y, z); if (topology.ContainsIndex(index)) { var selected = propagator.GetSelectedTristate(x, y, z, tileSet); if (selected.IsNo) { noCount++; } if (selected.IsMaybe) { maybeCount++; } if (selected.IsYes) { yesCount++; } } } } } if (Comparison == CountComparison.AtMost || Comparison == CountComparison.Exactly) { if (yesCount > Count) { // Already got too many, just fail propagator.SetContradiction(); return; } if (yesCount == Count && maybeCount > 0) { // We've reached the limit, ban any more for (var z = 0; z < depth; z++) { for (var y = 0; y < height; y++) { for (var x = 0; x < width; x++) { var index = topology.GetIndex(x, y, z); if (topology.ContainsIndex(index)) { var selected = propagator.GetSelectedTristate(x, y, z, tileSet); if (selected.IsMaybe) { propagator.Ban(x, y, z, tileSet); } } } } } } } if (Comparison == CountComparison.AtLeast || Comparison == CountComparison.Exactly) { if (yesCount + maybeCount < Count) { // Already got too few, just fail propagator.SetContradiction(); return; } if (yesCount + maybeCount == Count && maybeCount > 0) { // We've reached the limit, select all the rest for (var z = 0; z < depth; z++) { for (var y = 0; y < height; y++) { for (var x = 0; x < width; x++) { var index = topology.GetIndex(x, y, z); if (topology.ContainsIndex(index)) { var selected = propagator.GetSelectedTristate(x, y, z, tileSet); if (selected.IsMaybe) { propagator.Select(x, y, z, tileSet); } } } } } } } }
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); } } } }