/
romashov.z
/
PPAGame
Обзор
Документация
Войти
/
romashov.z
/
PPAGame
Код
Запросы
1
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
Core/Army.cs
167 строк
7 KB
Zakhar Romashov
Добавлен функционал для Демо 3
26 апр 2026, 18:46
26 апр 2026, 18:46
5bd1cee
Код
Авторство
О чём код?
using System; using System.Collections.Generic; using System.Linq; namespace ArmyBattleGame { // Армия хранится как 2D-сетка: Grid[row][col]; null = пустой слот. // Узкий мост = 1 колонка, широкий мост = 3 колонки, стенка = N колонок × 1 ряд. // Конкретное число колонок задаёт IFormationStrategy через RebuildFromFlat. class Army { public List<IUnit?[]> Grid { get; } = new List<IUnit?[]>(); public int ColumnCount { get; private set; } = 1; public int RowCount => Grid.Count; // Срабатывает каждый раз, когда в армии появляется новый юнит // (например, при создании клона магом). Используется наблюдателями // для автоматической подписки на новые события. public event Action<IUnit>? UnitAdded; // Внутренний триггер события - используется стратегиями при размещении клона // через RebuildFromFlat (которая сама не уведомляет, чтобы не дублировать // событие при перепостроении армии). public void NotifyUnitAdded(IUnit unit) => UnitAdded?.Invoke(unit); public bool HasAliveUnits => AllUnits.Any(u => u.IsAlive); // Все живые и мёртвые юниты в плоском порядке (по строкам, слева направо). public IEnumerable<IUnit> AllUnits { get { foreach (var row in Grid) foreach (var u in row) if (u != null) yield return u; } } // Все живые юниты — для удобства итерации. public IEnumerable<IUnit> AliveUnits => AllUnits.Where(u => u.IsAlive); // Совместимость с прежним API: плоский список живых юнитов. // Read-only — изменять армию через AddUnit/SetAt. public IReadOnlyList<IUnit> Units => AliveUnits.ToList(); public IUnit? GetAt(int row, int col) { if (row < 0 || row >= Grid.Count) return null; if (col < 0 || col >= ColumnCount) return null; return Grid[row][col]; } public void SetAt(int row, int col, IUnit? unit) { EnsureRow(row); Grid[row][col] = unit; if (unit != null) UnitAdded?.Invoke(unit); } // Передний живой юнит в указанной колонке (наименьший row, в котором живой). public IUnit? GetFront(int col) { for (int r = 0; r < Grid.Count; r++) { var u = Grid[r][col]; if (u != null && u.IsAlive) return u; } return null; } // Позиция переднего живого юнита в колонке (или -1 если такого нет). public int GetFrontRow(int col) { for (int r = 0; r < Grid.Count; r++) { var u = Grid[r][col]; if (u != null && u.IsAlive) return r; } return -1; } // Позиция юнита в сетке. Возвращает (-1,-1) если не найден. public UnitPosition? FindPosition(IUnit unit) { for (int r = 0; r < Grid.Count; r++) for (int c = 0; c < ColumnCount; c++) if (ReferenceEquals(Grid[r][c], unit)) return new UnitPosition(r, c); return null; } // Добавить юнита в первую свободную позицию (по строкам, слева направо). // Используется при первоначальной сборке армии. public void AddUnit(IUnit unit) { for (int r = 0; r < Grid.Count; r++) { for (int c = 0; c < ColumnCount; c++) { if (Grid[r][c] == null) { Grid[r][c] = unit; UnitAdded?.Invoke(unit); return; } } } int newRow = Grid.Count; EnsureRow(newRow); Grid[newRow][0] = unit; UnitAdded?.Invoke(unit); } // Плоский список всех живых юнитов (по строкам, слева направо). // Используется при перепостроении и сохранении. public List<IUnit> Flatten() => AliveUnits.ToList(); // Перестроить армию из плоского списка под заданное число колонок. // Раскладывает units[i] в позицию [i / cols][i % cols]. public void RebuildFromFlat(IList<IUnit> units, int columnCount) { if (columnCount < 1) throw new ArgumentOutOfRangeException(nameof(columnCount)); Grid.Clear(); ColumnCount = columnCount; for (int i = 0; i < units.Count; i++) { int row = i / columnCount; int col = i % columnCount; EnsureRow(row); Grid[row][col] = units[i]; } } // Удалить мёртвых и схлопнуть пустоты: эквивалентно Flatten + RebuildFromFlat. // Гарантирует: первый ряд максимально заполнен, дыры допустимы только снизу-справа. public void Compact() { var alive = Flatten(); RebuildFromFlat(alive, ColumnCount); } // Удалить мёртвых, не схлопывая (на случай, если стратегия хочет // увидеть состояние "до Compact"). Сейчас не используется напрямую, // оставлено для будущей гибкости. public void RemoveDead() { for (int r = 0; r < Grid.Count; r++) for (int c = 0; c < ColumnCount; c++) if (Grid[r][c] != null && !Grid[r][c]!.IsAlive) Grid[r][c] = null; } private void EnsureRow(int row) { while (Grid.Count <= row) Grid.Add(new IUnit?[ColumnCount]); } } }