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); } }
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); }
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); }
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); }
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); } }