Exemple #1
0
        private void PlaceGatesAndTowers(IEnumerable <Vector2> allowedTowerPositions, int minNumberOfGates, int maxNumberOfGates, List <Vector2> illegalGatePositions)
        {
            var cityPatches    = _town.Patches.Where(p => p.WithinCity).ToList();
            var outsidePatches = _town.Patches.Except(cityPatches).ToList();
            var possibleGates  = allowedTowerPositions
                                 .Where(v => cityPatches.Count(cp => cp.Shape.Vertices.Contains(v)) > 1)
                                 .Except(illegalGatePositions)
                                 .OrderByDescending(v => (_town.Castle.Patch.Center - v).Length)
                                 .ToList();

            var towers = Circumference.ToList();
            var gates  = new List <Vector2>();

            var attempts = 0;

            while ((gates.Count < minNumberOfGates || attempts < 4) && possibleGates.Any() && gates.Count < maxNumberOfGates)
            {
                attempts++;
                var newGate = possibleGates.First();

                try
                {
                    possibleGates.Remove(newGate);
                    possibleGates.RemoveFirstIfPossible();
                    possibleGates.RemoveFirstIfPossible();

                    var outerNeighbours = outsidePatches
                                          .Where(p => p.Shape.Vertices.Any(v => v.Equals(newGate)))
                                          .ToList();

                    if (outerNeighbours.Count == 1)
                    {
                        var neighbour = outerNeighbours.Single();
                        var wallPoint = neighbour.Shape.GetNextVertex(newGate) -
                                        neighbour.Shape.GetPreviousVertex(newGate);
                        var outPoint            = new Vector2(wallPoint.y, -wallPoint.x);
                        var possibleSplitPoints = neighbour.Shape.Vertices.Except(Circumference).ToList();
                        var farthest            = possibleSplitPoints.OrderByDescending(p =>
                        {
                            var dir = p - newGate;
                            return(Vector2.Dot(dir, outPoint) / dir.Length);
                        }).First();

                        var newPatches = neighbour.Shape.Split(newGate, farthest).Select(p => Patch.FromPolygon(_town, p)).ToList();
                        if (newPatches.Any(p => p.Shape.Vertices.Count < 3))
                        {
                            farthest   = neighbour.Shape.GetNextVertex(farthest);
                            newPatches = neighbour.Shape.Split(newGate, farthest).Select(p => Patch.FromPolygon(_town, p)).ToList();
                            if (newPatches.Any(p => p.Shape.Vertices.Count < 3))
                            {
                                throw new InvalidOperationException(
                                          "Splitting patch resulted in polygon with only two points");
                            }
                        }
                        _town.Patches.Remove(neighbour);
                        _town.Patches.AddRange(newPatches);
                    }

                    gates.Add(newGate);
                    towers.Remove(newGate);
                }
                catch (InvalidOperationException)
                { }
            }

            _town.Gates.AddRange(gates);
            Gates.AddRange(gates);
            Towers.AddRange(towers);
        }