예제 #1
0
        public override void Apply(Skeleton skeleton, float lastTime, float time, ExposedList <Event> events, float alpha)
        {
            float[] array = this.frames;
            if (time < array[0])
            {
                return;
            }
            PathConstraint pathConstraint = skeleton.pathConstraints.Items[this.pathConstraintIndex];

            if (time >= array[array.Length - 3])
            {
                int num = array.Length;
                pathConstraint.rotateMix    += (array[num + -2] - pathConstraint.rotateMix) * alpha;
                pathConstraint.translateMix += (array[num + -1] - pathConstraint.translateMix) * alpha;
                return;
            }
            int   num2         = Animation.binarySearch(array, time, 3);
            float num3         = array[num2 + -2];
            float num4         = array[num2 + -1];
            float num5         = array[num2];
            float curvePercent = base.GetCurvePercent(num2 / 3 - 1, 1f - (time - num5) / (array[num2 + -3] - num5));

            pathConstraint.rotateMix    += (num3 + (array[num2 + 1] - num3) * curvePercent - pathConstraint.rotateMix) * alpha;
            pathConstraint.translateMix += (num4 + (array[num2 + 2] - num4) * curvePercent - pathConstraint.translateMix) * alpha;
        }
예제 #2
0
        private IConstraint ConvertJsonToConstraint(JObject jObject)
        {
            if (jObject["and"] != null)
            {
                var andConstraint = new AndConstraint();
                foreach (var item in jObject["and"])
                {
                    andConstraint.Add(ConvertJsonToConstraint((item as JObject)));
                }

                return(andConstraint);
            }
            if (jObject["or"] != null)
            {
                var orConstraint = new OrConstraint();
                foreach (var item in jObject["or"])
                {
                    orConstraint.Add(ConvertJsonToConstraint((item as JObject)));
                }

                return(orConstraint);
            }
            if (jObject["equals"] != null)
            {
                var equalsConstraint = new EqualsConstraint();

                equalsConstraint.Property     = jObject["equals"][0]["doc"]?.ToString();
                equalsConstraint.ValueToEqual = jObject["equals"][1]?.ToString();

                return(equalsConstraint);
            }
            if (jObject["in"] != null)
            {
                var inConstraint = new InConstraint();

                inConstraint.Property      = jObject["in"][0]["doc"]?.ToString();
                inConstraint.ValuesToEqual = jObject["in"][1]?.ToObject <string[]>();

                return(inConstraint);
            }
            if (jObject["paths"] != null)
            {
                var pathsConstraint = new PathConstraint();

                pathsConstraint.Fields = jObject["paths"][0]["doc"]?.ToString();

                return(pathsConstraint);
            }
            if (jObject["not"] != null)
            {
                var notConstraint = new NotConstraint();

                notConstraint.ConstraintToInvert = ConvertJsonToConstraint(jObject["not"] as JObject);

                return(notConstraint);
            }

            return(null);
        }
		public void Ctor_SerializationInfo_Success()
		{
			PathConstraint c = new PathConstraint();
			System.IO.MemoryStream Buffer = SerializationHelper.Serialize(c);
			PathConstraint c2 = SerializationHelper.Deserialize<PathConstraint>(Buffer);

			Assert.AreEqual(Constraint.PathConstraintName, c2.Name);
		}
