Euphoria
table_bool.cc
Go to the documentation of this file.
1  #include "core/table_bool.h"
2 
3 #include "core/image_draw.h"
4 #include "assert/assert.h"
5 #include <cmath>
6 
7 namespace eu::core
8 {
9  void
11  (
12  BoolTable* world,
13  Lrud<BorderSetupRule> border_control,
14  std::function<bool()> rng
15  )
16  {
17  world->set_all([&](int x, int y)
18  {
19  const auto is_on_left_border = x == 0;
20  const auto is_on_right_border = x == world->get_width() - 1;
21  const auto is_on_up_border = y == 0;
22  const auto is_on_down_border = y == world->get_height() - 1;
23 
24 #define CHECK_BORDER(b, p) \
25  do \
26  { \
27  if( b && border_control.p != BorderSetupRule::random) \
28  { return border_control.p == BorderSetupRule::always_wall; } \
29  } while(false)
30 
31  CHECK_BORDER(is_on_left_border, left);
32  CHECK_BORDER(is_on_right_border, right);
33  CHECK_BORDER(is_on_up_border, up);
34  CHECK_BORDER(is_on_down_border, down);
35 #undef CHECK_BORDER
36 
37  return rng();
38  });
39  }
40 
41 
42  namespace
43  {
44  int
45  count_single_walls
46  (
47  const BoolTable& world,
48  Lrud<OutsideRule> outside_rule,
49  int x,
50  int y,
51  int cx,
52  int cy,
53  bool include_self
54  )
55  {
56  if (include_self==false && x == cx && y == cy)
57  {
58  // do not include self when counting walls
59  return 0;
60  }
61 
62  auto contains = [&world](int xx, int yy)
63  {
64  return world.get_indices().contains_inclusive(xx, yy);
65  };
66 
67  if (contains(x, y))
68  {
69  // it is inside
70  if (world[{x, y}])
71  {
72  return 1;
73  }
74  else
75  {
76  return 0;
77  }
78  }
79 
80  // todo(Gustav): the x/y is too much copy/paste... fix!
81  auto nx = x;
82  if (!contains(x, 0))
83  {
84  // x is outside
85  const auto xrule = x < 0 ? outside_rule.left : outside_rule.right;
86  switch (xrule)
87  {
88  case OutsideRule::wall:
89  return 1;
90  case OutsideRule::empty:
91  return 0;
93  // todo(Gustav): implement this!
94  nx = keep_within(world.get_indices().get_range_x(), x);
95  DIE("Implement this");
96  break;
97  case OutsideRule::wrap:
98  nx = wrap(world.get_indices().get_range_x(), x);
99  break;
100  default:
101  DIE("Unhandled case");
102  break;
103  }
104  }
105 
106  auto ny = y;
107  if (!contains(0, y))
108  {
109  // y is outside
110  const auto yrule = y < 0 ? outside_rule.up : outside_rule.down;
111  switch (yrule)
112  {
113  case OutsideRule::wall:
114  return 1;
115  case OutsideRule::empty:
116  // pass
117  return 0;
118  case OutsideRule::mirror:
119  // todo(Gustav): implement this!
120  ny = keep_within(world.get_indices().get_range_y(), y);
121  DIE("Implement this");
122  break;
123  case OutsideRule::wrap:
124  ny = wrap(world.get_indices().get_range_y(), y);
125  break;
126  default:
127  DIE("Unhandled case");
128  break;
129  }
130  }
131 
132  if (world[{nx, ny}])
133  {
134  return 1;
135  }
136  else
137  {
138  return 0;
139  }
140  }
141  }
142 
143 
144  int
146  (
147  const BoolTable& world,
148  Lrud<OutsideRule> outside_rule,
149  int cx,
150  int cy,
151  int step,
152  bool include_self
153  )
154  {
155  int walls = 0;
156 
157  for (int y = cy - step; y <= cy + step; y += 1)
158  {
159  for (int x = cx - step; x <= cx + step; x += 1)
160  {
161  const auto manhattan_distance = std::abs(x-cx) + std::abs(y-cy);
162  if(manhattan_distance > step) { continue; }
163 
164  walls += count_single_walls
165  (
166  world,
167  outside_rule,
168  x,
169  y,
170  cx,
171  cy,
172  include_self
173  );
174  }
175  }
176 
177  return walls;
178  }
179 
180 
181  int
183  (
184  const BoolTable& world,
185  Lrud<OutsideRule> outside_rule,
186  int cx,
187  int cy,
188  int step,
189  bool include_self
190  )
191  {
192  int walls = 0;
193 
194  auto calc_walls = [&](int x, int y)
195  {
196  walls += count_single_walls
197  (
198  world,
199  outside_rule,
200  x,
201  y,
202  cx,
203  cy,
204  include_self
205  );
206  };
207  for (int y = cy - step; y <= cy + step; y += 1)
208  {
209  calc_walls(cx, y);
210  }
211  for (int x = cx - step; x <= cx + step; x += 1)
212  {
213  calc_walls(x, cy);
214  }
215 
216  return walls;
217  }
218 
219 
220  int
222  (
223  const BoolTable& world,
224  Lrud<OutsideRule> outside_rule,
225  int cx,
226  int cy,
227  int step,
228  bool include_self
229  )
230  {
231  int walls = 0;
232 
233  for (int y = cy - step; y <= cy + step; y += 1)
234  {
235  for (int x = cx - step; x <= cx + step; x += 1)
236  {
237  walls += count_single_walls
238  (
239  world,
240  outside_rule,
241  x,
242  y,
243  cx,
244  cy,
245  include_self
246  );
247  }
248  }
249 
250  return walls;
251  }
252 
253 
255  (
256  const BoolTable& w,
258  int x,
259  int y
260  )
261  : world(w)
262  , outside_rule(r)
263  , cx(x)
264  , cy(y)
265  {
266  }
267 
268 
269  namespace
270  {
271  int
272  count_walls
273  (
274  NeighborhoodAlgorithm algorithm,
275  const BoolTable& world,
276  Lrud<OutsideRule> outside_rule,
277  int cx,
278  int cy,
279  int step,
280  bool include_self
281  )
282  {
283  switch(algorithm)
284  {
286  return count_walls_manhattan
287  (world, outside_rule, cx, cy, step, include_self);
289  return count_walls_plus
290  (world, outside_rule, cx, cy, step, include_self);
292  return count_walls_box
293  (world, outside_rule, cx, cy, step, include_self);
294 
295  default:
296  DIE("Unhandled algorithm");
297  return 0;
298  }
299  }
300  }
301 
302 
303 
304  int
306  (
307  int step,
308  bool include_self,
309  NeighborhoodAlgorithm algorithm
310  ) const
311  {
312  return count_walls
313  (
314  algorithm,
315  world,
316  outside_rule,
317  cx,
318  cy,
319  step,
320  include_self
321  );
322  }
323 
324 
325  void
327  (
328  BoolTable* world,
329  Lrud<OutsideRule> outside_rule,
330  std::function<std::optional<bool>(bool, const WallCounter&)> smooth_function
331  )
332  {
333  const BoolTable current = *world;
334 
335  world->set_all([&current, outside_rule, smooth_function](int x, int y)
336  {
337  const auto value = current[{x, y}];
338  const auto walls = WallCounter{current, outside_rule, x, y};
339  const auto smoothed_wall = smooth_function(value, walls);
340  return smoothed_wall.value_or(value);
341  });
342  }
343 
344 
345  std::vector<vec2i>
347  {
348  auto ret = std::vector<vec2i>{};
349 
350  for (int y = 0; y < world.get_height(); y += 1)
351  {
352  for (int x = 0; x < world.get_width(); x += 1)
353  {
354  if(world[{x,y}] == false)
355  {
356  ret.emplace_back(x, y);
357  }
358  }
359  }
360 
361  return ret;
362  }
363 
364  std::vector<vec2i>
366  (
367  const BoolTable& world,
368  const vec2i& start,
369  bool allow_diagonals
370  )
371  {
373  (
374  world.get_width(),
375  world.get_height(),
376  false
377  );
378  auto stack = std::vector<vec2i>{};
379  auto ret = std::vector<vec2i>{};
380 
381  auto add_to_stack = [&](const vec2i& p)
382  {
383  if(p.x < 0) { return; }
384  if(p.x >= world.get_width()) { return; }
385  if(p.y < 0) { return; }
386  if(p.y >= world.get_height()) { return; }
387  if(visited[p] == true) { return; }
388  visited[p] = true;
389  // todo(Gustav): if ret contains p, return
390 
391  stack.emplace_back(p);
392  };
393 
394  add_to_stack(start);
395  while(stack.empty() == false)
396  {
397  const auto p = *stack.rbegin();
398  stack.pop_back();
399  if(world[p] == true) { continue; }
400 
401  // todo(Gustav): don't add if already in list
402  ret.emplace_back(p);
403 
404  add_to_stack({p.x + 1, p.y});
405  add_to_stack({p.x - 1, p.y});
406  add_to_stack({p.x, p.y + 1});
407  add_to_stack({p.x, p.y - 1});
408 
409  if(allow_diagonals)
410  {
411  add_to_stack({p.x + 1, p.y + 1});
412  add_to_stack({p.x + 1, p.y - 1});
413  add_to_stack({p.x - 1, p.y + 1});
414  add_to_stack({p.x - 1, p.y - 1});
415  }
416  }
417 
418  return ret;
419  }
420 
421  std::vector<std::vector<vec2i>>
422  find_empty_regions(const BoolTable& world, bool allow_diagonals)
423  {
424  auto ret = std::vector<std::vector<vec2i>>{};
425 
427  (
428  world.get_width(),
429  world.get_height(),
430  false
431  );
432 
433  const auto blocks = find_empty_blocks(world);
434  for(const auto block: blocks)
435  {
436  if(visited[block] == true) { continue; }
437 
438  const auto island = find_flood_fill_items(world, block, allow_diagonals);
439  ret.emplace_back(island);
440  for(const auto& island_block: island)
441  {
442  visited[island_block] = true;
443  }
444  }
445 
446  return ret;
447  }
448 
449 
450 
452  : color(c)
453  {
454  }
455 
456 
457  Image
459  (
460  const BoolTable& world,
461  Rgbai wall_color,
462  Rgbai space_color,
463  int scale,
464  std::optional<BorderSettings> border
465  )
466  {
467  const bool has_alpha =
468  wall_color.a < 255 ||
469  space_color.a < 255 ||
470  (border.has_value() ? border->color.a < 255 : false)
471  ;
472 
473  const auto image_width = world.get_width() * scale;
474  const auto image_height = world.get_height() * scale;
475 
476  Image image;
477  if(has_alpha)
478  {
479  image.setup_with_alpha_support(image_width, image_height);
480  }
481  else
482  {
483  image.setup_no_alpha_support(image_width, image_height);
484  }
485 
486  auto get_space_color = [&](int x, int y) -> Rgbai
487  {
488  if(border.has_value() == false) { return space_color; }
489 
490  const auto rule = Lrud<OutsideRule>{OutsideRule::empty};
491  const auto algorithm = NeighborhoodAlgorithm::plus;
492 
493  const auto wc = WallCounter{world, rule, x, y};
494  const auto walls = wc.count(1, false, algorithm);
495 
496  if(walls>0) { return border->color; }
497  else { return space_color; }
498  };
499 
500  clear(&image, space_color);
501 
502  for (int y = 0; y < world.get_height(); y += 1)
503  {
504  for (int x = 0; x < world.get_width(); x += 1)
505  {
506  const auto px = x * scale;
507  const auto py = y * scale;
508  const auto color = world[{x, y}]
509  ? wall_color
510  : get_space_color(x, y)
511  ;
512  draw_square(&image, color, px, py + scale - 1, scale);
513  }
514  }
515 
516  return image;
517  }
518 }
#define DIE(message)
Definition: assert.h:67
void make_smoother(BoolTable *world, Lrud< OutsideRule > outside_rule, std::function< std::optional< bool >(bool, const WallCounter &)> smooth_function)
Definition: table_bool.cc:327
void clear(Image *image, const Rgbai &color)
Definition: image_draw.cc:32
int count_walls_manhattan(const BoolTable &world, Lrud< OutsideRule > outside_rule, int cx, int cy, int step, bool include_self)
Definition: table_bool.cc:146
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
Table< bool > BoolTable
Definition: table_bool.h:15
int count_walls_box(const BoolTable &world, Lrud< OutsideRule > outside_rule, int cx, int cy, int step, bool include_self)
Definition: table_bool.cc:222
std::vector< vec2i > find_flood_fill_items(const BoolTable &world, const vec2i &start, bool allow_diagonals)
Definition: table_bool.cc:366
std::vector< vec2i > find_empty_blocks(const BoolTable &world)
Definition: table_bool.cc:346
int count_walls_plus(const BoolTable &world, Lrud< OutsideRule > outside_rule, int cx, int cy, int step, bool include_self)
Definition: table_bool.cc:183
Image draw(const BoolTable &world, Rgbai wall_color, Rgbai space_color, int scale, std::optional< BorderSettings > border)
Definition: table_bool.cc:459
std::vector< std::vector< vec2i > > find_empty_regions(const BoolTable &world, bool allow_diagonals)
Definition: table_bool.cc:422
void draw_square(Image *image, const Rgbai &color, int x, int y, int size)
Definition: image_draw.cc:67
T keep_within(const Range< T > &range, T value)
Definition: range.h:115
constexpr float abs(float r)
Definition: numeric.h:8
T wrap(const Range< T > &range, T value)
Definition: range.h:130
T right
Definition: lrud.h:24
T left
Definition: lrud.h:23
T up
Definition: lrud.h:25
T down
Definition: lrud.h:26
Definition: rgb.h:45
U8 a
Definition: rgb.h:49
BorderSettings(const Rgbai &c)
Definition: table_bool.cc:451
void set_all(TFunc f)
Definition: table.h:49
Idx get_height() const
Definition: table.h:158
Idx get_width() const
Definition: table.h:153
static Table from_width_height(Idx width, Idx height, T d=T())
Definition: table.h:23
const BoolTable & world
Definition: table_bool.h:99
WallCounter(const BoolTable &w, Lrud< core::OutsideRule > r, int x, int y)
Definition: table_bool.cc:255
int count(int step, bool include_self, NeighborhoodAlgorithm algorithm) const
Definition: table_bool.cc:306
Lrud< core::OutsideRule > outside_rule
Definition: table_bool.h:100
Definition: vec2.h:72
#define CHECK_BORDER(b, p)