private int DetermineMaxSubtreeLeftShift(BuildingBuilder building, int maxShift)
        {
            if (maxShift == 0)
            {
                return(0);
            }

            // first, see how far left this building can go
            int dist = DetermineAvailableLeftShift(building, maxShift);

            // then, see how far left its leftmost child can go
            BuildingBuilder leftChild = GetBuildings(building.Unlocks)
                                        .OrderBy(child => child.DisplayColumn)
                                        .FirstOrDefault();

            if (leftChild == null)
            {
                return(dist);
            }

            if (dist == 0)
            {
                return(0);
            }

            // return which of the above two is the smallest
            return(Math.Min(dist, DetermineMaxSubtreeLeftShift(leftChild, dist)));
        }
 private void SetRowRecursive(int row, BuildingBuilder building)
 {
     building.DisplayRow = row;
     foreach (var child in GetBuildings(building.Unlocks))
     {
         SetRowRecursive(row + 1, child);
     }
 }
        private void ShiftSubtreeLeft(BuildingBuilder building, int distance)
        {
            building.DisplayColumn -= distance;

            foreach (var childBuilding in GetBuildings(building.Unlocks))
            {
                ShiftSubtreeLeft(childBuilding, distance);
            }
        }
Example #4
0
        private BuildingBuilder GenerateTechBuilding(uint identifier)
        {
            var building = new BuildingBuilder(Random, identifier, AllocateBuildingSymbol(), BuildingRole.Research);

            building.AllocateName(UsedNames);
            building.VisionRange = BuildingVisionRange;

            // TODO: populate this?

            return(building);
        }
Example #5
0
        private BuildingBuilder GenerateResourceBuilding(uint identifier, ResourceType resource, bool isPrimary)
        {
            var building = new BuildingBuilder(Random, identifier, AllocateBuildingSymbol(), BuildingRole.Resource);

            building.AllocateName(UsedNames);
            building.VisionRange = BuildingVisionRange;

            // TODO: populate this

            return(building);
        }
        private bool CanBuildingMove(BuildingBuilder building, int targetShift, HashSet <BuildingBuilder> movers)
        {
            int targetColumn = building.DisplayColumn - targetShift;

            if (targetColumn < 1)
            {
                return(false);
            }

            var existing = CheckForBuilding(building.DisplayRow, targetColumn);

            return(existing == null || movers.Contains(existing));
        }
        private int DetermineJumpLeftShift(BuildingBuilder building)
        {
            var allSiblings = Buildings.Values
                              .Where(test => test.Prerequisite == building.Prerequisite)
                              .ToArray();
            var minSibling = allSiblings.Min(sibling => sibling.DisplayColumn);
            var maxSibling = allSiblings.Max(sibling => sibling.DisplayColumn);

            // Find the first free space for this building, then check its descendants.
            var movers = new HashSet <BuildingBuilder> {
                building
            };
            int targetShift = 0;

            while (true)
            {
                if (CanBuildingMove(building, ++targetShift, movers))
                {
                    break;
                }
                else if (building.DisplayColumn - targetShift <= 1)
                {
                    return(0);
                }
            }

            if ((building.DisplayColumn - targetShift) < (minSibling - 1))
            {
                return(0);
            }

            if (building.Prerequisite.HasValue)
            {
                var prerequisite = Buildings[building.Prerequisite.Value];
                int parentCol    = prerequisite.DisplayColumn;

                // Don't let the rightmost sibling end up left of the parent
                if (building.DisplayColumn == maxSibling && (building.DisplayColumn - targetShift) < parentCol)
                {
                    return(0);
                }
            }

            return(CanChildrenCanMove(building, targetShift, movers)
                ? targetShift
                : 0);
        }
        private int DetermineAvailableLeftShift(BuildingBuilder building, int maxShift)
        {
            int dist = 0;

            do
            {
                var collision = CheckForBuilding(building.DisplayRow, building.DisplayColumn - dist - 1);
                if (collision != null)
                {
                    break;
                }

                dist++;
            } while (dist < maxShift);

            return(dist);
        }