예제 #4
0
        private static FileRule ParseFileRuleNode(XmlNode ruleNode)
        {
            if (ruleNode == null)
            {
                throw new ArgumentNullException("ruleNode");
            }
            if (ruleNode.Name != "file")
            {
                throw new ArgumentException("ruleNode is not file node");
            }

            var constraints     = new List <IConstraint>();
            var constraintsNode = ruleNode.SelectSingleNode("constraints");

            if (constraintsNode != null)
            {
                foreach (XmlNode constraintNode in constraintsNode.ChildNodes)
                {
                    if (constraintNode.NodeType != XmlNodeType.Element)
                    {
                        continue;
                    }

                    IConstraint constraint = null;
                    switch (constraintNode.Name)
                    {
                    case "param":
                        constraint = new ParamConstraint(constraintNode.Attributes["key"].Value, constraintNode.Attributes["pattern"].Value);
                        break;

                    case "path":
                        constraint = new PathConstraint(constraintNode.Attributes["pattern"].Value);
                        break;
                    }
                    if (constraint != null)
                    {
                        constraints.Add(constraint);
                    }
                }
            }

            IEnumerable <ITask> tasks = null;
            var taskNodes             = ruleNode.SelectSingleNode("tasks");

            if (taskNodes != null)
            {
                tasks = ParseChildren(taskNodes);
            }

            string title = string.Empty;

            if (ruleNode.Attributes != null && ruleNode.Attributes["title"] != null)
            {
                title = ruleNode.Attributes["title"].Value;
            }

            return(new FileRule(title, tasks, constraints));
        }
예제 #5
0
        public override void Apply(Skeleton skeleton, float lastTime, float time, ExposedList <Event> firedEvents, float alpha, MixPose pose, MixDirection direction)
        {
            PathConstraint pathConstraint = skeleton.pathConstraints.Items[pathConstraintIndex];

            float[] array = frames;
            if (time < array[0])
            {
                switch (pose)
                {
                case MixPose.Setup:
                    pathConstraint.rotateMix    = pathConstraint.data.rotateMix;
                    pathConstraint.translateMix = pathConstraint.data.translateMix;
                    break;

                case MixPose.Current:
                    pathConstraint.rotateMix    += (pathConstraint.data.rotateMix - pathConstraint.rotateMix) * alpha;
                    pathConstraint.translateMix += (pathConstraint.data.translateMix - pathConstraint.translateMix) * alpha;
                    break;
                }
                return;
            }
            float num;
            float num2;

            if (time >= array[array.Length - 3])
            {
                num  = array[array.Length + -2];
                num2 = array[array.Length + -1];
            }
            else
            {
                int num3 = Animation.BinarySearch(array, time, 3);
                num  = array[num3 + -2];
                num2 = array[num3 + -1];
                float num4         = array[num3];
                float curvePercent = GetCurvePercent(num3 / 3 - 1, 1f - (time - num4) / (array[num3 + -3] - num4));
                num  += (array[num3 + 1] - num) * curvePercent;
                num2 += (array[num3 + 2] - num2) * curvePercent;
            }
            if (pose == MixPose.Setup)
            {
                pathConstraint.rotateMix    = pathConstraint.data.rotateMix + (num - pathConstraint.data.rotateMix) * alpha;
                pathConstraint.translateMix = pathConstraint.data.translateMix + (num2 - pathConstraint.data.translateMix) * alpha;
            }
            else
            {
                pathConstraint.rotateMix    += (num - pathConstraint.rotateMix) * alpha;
                pathConstraint.translateMix += (num2 - pathConstraint.translateMix) * alpha;
            }
        }
예제 #6
0
        public override void Apply(Skeleton skeleton, float lastTime, float time, ExposedList <Event> firedEvents, float alpha, MixPose pose, MixDirection direction)
        {
            PathConstraint pathConstraint = skeleton.pathConstraints.Items[pathConstraintIndex];

            float[] frames = base.frames;
            if (time < frames[0])
            {
                switch (pose)
                {
                case MixPose.Setup:
                    pathConstraint.spacing = pathConstraint.data.spacing;
                    break;

                case MixPose.Current:
                    pathConstraint.spacing += (pathConstraint.data.spacing - pathConstraint.spacing) * alpha;
                    break;
                }
                return;
            }
            float num;

            if (time >= frames[frames.Length - 2])
            {
                num = frames[frames.Length + -1];
            }
            else
            {
                int num2 = Animation.BinarySearch(frames, time, 2);
                num = frames[num2 + -1];
                float num3         = frames[num2];
                float curvePercent = GetCurvePercent(num2 / 2 - 1, 1f - (time - num3) / (frames[num2 + -2] - num3));
                num += (frames[num2 + 1] - num) * curvePercent;
            }
            if (pose == MixPose.Setup)
            {
                pathConstraint.spacing = pathConstraint.data.spacing + (num - pathConstraint.data.spacing) * alpha;
            }
            else
            {
                pathConstraint.spacing += (num - pathConstraint.spacing) * alpha;
            }
        }
