Ejemplo n.º 1
0
        /// <summary>
        /// Constructs a TilePropagator.
        /// </summary>
        /// <param name="tileModel">The model to guide the generation.</param>
        /// <param name="topology">The dimensions of the output to generate</param>
        /// <param name="backtrack">If true, store additional information to allow rolling back choices that lead to a contradiction.</param>
        /// <param name="constraints">Extra constraints to control the generation process.</param>
        /// <param name="random">Source of randomness</param>
        public TilePropagator(TileModel tileModel, Topology topology, bool backtrack = false,
                              ITileConstraint[] constraints = null,
                              Random random = null)
        {
            this.tileModel = tileModel;
            this.topology  = topology;

            var overlapping = tileModel as OverlappingModel;

            Topology patternTopology;

            if (!(topology.PeriodicX && topology.PeriodicY && topology.PeriodicZ) && overlapping != null)
            {
                // Shrink the topology as patterns can cover multiple tiles.
                patternTopology = topology.WithSize(
                    topology.PeriodicX ? topology.Width : topology.Width - overlapping.NX + 1,
                    topology.PeriodicY ? topology.Height : topology.Height - overlapping.NY + 1,
                    topology.PeriodicZ ? topology.Depth : topology.Depth - overlapping.NZ + 1);

                mappingType = MappingType.Overlapping;
                mappingNX   = overlapping.NX;
                mappingNY   = overlapping.NY;
                mappingNZ   = overlapping.NZ;

                // Compute tilesToPatterns and patternsToTiles
                var patternArrays = overlapping.PatternArrays;
                tilesToPatternsByOffset = new Dictionary <int, IReadOnlyDictionary <Tile, ISet <int> > >();
                patternsToTilesByOffset = new Dictionary <int, IReadOnlyDictionary <int, Tile> >();
                for (int ox = 0; ox < overlapping.NX; ox++)
                {
                    for (int oy = 0; oy < overlapping.NY; oy++)
                    {
                        for (int oz = 0; oz < overlapping.NZ; oz++)
                        {
                            var o = CombineOffsets(ox, oy, oz);
                            var tilesToPatterns = new Dictionary <Tile, ISet <int> >();
                            tilesToPatternsByOffset[o] = tilesToPatterns;
                            var patternsToTiles = new Dictionary <int, Tile>();
                            patternsToTilesByOffset[o] = patternsToTiles;
                            for (var pattern = 0; pattern < patternArrays.Count; pattern++)
                            {
                                var patternArray = patternArrays[pattern];
                                var tile         = patternArray.Values[ox, oy, oz];
                                patternsToTiles[pattern] = tile;
                                if (!tilesToPatterns.TryGetValue(tile, out var patternSet))
                                {
                                    patternSet = tilesToPatterns[tile] = new HashSet <int>();
                                }
                                patternSet.Add(pattern);
                            }
                        }
                    }
                }
            }
            else
            {
                patternTopology         = topology;
                mappingType             = MappingType.OneToOne;
                tilesToPatternsByOffset = new Dictionary <int, IReadOnlyDictionary <Tile, ISet <int> > >()
                {
                    { 0, tileModel.TilesToPatterns.ToDictionary(g => g.Key, g => (ISet <int>) new HashSet <int>(g)) }
                };
                patternsToTilesByOffset = new Dictionary <int, IReadOnlyDictionary <int, Tile> >
                {
                    { 0, tileModel.PatternsToTiles },
                };
            }

            // Masks interact a bit weirdly with the overlapping model
            // We choose a pattern mask that is a expansion of the topology mask
            // i.e. a pattern location is masked out if all the tile locations it covers is masked out.
            // This makes the propagator a bit conservative - it'll always preserve the overlapping property
            // but might ban some layouts that make sense.
            // The alternative is to contract the mask - that is more permissive, but sometimes will
            // violate the overlapping property.
            // (passing the mask verbatim is unacceptable as does not lead to symmetric behaviour)
            // See TestTileMaskWithThinOverlapping for an example of the problem, and
            // https://github.com/BorisTheBrave/DeBroglie/issues/7 for a possible solution.
            if (topology.Mask != null && overlapping != null)
            {
                // TODO: This could probably do with some cleanup
                bool GetTopologyMask(int x, int y, int z)
                {
                    if (!topology.PeriodicX && x >= topology.Width)
                    {
                        return(false);
                    }
                    if (!topology.PeriodicY && y >= topology.Height)
                    {
                        return(false);
                    }
                    if (!topology.PeriodicZ && z >= topology.Depth)
                    {
                        return(false);
                    }
                    x = x % topology.Width;
                    y = y % topology.Height;
                    z = z % topology.Depth;
                    return(topology.Mask[topology.GetIndex(x, y, z)]);
                }

                bool GetPatternTopologyMask(Point p)
                {
                    for (var oz = 0; oz < overlapping.NZ; oz++)
                    {
                        for (var oy = 0; oy < overlapping.NY; oy++)
                        {
                            for (var ox = 0; ox < overlapping.NX; ox++)
                            {
                                if (GetTopologyMask(p.X + ox, p.Y + oy, p.Z + oz))
                                {
                                    return(true);
                                }
                            }
                        }
                    }
                    return(false);
                }

                var patternMask = TopoArray.Create(GetPatternTopologyMask, patternTopology);
                patternTopology = patternTopology.WithMask(patternMask);
            }

            var waveConstraints =
                (constraints?.Select(x => new TileConstraintAdaptor(x, this)).ToArray() ?? Enumerable.Empty <IWaveConstraint>())
                .ToArray();

            this.wavePropagator = new WavePropagator(tileModel.GetPatternModel(), patternTopology, backtrack, waveConstraints, random, clear: false);
            wavePropagator.Clear();
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Constructs a TilePropagator.
        /// </summary>
        /// <param name="tileModel">The model to guide the generation.</param>
        /// <param name="topology">The dimensions of the output to generate</param>
        /// <param name="backtrack">If true, store additional information to allow rolling back choices that lead to a contradiction.</param>
        /// <param name="constraints">Extra constraints to control the generation process.</param>
        /// <param name="random">Source of randomness</param>
        public TilePropagator(TileModel tileModel, Topology topology, bool backtrack = false,
                              ITileConstraint[] constraints = null,
                              Random random = null)
        {
            this.tileModel = tileModel;
            this.topology  = topology;

            var patternTopology = topology;

            if (!(topology.PeriodicX && topology.PeriodicY && topology.PeriodicZ) && tileModel is OverlappingModel overlapping)
            {
                // Shrink the topology as patterns can cover multiple tiles.
                patternTopology = topology.WithSize(
                    topology.PeriodicX ? topology.Width : topology.Width - overlapping.NX + 1,
                    topology.PeriodicY ? topology.Height : topology.Height - overlapping.NY + 1,
                    topology.PeriodicZ ? topology.Depth : topology.Depth - overlapping.NZ + 1);

                mappingType = MappingType.Overlapping;
                mappingNX   = overlapping.NX;
                mappingNY   = overlapping.NY;
                mappingNZ   = overlapping.NZ;

                // Compute tilesToPatterns and patternsToTiles
                var patternArrays = overlapping.PatternArrays;
                tilesToPatternsByOffset = new Dictionary <int, IReadOnlyDictionary <Tile, ISet <int> > >();
                patternsToTilesByOffset = new Dictionary <int, IReadOnlyDictionary <int, Tile> >();
                for (int ox = 0; ox < overlapping.NX; ox++)
                {
                    for (int oy = 0; oy < overlapping.NY; oy++)
                    {
                        for (int oz = 0; oz < overlapping.NZ; oz++)
                        {
                            var o = CombineOffsets(ox, oy, oz);
                            var tilesToPatterns = new Dictionary <Tile, ISet <int> >();
                            tilesToPatternsByOffset[o] = tilesToPatterns;
                            var patternsToTiles = new Dictionary <int, Tile>();
                            patternsToTilesByOffset[o] = patternsToTiles;
                            for (var pattern = 0; pattern < patternArrays.Count; pattern++)
                            {
                                var patternArray = patternArrays[pattern];
                                var tile         = patternArray.Values[ox, oy, oz];
                                patternsToTiles[pattern] = tile;
                                if (!tilesToPatterns.TryGetValue(tile, out var patternSet))
                                {
                                    patternSet = tilesToPatterns[tile] = new HashSet <int>();
                                }
                                patternSet.Add(pattern);
                            }
                        }
                    }
                }
            }
            else
            {
                mappingType             = MappingType.OneToOne;
                tilesToPatternsByOffset = new Dictionary <int, IReadOnlyDictionary <Tile, ISet <int> > >()
                {
                    { 0, tileModel.TilesToPatterns.ToDictionary(g => g.Key, g => (ISet <int>) new HashSet <int>(g)) }
                };
                patternsToTilesByOffset = new Dictionary <int, IReadOnlyDictionary <int, Tile> >
                {
                    { 0, tileModel.PatternsToTiles },
                };
            }

            var waveConstraints =
                (constraints?.Select(x => new TileConstraintAdaptor(x, this)).ToArray() ?? Enumerable.Empty <IWaveConstraint>())
                .ToArray();

            this.wavePropagator = new WavePropagator(tileModel.GetPatternModel(), patternTopology, backtrack, waveConstraints, random, clear: false);
            wavePropagator.Clear();
        }