Example #9
0
        private void GenerateTechBuildings(IEnumerable <uint> factoryIDs)
        {
            foreach (var factoryID in factoryIDs)
            {
                var factory = Buildings[factoryID];

                uint?prevPrerequisite = null;
                bool first            = true;

                foreach (var unitID in factory.Builds)
                {
                    if (!Units.TryGetValue(unitID, out var unit))
                    {
                        continue;
                    }

                    // TODO: have each unit save the ID of its correponding tech building

                    if (first)
                    {// the first unit type built by a building never has any prerequisites ... doesn't mean it can't have upgrades in its own building or the next one, though.
                        first = false;
                        continue;
                    }

                    // give this unit type a 1 in 3 chance of sharing a prerequisite with its predecessor
                    if (prevPrerequisite.HasValue && Random.Next(3) == 0)
                    {
                        AddUnlock(prevPrerequisite.Value, unitID, unit);
                        continue;
                    }

                    // generate a new tech building to be this unit type's prerequisite
                    uint            identifier   = nextIdentifier++;
                    BuildingBuilder techBuilding = GenerateTechBuilding(identifier);
                    Buildings.Add(identifier, techBuilding);

                    prevPrerequisite = identifier;
                    AddUnlock(identifier, unitID, unit);

                    // insert that into the tech tree somewhere in the factory's subtree
                    AddToSubtree(factoryID, identifier, techBuilding);
                }
            }
        }
        private bool CanChildrenCanMove(BuildingBuilder building, int targetShift, HashSet <BuildingBuilder> movers)
        {
            var childBuildings = GetBuildings(building.Unlocks)
                                 .OrderByDescending(b => b.DisplayColumn);

            foreach (var childBuilding in childBuildings)
            {
                if (!CanBuildingMove(childBuilding, targetShift, movers))
                {
                    return(false);
                }

                movers.Add(childBuilding);

                if (!CanChildrenCanMove(childBuilding, targetShift, movers))
                {
                    return(false);
                }
            }

            return(true);
        }
Example #11
0
        private void AddToSubtree(uint rootID, uint newDescendentID, BuildingBuilder newDescendent)
        {
            BuildingBuilder root = Buildings[rootID];

            var childrenIDs = OnlyBuildings(root.Unlocks).ToArray();
            int numChildren = childrenIDs.Length;

            // Sometimes we get a really boring tree, that's just A -> B -> C -> D -> E -> F -> G -> H (etc) with no branching.
            // Instead of generating a subtree like that, if the "ancestor chain" is too long, insert further up the tree, instead.
            int chainLengthWithNoSiblings = numChildren == 0 ? 1 : 0;

            if (chainLengthWithNoSiblings > 0)
            {
                var checkID = root.Prerequisite;

                while (checkID.HasValue)
                {
                    var check = Buildings[checkID.Value];

                    if (OnlyBuildings(check.Unlocks).Count() == 1)
                    {
                        chainLengthWithNoSiblings++;
                    }
                    else
                    {
                        break;
                    }

                    checkID = check.Prerequisite;
                }

                if (chainLengthWithNoSiblings > 2)
                {
                    // Insert further up the tree instead, and then return.
                    int stepsUp = Random.Next(1, chainLengthWithNoSiblings + 1);

                    for (int i = 0; i < stepsUp; i++)
                    {
                        if (!root.Prerequisite.HasValue)
                        {
                            break;
                        }

                        rootID = root.Prerequisite.Value;
                        root   = Buildings[rootID];
                    }

                    AddUnlock(rootID, newDescendentID, newDescendent);
                    return;
                }
            }

            // The more children a node has, the less likely it is to just have this child added directly to it.
            // For a node with 1 child, the chances of "falling on" to the next row are 1/3. For one with 2, it's 2/4, for one with 3, it's 3/5,for one with 4, it's 4/6, etc.
            if (numChildren == 0 || Random.Next(numChildren + 2) >= numChildren)
            {
                AddUnlock(rootID, newDescendentID, newDescendent);
                return;
            }

            // Choose a building type that is unlocked by this one.
            var childID = childrenIDs[Random.Next(numChildren)];

            if (Random.Next(3) == 0)
            {// On a 1/3 chance, insert as a prerequisite of this other child building.
                BuildingBuilder child = Buildings[childID];
                AddUnlock(newDescendentID, childID, child);
                AddUnlock(rootID, newDescendentID, newDescendent);
            }
            else
            {// otherwise, add as a descendent of this other building
                AddToSubtree(childID, newDescendentID, newDescendent);
            }
        }