1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
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
}
}