예제 #7
0
        public void PathSetup()
        {
            var tileCount = 10;
            var topology  = new GridTopology(20, 20, false);

            var model = new AdjacentModel(DirectionSet.Cartesian2d);

            var tiles = Enumerable.Range(0, tileCount).Select(x => new Tile(x)).ToList();;

            model.AddAdjacency(tiles, tiles, Direction.XPlus);
            model.AddAdjacency(tiles, tiles, Direction.YPlus);

            model.SetUniformFrequency();
            var pathConstraint = new PathConstraint(tiles.Skip(1).ToHashSet());

            propagator5 = new TilePropagator(model, topology, new TilePropagatorOptions
            {
                BackTrackDepth = -1,
                Constraints    = new[] { pathConstraint },
            });
        }
        public override void Apply(Skeleton skeleton, float lastTime, float time, ExposedList <Event> events, float alpha)
        {
            float[] frames = this.frames;
            if (time < frames[0])
            {
                return;
            }
            PathConstraint pathConstraint = skeleton.pathConstraints.Items[this.pathConstraintIndex];

            if (time >= frames[frames.Length - 2])
            {
                int num = frames.Length;
                pathConstraint.spacing += (frames[num + -1] - pathConstraint.spacing) * alpha;
                return;
            }
            int   num2         = Animation.binarySearch(frames, time, 2);
            float num3         = frames[num2 + -1];
            float num4         = frames[num2];
            float curvePercent = base.GetCurvePercent(num2 / 2 - 1, 1f - (time - num4) / (frames[num2 + -2] - num4));

            pathConstraint.spacing += (num3 + (frames[num2 + 1] - num3) * curvePercent - pathConstraint.spacing) * alpha;
        }
예제 #9
0
        public void PathSetup()
        {
            var tileCount = 10;
            var topology  = new GridTopology(20, 20, false);

            var model = new AdjacentModel(DirectionSet.Cartesian2d);

            var tiles = Enumerable.Range(0, tileCount).Select(x => new Tile(x)).ToList();;

            model.AddAdjacency(tiles, tiles, Direction.XPlus);
            model.AddAdjacency(tiles, tiles, Direction.YPlus);

            model.SetUniformFrequency();
#pragma warning disable CS0618 // Type or member is obsolete
            var pathConstraint = new PathConstraint(tiles.Skip(1).ToHashSet());
#pragma warning restore CS0618 // Type or member is obsolete

            propagatorPath = new TilePropagator(model, topology, new TilePropagatorOptions
            {
                BacktrackType = BacktrackType.Backtrack,
                Constraints   = new[] { pathConstraint },
            });
        }
