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);
            }
        }
Example #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);
                }
            }
        }
        public Point GetRandomPoint(TilePropagator propagator, TilePropagatorTileSet tileSet)
        {
            var topology = propagator.Topology;

            var points = new List <Point>();

            for (var z = 0; z < topology.Depth; z++)
            {
                for (var y = 0; y < topology.Height; y++)
                {
                    for (var x = 0; x < topology.Width; x++)
                    {
                        if (topology.Mask != null)
                        {
                            var index = topology.GetIndex(x, y, z);
                            if (!topology.Mask[index])
                            {
                                continue;
                            }
                        }

                        propagator.GetBannedSelected(x, y, z, tileSet, out var isBanned, out var _);
                        if (isBanned)
                        {
                            continue;
                        }

                        points.Add(new Point(x, y, z));
                    }
                }
            }

            // Choose a random point to select
            if (points.Count == 0)
            {
                throw new System.Exception($"No legal placement of {tileSet}");
            }

            var i = (int)(propagator.RandomDouble() * points.Count);

            return(points[i]);
        }
Example #4
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;
                                }
                            }
                        }
                    }
                }
            }
        }
        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);
                    }
                }
            }
        }