Euphoria
generator_cell.cc
Go to the documentation of this file.
1 #include "core/generator_cell.h"
2 
3 #include "base/random.h"
4 #include "core/image_draw.h"
5 #include "base/colors.h"
6 #include "core/image.h"
7 #include "base/cint.h"
8 #include "core/table_bool.h"
9 
10 #include <functional>
11 #include <optional>
12 
14 {
15  struct SmoothRule final : public Rule
16  {
18 
20 
22  : smooth_function(sf)
23  {
24  }
25 
26  void
27  update(CellularAutomata* self) override
28  {
30  (
31  self->world,
32  self->outside_rule,
34  );
35  }
36  };
37 
38 
39  struct RandomFillRule : public Rule
40  {
42  float random_fill;
44 
46  (
47  Random* r,
48  float rf,
50  )
51  : rand(r)
52  , random_fill(rf)
53  , border_control(bc)
54  {
55  }
56 
57  void
58  update(CellularAutomata* self) override
59  {
60  set_white_noise(self->world, border_control, [this]()
61  {
62  return rand->get_next_float01() < random_fill;
63  });
64  }
65  };
66 
67 
68  struct FillSmallHolesRule : public Rule
69  {
71  int min_count;
72 
73  FillSmallHolesRule(bool ad, int mc)
74  : allow_diagonals(ad)
75  , min_count(mc)
76  {
77  }
78 
79  void
80  update(CellularAutomata* self) override
81  {
82  BoolTable& world = *self->world;
83  const auto regions = find_empty_regions(world, allow_diagonals);
84  for(const auto& re: regions)
85  {
86  if(c_sizet_to_int(re.size()) < min_count)
87  {
88  for(const auto& p: re)
89  {
90  world[{p.x, p.y}] = true;
91  }
92  }
93  }
94  }
95  };
96 
97 
98  struct FillAllHoles : public Rule
99  {
102 
103  FillAllHoles(bool ad, int htk)
104  : allow_diagonals(ad)
105  , holes_to_keep(htk)
106  {
107  }
108 
109  void
110  update(CellularAutomata* self) override
111  {
112  BoolTable& world = *self->world;
113  auto regions = find_empty_regions(world, allow_diagonals);
114  using V = std::vector<vec2i>;
115  std::sort
116  (
117  regions.begin(),
118  regions.end(),
119  [](const V& lhs, const V& rhs)
120  {
121  return lhs.size() < rhs.size();
122  }
123  );
124  for(int hole_index=0; hole_index<holes_to_keep && regions.empty() == false; hole_index+=1)
125  {
126  regions.pop_back();
127  }
128  for(const auto& re: regions)
129  {
130  for(const auto& p: re)
131  {
132  world[{p.x, p.y}] = true;
133  }
134  }
135  }
136  };
137 
138 
139  struct HorizontalBlankRule : public Rule
140  {
141  int center;
142  int height;
143 
144  HorizontalBlankRule(int c, int h)
145  : center(c)
146  , height(h)
147  {
148  }
149 
150  void
151  update(CellularAutomata* self) override
152  {
153  const BoolTable current = *self->world;
154 
155  self->world->set_all
156  (
157  [&current, this] (int x, int y)
158  {
159  if(y >= center && y < center + height)
160  {
161  // todo(Gustav): this doesn't respect the outside rule
162  // but should it...?
163  return false;
164  }
165  return current[{x, y}];
166  }
167  );
168  }
169  };
170 
171 
172  void
173  Rules::add_rule(int count, std::shared_ptr<Rule> rule)
174  {
175  for (int index = 0; index < count; index += 1)
176  {
177  rules.emplace_back(rule);
178  }
179  }
180 
181 
183  (
184  generator::Rules* r,
185  generator::World* w,
186  const Lrud<core::OutsideRule>& fw
187  )
188  : rules(r)
189  , world(w)
190  , outside_rule(fw)
191  , iteration(0)
192  {
193  }
194 
195 
196  bool
198  {
199  return false == (iteration < c_sizet_to_int(rules->rules.size()));
200  }
201 
202 
203  void
205  {
206  rules->rules[iteration]->update(this);
207  iteration += 1;
208  }
209 
210 
211  void
213  (
214  Rules* cell,
215  Random* random,
216  float random_fill,
217  Lrud<BorderSetupRule> border_control
218  )
219  {
220  cell->add_rule
221  (
222  1,
223  std::make_shared<RandomFillRule>
224  (
225  random,
226  random_fill,
227  border_control
228  )
229  );
230  }
231 
232 
233  void
234  add_clear_rules(Rules* ca, int times, int count, int range, bool include_self, NeighborhoodAlgorithm algorithm)
235  {
236  ca->add_rule
237  (
238  times,
239  std::make_shared<SmoothRule>
240  (
241  [count, range, include_self, algorithm] (bool, const WallCounter& wc) -> std::optional<bool>
242  {
243  const auto walls = wc.count(range, include_self, algorithm);
244  if (walls < count) { return false; }
245  return std::nullopt;
246  }
247  )
248  );
249  }
250 
251 
252  void
254  (
255  Rules* ca,
256  int times,
257  ChangeFunction change
258  )
259  {
260  ca->add_rule
261  (
262  times,
263  std::make_shared<SmoothRule>(change)
264  );
265  }
266 
267 
268  void
269  add_simple_rules(Rules* ca, int times, int count, bool include_self, NeighborhoodAlgorithm algorithm)
270  {
271  ca->add_rule
272  (
273  times,
274  std::make_shared<SmoothRule>
275  (
276  [count, include_self, algorithm] (bool, const WallCounter& wc) -> std::optional<bool>
277  {
278  const auto walls = wc.count(1, include_self, algorithm);
279  if (walls > count) { return true; }
280  if (walls < count) { return false; }
281  return std::nullopt;
282  }
283  )
284  );
285  }
286 
287 
288  void
289  add_horizontal_blank_rule(Rules* ca, int y, int height)
290  {
291  ca->add_rule(1, std::make_shared<HorizontalBlankRule>(y, height));
292  }
293 
294 
295  void
296  add_spiky_rules(Rules* ca, int times, int count, bool include_self, NeighborhoodAlgorithm algorithm)
297  {
298  ca->add_rule
299  (
300  times,
301  std::make_shared<SmoothRule>
302  (
303  [count, include_self, algorithm] (bool, const WallCounter& wc) -> std::optional<bool>
304  {
305  return wc.count(1, include_self, algorithm) >= count;
306  }
307  )
308  );
309  }
310 
311 
312  void
313  add_combo_rules(Rules* ca, int times, int count, int big_count, bool include_self, NeighborhoodAlgorithm algorithm)
314  {
315  ca->add_rule
316  (
317  times,
318  std::make_shared<SmoothRule>
319  (
320  [count, big_count, include_self, algorithm](bool, const WallCounter& wc) -> std::optional<bool>
321  {
322  const auto walls = wc.count(1, include_self, algorithm);
323  if (walls > count) { return true; }
324  if(wc.count(2, include_self, algorithm) <= big_count) { return true; }
325  if (walls < count) { return false; }
326  return std::nullopt;
327  }
328  )
329  );
330  }
331 
332 
333  void
334  add_fill_small_holes_rule(Rules* rules, bool allow_diagonals, int min_count)
335  {
336  rules->add_rule
337  (
338  1,
339  std::make_shared<FillSmallHolesRule>(allow_diagonals, min_count)
340  );
341  }
342 
343 
344  void
345  add_fill_all_holes_rule(Rules* rules, bool allow_diagonals, int holes_to_keep)
346  {
347  rules->add_rule
348  (
349  1,
350  std::make_shared<FillAllHoles>(allow_diagonals, holes_to_keep)
351  );
352  }
353 }
void add_spiky_rules(Rules *ca, int times, int count, bool include_self, NeighborhoodAlgorithm algorithm)
simple smoothing, but always set the cell, seems to provide spikes
void add_combo_rules(Rules *ca, int times, int count, int big_count, bool include_self, NeighborhoodAlgorithm algorithm)
smooth but 'big_count' is applied for R(2)
void add_random_fill(Rules *cell, Random *random, float random_fill, Lrud< BorderSetupRule > border_control)
fills the world with random data
void add_fill_small_holes_rule(Rules *rules, bool allow_diagonals, int min_count)
fills all open areas that are less than 'min_count'
void add_fill_all_holes_rule(Rules *rules, bool allow_diagonals, int holes_to_keep)
fills all open areas, but keeps 'holes_to_keep'
void add_clear_rules(Rules *ca, int times, int count, int range, bool include_self, NeighborhoodAlgorithm algorithm)
'clears' cells with less than 'count' neighbours, good for removing 'blobs'
void add_simple_rules(Rules *ca, int times, int count, bool include_self, NeighborhoodAlgorithm algorithm)
simple smoothing, less than count neighbours are removed, more -> solid
void add_complex_rules(Rules *ca, int times, ChangeFunction change)
void add_horizontal_blank_rule(Rules *ca, int y, int height)
blanks out cells at 'y' and 'height' down
std::function< std::optional< bool >(bool, const WallCounter &) > ChangeFunction
void make_smoother(BoolTable *world, Lrud< OutsideRule > outside_rule, std::function< std::optional< bool >(bool, const WallCounter &)> smooth_function)
Definition: table_bool.cc:327
NeighborhoodAlgorithm
Definition: table_bool.h:85
void set_white_noise(BoolTable *world, Lrud< BorderSetupRule > border_control, std::function< bool()> rng)
Definition: table_bool.cc:11
std::vector< std::vector< vec2i > > find_empty_regions(const BoolTable &world, bool allow_diagonals)
Definition: table_bool.cc:422
int c_sizet_to_int(size_t t)
Definition: cint.cc:11
WEL512 Random Number Generator.
Definition: random.h:21
void set_all(TFunc f)
Definition: table.h:49
int count(int step, bool include_self, NeighborhoodAlgorithm algorithm) const
Definition: table_bool.cc:306
CellularAutomata(generator::Rules *r, generator::World *w, const Lrud< core::OutsideRule > &fw)
void update(CellularAutomata *self) override
void update(CellularAutomata *self) override
void update(CellularAutomata *self) override
RandomFillRule(Random *r, float rf, Lrud< BorderSetupRule > bc)
void update(CellularAutomata *self) override
Lrud< BorderSetupRule > border_control
std::vector< std::shared_ptr< Rule > > rules
void add_rule(int count, std::shared_ptr< Rule > rule)
SmoothRule(SmoothRule::SmoothFunction sf)
void update(CellularAutomata *self) override