예제 #10
0
 public void Write(TProtocol oprot)
 {
     oprot.IncrementRecursionDepth();
     try
     {
         TStruct struc = new TStruct("MConstraint");
         oprot.WriteStructBegin(struc);
         TField field = new TField();
         if (ID == null)
         {
             throw new TProtocolException(TProtocolException.INVALID_DATA, "required field ID not set");
         }
         field.Name = "ID";
         field.Type = TType.String;
         field.ID   = 1;
         oprot.WriteFieldBegin(field);
         oprot.WriteString(ID);
         oprot.WriteFieldEnd();
         if (GeometryConstraint != null && __isset.GeometryConstraint)
         {
             field.Name = "GeometryConstraint";
             field.Type = TType.Struct;
             field.ID   = 2;
             oprot.WriteFieldBegin(field);
             GeometryConstraint.Write(oprot);
             oprot.WriteFieldEnd();
         }
         if (VelocityConstraint != null && __isset.VelocityConstraint)
         {
             field.Name = "VelocityConstraint";
             field.Type = TType.Struct;
             field.ID   = 3;
             oprot.WriteFieldBegin(field);
             VelocityConstraint.Write(oprot);
             oprot.WriteFieldEnd();
         }
         if (AccelerationConstraint != null && __isset.AccelerationConstraint)
         {
             field.Name = "AccelerationConstraint";
             field.Type = TType.Struct;
             field.ID   = 4;
             oprot.WriteFieldBegin(field);
             AccelerationConstraint.Write(oprot);
             oprot.WriteFieldEnd();
         }
         if (PathConstraint != null && __isset.PathConstraint)
         {
             field.Name = "PathConstraint";
             field.Type = TType.Struct;
             field.ID   = 5;
             oprot.WriteFieldBegin(field);
             PathConstraint.Write(oprot);
             oprot.WriteFieldEnd();
         }
         if (JointPathConstraint != null && __isset.JointPathConstraint)
         {
             field.Name = "JointPathConstraint";
             field.Type = TType.Struct;
             field.ID   = 6;
             oprot.WriteFieldBegin(field);
             JointPathConstraint.Write(oprot);
             oprot.WriteFieldEnd();
         }
         if (PostureConstraint != null && __isset.PostureConstraint)
         {
             field.Name = "PostureConstraint";
             field.Type = TType.Struct;
             field.ID   = 7;
             oprot.WriteFieldBegin(field);
             PostureConstraint.Write(oprot);
             oprot.WriteFieldEnd();
         }
         if (JointConstraint != null && __isset.JointConstraint)
         {
             field.Name = "JointConstraint";
             field.Type = TType.Struct;
             field.ID   = 8;
             oprot.WriteFieldBegin(field);
             JointConstraint.Write(oprot);
             oprot.WriteFieldEnd();
         }
         if (Properties != null && __isset.Properties)
         {
             field.Name = "Properties";
             field.Type = TType.Map;
             field.ID   = 9;
             oprot.WriteFieldBegin(field);
             {
                 oprot.WriteMapBegin(new TMap(TType.String, TType.String, Properties.Count));
                 foreach (string _iter4 in Properties.Keys)
                 {
                     oprot.WriteString(_iter4);
                     oprot.WriteString(Properties[_iter4]);
                 }
                 oprot.WriteMapEnd();
             }
             oprot.WriteFieldEnd();
         }
         oprot.WriteFieldStop();
         oprot.WriteStructEnd();
     }
     finally
     {
         oprot.DecrementRecursionDepth();
     }
 }
