Esempio n. 1
0
        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);
                        }
                    }
                }
            }
        }
Esempio n. 2
0
        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);
                }
            }
        }
Esempio n. 3
0
        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;
                }
            }
        }
Esempio n. 4
0
        public void Check(TilePropagator propagator)
        {
            pathView.Update();

            var graph      = pathView.Graph;
            var mustBePath = pathView.MustBePath;
            // TODO: Support relevant?
            var visited = new bool[graph.NodeCount];

            for (var i = 0; i < graph.NodeCount; i++)
            {
                if (!mustBePath[i])
                {
                    continue;
                }
                if (visited[i])
                {
                    continue;
                }

                // Start DFS
                var stack = new Stack <(int, int)>();
                stack.Push((-1, i));
                while (stack.Count > 0)
                {
                    var(prev, u) = stack.Pop();
                    if (visited[u])
                    {
                        propagator.SetContradiction();
                        return;
                    }
                    visited[u] = true;
                    foreach (var v in graph.Neighbours[u])
                    {
                        if (!mustBePath[v])
                        {
                            continue;
                        }
                        if (v == prev)
                        {
                            continue;
                        }
                        stack.Push((u, v));
                    }
                }
            }
        }
        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);
                    }
                }
            }
        }
Esempio n. 6
0
        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);
                    }
                }
            }
        }
Esempio n. 7
0
        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;
                                }
                            }
                        }
                    }
                }
            }
        }
Esempio n. 8
0
        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();
                }
            }
        }
Esempio n. 9
0
        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);
                        }
                    }
                }
            }
        }
Esempio n. 11
0
        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);
                    }
                }
            }
        }
Esempio n. 12
0
        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);
                    }
                }
            }
        }
Esempio n. 13
0
        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);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Esempio n. 14
0
        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);
                    }
                }
            }
        }
Esempio n. 15
0
        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;
                                }
                            }
                        }
                    }
                }
            }
        }