public void DisplayEnclosedArea(EnclosedArea enclosedArea) { ClearInspectorWindow(); currentDisplay = InspectorText.Area; inspectorWindowTitle.text = $"Enclosure {enclosedArea.id + 1}"; // THe composition is a list of float value in the order of the AtmoshpereComponent Enum float[] terrainComposition = enclosedArea.terrainComposition; string displayText = ""; // Atmospheric info //displayText += "Atmospheric composition: \n"; //foreach (var (value, index) in atmosphericComposition.WithIndex()) //{ // displayText += $"{((AtmosphereComponent)index).ToString()} : {value}\n"; //} foreach (var(value, index) in terrainComposition.WithIndex()) { if (value == 0) { continue; } displayText += $"{((TileType)index).ToString()} : {value}\n"; } //displayText += "\n"; //displayText += $"Population count: {enclosedArea.populations.Count}\n"; //displayText += $"Total animal count: {enclosedArea.animals.Count}\n"; //displayText += $"Food Source count: {enclosedArea.foodSources.Count}\n"; this.inspectorWindowText.text = displayText; }
public override string ToString() { StringBuilder lStringBuilder = new StringBuilder(); lStringBuilder.AppendLine(".." + Defender.ToString2() + " Color Enclosed Region #" + _RegionNbr + " At: " + Board.Coord.ToString(Members[0].MemberList[0])); lStringBuilder.Append("....Members Block: (" + Members.Count + ") "); foreach (GoBlockBase lGoBlockBase in Members) { lStringBuilder.Append(Board.Coord.ToString(lGoBlockBase.Members.GetFirst()) + " "); } lStringBuilder.AppendLine(); lStringBuilder.Append("....Neighbors Blocks: (" + Neighbors.Count + ") "); foreach (GoBlockBase lGoBlockBase in Neighbors) { lStringBuilder.Append(Board.Coord.ToString(lGoBlockBase.Members.GetFirst()) + " "); } lStringBuilder.AppendLine(); lStringBuilder.Append("....Enclosing Blocks: (" + EnclosingBlocks.Count + ") "); foreach (GoBlockBase lGoBlock in EnclosingBlocks) { lStringBuilder.Append(Board.Coord.ToString(lGoBlock.Members.GetFirst()) + " "); } lStringBuilder.AppendLine(); lStringBuilder.Append("....Interior Defender Blocks: (" + InteriorDefenderBlocks.Count + ") "); foreach (GoBlockBase lGoBlock in InteriorDefenderBlocks) { lStringBuilder.Append(Board.Coord.ToString(lGoBlock.Members.GetFirst()) + " "); } lStringBuilder.AppendLine(); lStringBuilder.Append("....Interior Attacker Blocks: (" + InteriorAttackerBlocks.Count + ") "); foreach (GoBlockBase lGoBlock in InteriorAttackerBlocks) { lStringBuilder.Append(Board.Coord.ToString(lGoBlock.Members.GetFirst()) + " "); } lStringBuilder.AppendLine(); lStringBuilder.AppendLine("....Is Small Enclosed: " + IsSmall.ToString()); // lStringBuilder.AppendLine("....Total Empty Region: "); // lStringBuilder.AppendLine(TotalEmptyRegion.ToString()); lStringBuilder.AppendLine("....Is 1-Vital: " + Is1Vital.ToString()); lStringBuilder.AppendLine("....Is 2-Vital: " + Is2Vital.ToString()); lStringBuilder.AppendLine("....Has Interior: " + (EmptyArea.HasInterior() ? "Yes" : "No")); // lStringBuilder.Append("Accessible Liberties:\n" + AccessibleLiberties.ToString()); lStringBuilder.Append("Empty Area:\n" + EmptyArea.ToString()); lStringBuilder.Append("Attackers Eye Area:\n" + AttackersEyeArea.ToString()); lStringBuilder.Append("Enclosed Region:\n" + EnclosedArea.ToString()); return(lStringBuilder.ToString().TrimEnd('\n')); }
/// <summary> /// Call this to update all the enclosed areas and create an EnclosedArea data structure to hold its information. /// </summary> /// <remarks> /// This is using a flood fill (https://en.wikipedia.org/wiki/Flood_fill) to find enclosed areas. /// Assumptions: the reserve is bordered by walls /// NOTE: this assumption does not hold up for some reserves, such as Level2E2 and Level2E3 /// </remarks> public void UpdateEnclosedAreas(bool isUpdate = true) { // non-wall tiles HashSet <Vector3Int> accessed = new HashSet <Vector3Int>(); // wall or null tiles HashSet <Vector3Int> unaccessible = new HashSet <Vector3Int>(); // walls Stack <Vector3Int> walls = new Stack <Vector3Int>(); List <EnclosedArea> newEnclosedAreas = new List <EnclosedArea>(); // Initial flood fill this.enclosedAreaCount = 0; EnclosedArea area = new EnclosedArea(this.enclosedAreaCount); newEnclosedAreas.Add(area); // If startingPositions is empty on start, startingPositions will contain gridSystem.startTile by default. foreach (var startingPos in startingPositions) { if (area.coordinates.Count > 0) { this.enclosedAreaCount++; area = new EnclosedArea(this.enclosedAreaCount); newEnclosedAreas.Add(area); } this.FloodFill(startingPos, accessed, unaccessible, walls, enclosedAreaCount, area, isUpdate); Vector3Int curPos = startingPos; while (walls.Count > 0) { if (area.coordinates.Count != 0) { this.enclosedAreaCount++; area = new EnclosedArea(this.enclosedAreaCount); newEnclosedAreas.Add(area); } curPos = walls.Pop(); this.FloodFill(curPos + Vector3Int.left, accessed, unaccessible, walls, this.enclosedAreaCount, area, isUpdate); this.FloodFill(curPos + Vector3Int.up, accessed, unaccessible, walls, this.enclosedAreaCount, area, isUpdate); this.FloodFill(curPos + Vector3Int.right, accessed, unaccessible, walls, this.enclosedAreaCount, area, isUpdate); this.FloodFill(curPos + Vector3Int.down, accessed, unaccessible, walls, this.enclosedAreaCount, area, isUpdate); } } // Not initializing: update the areas based on the previous ones if (isUpdate) { } this.internalEnclosedAreas = newEnclosedAreas; this.UpdatePublicEnclosedAreas(); }
private void logAtmoesphereChange(EnclosedArea enclosedArea) { LogEntry newLog = new LogEntry(Math.Round(Time.time, 0, MidpointRounding.AwayFromZero).ToString(), $"Atmospheric composition changed at enclose area {enclosedArea.id}!"); if (!this.enclosedAreaLogs.ContainsKey(enclosedArea)) { this.enclosedAreaLogs.Add(enclosedArea, new List<LogEntry>()); } this.enclosedAreaLogs[enclosedArea].Add(newLog); this.worldLog.Add(newLog); }
private void logNewCreation(object creation) { if (creation.GetType() == typeof(Population)) { Population population = (Population)creation; if (!this.populationLogs.ContainsKey(population)) { this.populationLogs.Add(population, new List<LogEntry>()); } LogEntry newLog = new LogEntry(Math.Round(Time.time, 0, MidpointRounding.AwayFromZero).ToString(), $"New {population.species.SpeciesName} created!"); this.populationLogs[population].Add(newLog); this.worldLog.Add(newLog); } else if (creation.GetType() == typeof(FoodSource)) { FoodSource foodSource = (FoodSource)creation; if (!this.foodSourceLogs.ContainsKey(foodSource)) { this.foodSourceLogs.Add(foodSource, new List<LogEntry>()); } LogEntry newLog = new LogEntry(Math.Round(Time.time, 0, MidpointRounding.AwayFromZero).ToString(), $"New {foodSource.Species.SpeciesName} created!"); this.foodSourceLogs[foodSource].Add(newLog); this.worldLog.Add(newLog); } else if (creation.GetType() == typeof(EnclosedArea)) { EnclosedArea enclosedArea = (EnclosedArea)creation; // Don't log empty enclosed area if (enclosedArea.coordinates.Count == 0) { return; } if (!this.enclosedAreaLogs.ContainsKey(enclosedArea)) { this.enclosedAreaLogs.Add(enclosedArea, new List<LogEntry>()); } LogEntry newLog = new LogEntry(Math.Round(Time.time, 0, MidpointRounding.AwayFromZero).ToString(), $"Enclosed area {enclosedArea.id} created"); this.enclosedAreaLogs[enclosedArea].Add(newLog); this.worldLog.Add(newLog); } }
private void logLiquidChange(Vector3Int cellPos) { enclosureSystem.UpdateEnclosedAreas(); EnclosedArea enclosedArea = this.enclosureSystem.GetEnclosedAreaByCellPosition(cellPos); if (!this.enclosedAreaLogs.ContainsKey(enclosedArea)) { this.enclosedAreaLogs.Add(enclosedArea, new List<LogEntry>()); } LogEntry newLog = new LogEntry(Math.Round(Time.time, 0, MidpointRounding.AwayFromZero).ToString(), $"Liquid composition changed at enclose area {enclosedArea.id}!"); this.enclosedAreaLogs[enclosedArea].Add(newLog); this.worldLog.Add(newLog); }
public void AddCoordinate(Coordinate coordinate, int tileType, EnclosedArea prevArea = null) { if (GameManager.Instance.m_tileDataController.IsCellinGrid(coordinate.x, coordinate.y)) { TileData tileData = GameManager.Instance.m_tileDataController.GetTileData(new UnityEngine.Vector3Int(coordinate.x, coordinate.y, 0)); this.coordinates.Add(coordinate); if (tileData.Animal) { this.animals.Add(tileData.Animal.GetComponent <Animal>()); Population population = tileData.Animal.GetComponent <Animal>().PopulationInfo; if (!this.populations.Contains(population)) { this.populations.Add(population); } } if (tileData.Food) { this.foodSources.Add(tileData.Food.GetComponent <FoodSource>()); } // TODO: If an enclosure is not contained entirely within walls (IE if any tile touches an empty space), then set this.isEnclosed to false // NOTE: This code works, but will fail if the level is not entirely surrounded by walls and is not square-shaped if (tileType != (int)TileType.Wall && GameManager.Instance.m_tileDataController.IsCellOnGridEdge(coordinate.x, coordinate.y)) { isEnclosed = false; } } this.terrainComposition[tileType]++; if (prevArea != null) { if (previousArea.ContainsKey(prevArea.id)) { previousArea[prevArea.id]++; } else { previousArea.Add(prevArea.id, 1); } } }
private void logTerrainChange(List<Vector3Int> changedTiles) { List<byte> seenEnclosedAreaIds = new List<byte>(); foreach (Vector3Int pos in changedTiles) { EnclosedArea enclosedArea = this.enclosureSystem.GetEnclosedAreaByCellPosition(pos); if (!seenEnclosedAreaIds.Contains(enclosedArea.id)) { if (!this.enclosedAreaLogs.ContainsKey(enclosedArea)) { this.enclosedAreaLogs.Add(enclosedArea, new List<LogEntry>()); } LogEntry newLog = new LogEntry(Math.Round(Time.time, 0, MidpointRounding.AwayFromZero).ToString(), $"Terrain changed in enclosed area {enclosedArea.id}"); this.enclosedAreaLogs[enclosedArea].Add(newLog); this.worldLog.Add(newLog); seenEnclosedAreaIds.Add(enclosedArea.id); } } }
/// <summary> /// Recursive flood fill. /// </summary> /// <param name="cur">Start location</param> /// <param name="accessed">Accessed cells</param> /// <param name="unaccessible">Unaccessible cells</param> /// <param name="walls">wall cells</param> /// <param name="atmosphereCount">index of the enclosed area</param> private void FloodFill(Vector3Int start, HashSet <Vector3Int> accessed, HashSet <Vector3Int> unaccessible, Stack <Vector3Int> walls, byte atmosphereCount, EnclosedArea enclosedArea, bool isUpdate) { if (accessed.Contains(start) || unaccessible.Contains(start)) { // checked before, move on return; } // Using iterative approach due to stack overflow with large maps Stack <Vector3Int> stack = new Stack <Vector3Int>(); stack.Push(start); Vector3Int cur; while (stack.Count > 0) { cur = stack.Pop(); if (accessed.Contains(cur) || unaccessible.Contains(cur)) { // checked before, move on continue; } // check if tilemap has tile GameTile tile = GameManager.Instance.m_tileDataController.GetGameTileAt(cur); if (tile != null) { if (tile.type != TileType.Wall) { // Mark the cell accessed.Add(cur); // Updating enclosed area if (isUpdate && this.positionToEnclosedArea.ContainsKey(cur) && this.GetEnclosedAreaById(this.positionToEnclosedArea[cur]) != null) { // Add the tile and tell the enclosed area what the previous area is enclosedArea.AddCoordinate(new EnclosedArea.Coordinate(cur.x, cur.y), (int)tile.type, this.GetEnclosedAreaById(this.positionToEnclosedArea[cur])); } // Initial round else { enclosedArea.AddCoordinate(new EnclosedArea.Coordinate(cur.x, cur.y), (int)tile.type, null); } this.positionToEnclosedArea[cur] = atmosphereCount; stack.Push(cur + Vector3Int.left); stack.Push(cur + Vector3Int.up); stack.Push(cur + Vector3Int.right); stack.Push(cur + Vector3Int.down); } else { walls.Push(cur); unaccessible.Add(cur); } } else { unaccessible.Add(cur); } } }