예제 #11
0
        public List <ITileConstraint> GetConstraints(DirectionSet directions, TileRotation tileRotation)
        {
            var is3d = directions.Type == DirectionSetType.Cartesian3d;

            var constraints = new List <ITileConstraint>();

            if (Config.Ground != null)
            {
                var groundTile = Parse(Config.Ground);
                constraints.Add(new BorderConstraint
                {
                    Sides = is3d ? BorderSides.ZMin : BorderSides.YMax,
                    Tiles = new[] { groundTile },
                });
                constraints.Add(new BorderConstraint
                {
                    Sides      = is3d ? BorderSides.ZMin : BorderSides.YMax,
                    Tiles      = new[] { groundTile },
                    InvertArea = true,
                    Ban        = true,
                });
            }

            if (Config.Constraints != null)
            {
                foreach (var constraint in Config.Constraints)
                {
                    if (constraint is PathConfig pathData)
                    {
                        var tiles = new HashSet <Tile>(pathData.Tiles.Select(Parse));
                        var p     = new PathConstraint(tiles, pathData.EndPoints);
                        constraints.Add(p);
                    }
                    else if (constraint is EdgedPathConfig edgedPathData)
                    {
                        var exits = edgedPathData.Exits.ToDictionary(
                            kv => Parse(kv.Key), x => (ISet <Direction>) new HashSet <Direction>(x.Value.Select(ParseDirection)));
                        var p = new EdgedPathConstraint(exits, edgedPathData.EndPoints, tileRotation);
                        constraints.Add(p);
                    }
                    else if (constraint is BorderConfig borderData)
                    {
                        var tiles        = borderData.Tiles.Select(Parse).ToArray();
                        var sides        = borderData.Sides == null ? BorderSides.All : (BorderSides)Enum.Parse(typeof(BorderSides), borderData.Sides, true);
                        var excludeSides = borderData.ExcludeSides == null ? BorderSides.None : (BorderSides)Enum.Parse(typeof(BorderSides), borderData.ExcludeSides, true);
                        if (!is3d)
                        {
                            sides        = sides & ~BorderSides.ZMin & ~BorderSides.ZMax;
                            excludeSides = excludeSides & ~BorderSides.ZMin & ~BorderSides.ZMax;
                        }
                        constraints.Add(new BorderConstraint
                        {
                            Tiles        = tiles,
                            Sides        = sides,
                            ExcludeSides = excludeSides,
                            InvertArea   = borderData.InvertArea,
                            Ban          = borderData.Ban,
                        });
                    }
                    else if (constraint is FixedTileConfig fixedTileConfig)
                    {
                        constraints.Add(new FixedTileConstraint
                        {
                            Tiles = fixedTileConfig.Tiles.Select(Parse).ToArray(),
                            Point = fixedTileConfig.Point,
                        });
                    }
                    else if (constraint is MaxConsecutiveConfig maxConsecutiveConfig)
                    {
                        var axes = maxConsecutiveConfig.Axes?.Select(ParseAxis);
                        constraints.Add(new MaxConsecutiveConstraint
                        {
                            Tiles    = new HashSet <Tile>(maxConsecutiveConfig.Tiles.Select(Parse)),
                            MaxCount = maxConsecutiveConfig.MaxCount,
                            Axes     = axes == null ? null : new HashSet <Axis>(axes),
                        });
                    }
                    else if (constraint is MirrorConfig mirrorConfig)
                    {
                        constraints.Add(new MirrorConstraint
                        {
                            TileRotation = tileRotation,
                        });
                    }
                    else
                    {
                        throw new NotImplementedException($"Unknown constraint type {constraint.GetType()}");
                    }
                }
            }

            return(constraints);
        }
		public void Validate_Relative2_Success()
		{
			PathConstraint c = new PathConstraint();
			IEnumerable<ParameterValidationResult> res = c.Validate("Documents\\MyPath.txt", ParameterDataType.String, Constants.MemberName);
			Assert.IsNotNull(res);
			Assert.IsFalse(res.GetEnumerator().MoveNext());
		}
		public void Ctor_Void_Success()
		{
			PathConstraint c = new PathConstraint();
			Assert.AreEqual(Constraint.PathConstraintName, c.Name);
		}
		public void Validate_Whitespace_Success()
		{
			PathConstraint c = new PathConstraint();
			IEnumerable<ParameterValidationResult> res = c.Validate("   ", ParameterDataType.String, Constants.MemberName);
			Assert.IsNotNull(res);
			Assert.IsTrue(res.GetEnumerator().MoveNext());
		}
