using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Runtime.Remoting.Messaging; using Assets.Scripts.Utils; using UnityEngine; namespace Assets.Scripts.MapGeneration { internal class DefaultCellDelegates { public static bool DefaultCanGrow(Cell cell) { return true; } public static bool DefaultWillGrow(Cell cell) { return true; } } public class CellularAutomaton { #region Delegates public delegate IEnumerable<Cell> Filter(Map map); public delegate bool CanGrow(Cell cell); public delegate bool WillGrow(Cell cell); public delegate Cell Picktarget(Map map, Cell origin); #endregion #region Fields private Map _map; private List<Cell> _toProcess; public CanGrow CanGrowRule; public WillGrow WillGrowRule; public Picktarget PickTargetRule; private TileType _targetType; #endregion #region Ctors public CellularAutomaton(Map map, TileType targetType, uint startX = 0, uint startY = 0) { _map = map; _targetType = targetType; CanGrowRule = DefaultCellDelegates.DefaultCanGrow; WillGrowRule = DefaultCellDelegates.DefaultWillGrow; _toProcess = new List<Cell> {new Cell(startX, startY, targetType)}; _map[startX, startY] = targetType; ApplyToMap(_toProcess); } #endregion #region Methods public void Step(float max) { if (!_toProcess.Any()) return; var newCells = new List<Cell>(); foreach (var cell in _toProcess) { if (!NeedToCompute(cell, max)) { newCells.Add(cell); continue; } foreach (var target in GetNeighbors(_map, cell)) { if (!CanGrowRule(target) || !WillGrowRule(target)) continue; Grow(target, _targetType); newCells.Add(target); } } ApplyToMap(newCells); _toProcess = newCells; } private bool NeedToCompute(Cell cell, float max) { return cell.Position.x < max % _map.Columns; } public void ApplyToMap(List<Cell> cells) { foreach (var cell in cells) { _map[(uint) cell.Position.x, (uint) cell.Position.y] = cell.Type; } } public static IEnumerable<Cell> GetNeighbors(Map map, Cell origin) { var ret = new List<Cell>(); for (var x = origin.Position.x - 1; x <= origin.Position.x + 1; x++) { for (var y = origin.Position.y - 1; y <= origin.Position.y + 1; y++) { if ((Math.Abs(x - origin.Position.x) > .1f || Math.Abs(y - origin.Position.y) > .1f) && IsInMapRange(map, (int) x, (int) y) && map[(uint) x, (uint) y] != origin.Type) { ret.Add(new Cell((uint) x, (uint) y, map[(uint) x, (uint) y])); } } } return ret; } private void Grow(Cell targetCell, TileType targetType) { targetCell.Type = targetType; } private static bool IsInMapRange(Map map, int x, int y) { return (x >= 0 && x < map.Columns && y >= 0 && y < map.Rows); } #endregion } }