예제 #15
0
        private List <ITileConstraint> GetConstraints(bool is3d)
        {
            var constraints = new List <ITileConstraint>();

            if (config.Ground != null)
            {
                var groundTile = Parse(config.Ground);
                constraints.Add(new BorderConstraint
                {
                    Sides = is3d ? BorderSides.ZMin : BorderSides.YMax,
                    Tile  = groundTile,
                });
                constraints.Add(new BorderConstraint
                {
                    Sides      = is3d ? BorderSides.ZMin : BorderSides.YMax,
                    Tile       = groundTile,
                    InvertArea = true,
                    Ban        = true,
                });
            }

            if (config.Constraints != null)
            {
                foreach (var constraint in config.Constraints)
                {
                    if (constraint is PathConfig pathData)
                    {
                        var pathTiles = new HashSet <Tile>(pathData.PathTiles.Select(Parse));
                        var p         = new PathConstraint(pathTiles);
                        constraints.Add(p);
                    }
                    else if (constraint is BorderConfig borderData)
                    {
                        var tile         = Parse(borderData.Tile);
                        var sides        = borderData.Sides == null ? BorderSides.All : (BorderSides)Enum.Parse(typeof(BorderSides), borderData.Sides, true);
                        var excludeSides = borderData.ExcludeSides == null ? BorderSides.None : (BorderSides)Enum.Parse(typeof(BorderSides), borderData.ExcludeSides, true);
                        if (!is3d)
                        {
                            sides        = sides & ~BorderSides.ZMin & ~BorderSides.ZMax;
                            excludeSides = excludeSides & ~BorderSides.ZMin & ~BorderSides.ZMax;
                        }
                        constraints.Add(new BorderConstraint
                        {
                            Tile         = tile,
                            Sides        = sides,
                            ExcludeSides = excludeSides,
                            InvertArea   = borderData.InvertArea,
                            Ban          = borderData.Ban,
                        });
                    }
                    else if (constraint is FixedTileConfig fixedTileConfig)
                    {
                        constraints.Add(new FixedTileConstraint
                        {
                            Tile  = Parse(fixedTileConfig.Tile),
                            Point = fixedTileConfig.Point,
                        });
                    }
                }
            }

            return(constraints);
        }
예제 #16
0
        public List <ITileConstraint> GetConstraints(DirectionSet directions, TileRotation tileRotation)
        {
            var is3d = directions.Type == DirectionSetType.Cartesian3d;

            var constraints = new List <ITileConstraint>();

            if (Config.Ground != null)
            {
                var groundTile = Parse(Config.Ground);
                constraints.Add(new BorderConstraint
                {
                    Sides = is3d ? BorderSides.ZMin : BorderSides.YMax,
                    Tiles = new[] { groundTile },
                });
                constraints.Add(new BorderConstraint
                {
                    Sides      = is3d ? BorderSides.ZMin : BorderSides.YMax,
                    Tiles      = new[] { groundTile },
                    InvertArea = true,
                    Ban        = true,
                });
            }

            if (Config.Constraints != null)
            {
                foreach (var constraint in Config.Constraints)
                {
                    if (constraint is PathConfig pathData)
                    {
                        var tiles = new HashSet <Tile>(pathData.Tiles.Select(Parse));
#pragma warning disable CS0618 // Type or member is obsolete
                        var p = new PathConstraint(tiles, pathData.EndPoints, tileRotation)
#pragma warning restore CS0618 // Type or member is obsolete
                        {
                            EndPointTiles = pathData.EndPointTiles == null ? null : new HashSet <Tile>(pathData.EndPointTiles.Select(Parse))
                        };
                        constraints.Add(p);
                    }
                    else if (constraint is EdgedPathConfig edgedPathData)
                    {
                        var exits = edgedPathData.Exits.ToDictionary(
                            kv => Parse(kv.Key), x => (ISet <Direction>) new HashSet <Direction>(x.Value.Select(ParseDirection)));
#pragma warning disable CS0618 // Type or member is obsolete
                        var p = new EdgedPathConstraint(exits, edgedPathData.EndPoints, tileRotation)
#pragma warning restore CS0618 // Type or member is obsolete
                        {
                            EndPointTiles = edgedPathData.EndPointTiles == null ? null : new HashSet <Tile>(edgedPathData.EndPointTiles.Select(Parse))
                        };
                        constraints.Add(p);
                    }
                    else if (constraint is BorderConfig borderData)
                    {
                        var tiles        = borderData.Tiles.Select(Parse).ToArray();
                        var sides        = borderData.Sides == null ? BorderSides.All : (BorderSides)Enum.Parse(typeof(BorderSides), borderData.Sides, true);
                        var excludeSides = borderData.ExcludeSides == null ? BorderSides.None : (BorderSides)Enum.Parse(typeof(BorderSides), borderData.ExcludeSides, true);
                        if (!is3d)
                        {
                            sides        = sides & ~BorderSides.ZMin & ~BorderSides.ZMax;
                            excludeSides = excludeSides & ~BorderSides.ZMin & ~BorderSides.ZMax;
                        }
                        constraints.Add(new BorderConstraint
                        {
                            Tiles        = tiles,
                            Sides        = sides,
                            ExcludeSides = excludeSides,
                            InvertArea   = borderData.InvertArea,
                            Ban          = borderData.Ban,
                        });
                    }
                    else if (constraint is FixedTileConfig fixedTileConfig)
                    {
                        constraints.Add(new FixedTileConstraint
                        {
                            Tiles = fixedTileConfig.Tiles.Select(Parse).ToArray(),
                            Point = fixedTileConfig.Point,
                        });
                    }
                    else if (constraint is MaxConsecutiveConfig maxConsecutiveConfig)
                    {
                        var axes = maxConsecutiveConfig.Axes?.Select(ParseAxis);
                        constraints.Add(new MaxConsecutiveConstraint
                        {
                            Tiles    = new HashSet <Tile>(maxConsecutiveConfig.Tiles.Select(Parse)),
                            MaxCount = maxConsecutiveConfig.MaxCount,
                            Axes     = axes == null ? null : new HashSet <Axis>(axes),
                        });
                    }
                    else if (constraint is MirrorXConfig mirrorYConfig)
                    {
                        constraints.Add(new MirrorXConstraint
                        {
                            TileRotation = tileRotation,
                        });
                    }
                    else if (constraint is MirrorYConfig mirrorXConfig)
                    {
                        constraints.Add(new MirrorYConstraint
                        {
                            TileRotation = tileRotation,
                        });
                    }
                    else if (constraint is CountConfig countConfig)
                    {
                        constraints.Add(new CountConstraint
                        {
                            Tiles      = new HashSet <Tile>(countConfig.Tiles.Select(Parse)),
                            Comparison = countConfig.Comparison,
                            Count      = countConfig.Count,
                            Eager      = countConfig.Eager,
                        });
                    }
                    else if (constraint is SeparationConfig separationConfig)
                    {
                        constraints.Add(new SeparationConstraint
                        {
                            Tiles       = new HashSet <Tile>(separationConfig.Tiles.Select(Parse)),
                            MinDistance = separationConfig.MinDistance,
                        });
                    }
                    else if (constraint is ConnectedConfig connectedConfig)
                    {
                        constraints.Add(new ConnectedConstraint
                        {
                            PathSpec = GetPathSpec(connectedConfig.PathSpec),
                        });
                    }
                    else if (constraint is LoopConfig loopConfig)
                    {
                        constraints.Add(new LoopConstraint
                        {
                            PathSpec = GetPathSpec(loopConfig.PathSpec),
                        });
                    }
                    else if (constraint is AcyclicConfig acyclicConfig)
                    {
                        constraints.Add(new AcyclicConstraint
                        {
                            PathSpec = GetPathSpec(acyclicConfig.PathSpec),
                        });
                    }
                    else
                    {
                        throw new NotImplementedException($"Unknown constraint type {constraint.GetType()}");
                    }
                }
            }

            return(constraints);
        }
		public void ToString_Success()
		{
			PathConstraint c = new PathConstraint();
			Assert.AreEqual("[Path]", c.ToString());
		}