header_utils
Loading...
Searching...
No Matches
square_grid_algorithms.h
1
4
5#pragma once
6
7#include "square_grid.h"
8#include <queue>
9
11{
14
19 template <typename TILE_DATA, bool RESIZABLE, typename FUNC>
20 void apply_cellular_automata(grid<TILE_DATA, RESIZABLE>& current_iteration, irec2 const& rect, FUNC&& func)
21 {
22 if constexpr (std::invocable<FUNC, TILE_DATA&, std::span<glm::ivec2 const>>)
23 {
24 using iteration_flags = grid<TILE_DATA, RESIZABLE>::iteration_flags;
25 static constexpr enum_flags<iteration_flags> neighbor_iteration_flags = { iteration_flags::only_valid, iteration_flags::diagonals };
26
27 grid<TILE_DATA, RESIZABLE> previous_iteration = current_iteration;
28
29 std::vector<glm::ivec2> neighbors;
30 current_iteration.for_each_tile_in_rect(rect, [&](glm::ivec2 pos) {
31 neighbors.clear();
32 current_iteration.for_each_neighbor<neighbor_iteration_flags>(pos, op::push_back_to(neighbors));
33 func(previous_iteration[pos], std::span<glm::ivec2 const>{ neighbors });
34 });
35
36 std::swap(current_iteration, previous_iteration);
37 }
38 else if constexpr (std::invocable<FUNC, TILE_DATA&, std::span<TILE_DATA const* const>>)
39 {
40 apply_cellular_automata(current_iteration, rect, [&, func = std::forward<FUNC>(func)](TILE_DATA& cell, std::span<glm::ivec2 const> neighbors){
41 std::array<TILE_DATA const*, 8> neighbor_cells;
42 for (size_t i = 0; i < neighbors.size(); ++i)
43 neighbor_cells[i] = &current_iteration[neighbors[i]];
44 func(cell, std::span<TILE_DATA const* const>{&neighbor_cells[0], neighbors.size()});
45 });
46 }
47 else
48 {
49 static_assert(std::is_same_v<TILE_DATA, FUNC>);
50 }
51 }
52
54 template <typename TILE_DATA, bool RESIZABLE, typename FUNC>
55 void apply_cellular_automata(grid<TILE_DATA, RESIZABLE>& current_iteration, FUNC&& func)
56 {
57 apply_cellular_automata(current_iteration, current_iteration.bounds(), std::forward<FUNC>(func));
58 }
59
61 template <typename TILE_DATA, bool RESIZABLE, typename FUNC>
62 void apply_cellular_automata(grid<TILE_DATA, RESIZABLE> const& current_iteration, grid<TILE_DATA, RESIZABLE>& new_iteration, irec2 const& rect, FUNC&& func);
63
68 template <typename TILE_DATA, bool RESIZABLE, change_tile_callback<TILE_DATA> REPLACE_FUNC, query_tile_callback<TILE_DATA> SHOULD_FLOOD_FUNC>
69 void flood_at(grid<TILE_DATA, RESIZABLE>& grid, glm::ivec2 start, REPLACE_FUNC&& replace, SHOULD_FLOOD_FUNC&& should_flood)
70 {
71 if (!grid.is_valid(start)) return;
72 if (!grid.apply(start, should_flood)) return;
73
74 grid.apply(start, replace);
75 if (grid.apply(start, should_flood)) return;
76
77 std::queue<glm::ivec2> queue;
78 queue.push(start);
79 while (!queue.empty())
80 {
81 auto n = queue.front();
82 queue.pop();
83
84 auto l = n, r = glm::ivec2{ n.x + 1, n.y };
85
86 while (grid.is_valid(l) && grid.apply(l, should_flood))
87 {
88 grid.apply(l, replace);
89 l.x--;
90 }
91 l.x++;
92
93 while (grid.is_valid(r) && grid.apply(r, should_flood))
94 {
95 grid.apply(r, replace);
96 r.x++;
97 }
98 r.x--;
99
100 if (n.y - 1 >= 0)
101 {
102 bool span_added = false;
103 for (int x = l.x; x <= r.x; x++)
104 {
105 glm::ivec2 up = { x, n.y - 1 };
106 if (grid.apply(up, should_flood))
107 {
108 if (!span_added)
109 {
110 span_added = true;
111 queue.push(up);
112 }
113 }
114 else
115 span_added = false;
116 }
117 }
118 if (n.y + 1 < grid.height())
119 {
120 bool span_added = false;
121 for (int x = l.x; x <= r.x; x++)
122 {
123 glm::ivec2 down = { x, n.y + 1 };
124 if (grid.apply(down, should_flood))
125 {
126 if (!span_added)
127 {
128 span_added = true;
129 queue.push(down);
130 }
131 }
132 else
133 span_added = false;
134 }
135 }
136 }
137 //*/
138 }
139
144 template <typename TILE_DATA, bool RESIZABLE, change_tile_callback<TILE_DATA> REPLACE_FUNC>
145 void flood_at(grid<TILE_DATA, RESIZABLE>& grid, glm::ivec2 start, REPLACE_FUNC&& replace)
146 {
147 static_assert(std::equality_comparable<TILE_DATA>, "To use this flood fill algorithm, tile data in this grid must be comparable using operator==");
148 const auto* data_at_start = grid.at(start);
149 flood_at(grid, start, std::forward<REPLACE_FUNC>(replace), [data_at_start](glm::ivec2 at, TILE_DATA const& data) { return data == *data_at_start; });
150 }
151
156 template <typename TILE_DATA, bool RESIZABLE, query_tile_callback<TILE_DATA> SHOULD_FLOOD_FUNC>
157 void flood_at(grid<TILE_DATA, RESIZABLE>& grid, glm::ivec2 start, TILE_DATA const& replace_with, SHOULD_FLOOD_FUNC&& should_flood)
158 {
159 static_assert(std::is_copy_assignable_v<TILE_DATA>, "To use this flood fill algorithm, tile data in this grid must be copy-assignable");
160 flood_at(grid, start, [&](glm::ivec2 at, TILE_DATA& data) { data = replace_with; }, std::forward<SHOULD_FLOOD_FUNC>(should_flood));
161 }
162
167 template <typename TILE_DATA, bool RESIZABLE>
168 void flood_at(grid<TILE_DATA, RESIZABLE>& grid, glm::ivec2 start, TILE_DATA const& replace_with)
169 {
170 static_assert(std::is_copy_assignable_v<TILE_DATA>, "To use this flood fill algorithm, tile data in this grid must be copy-assignable");
171 flood_at(grid, start, [&](glm::ivec2 at, TILE_DATA& data) { data = replace_with; });
172 }
173
175}
void flood_at(grid< TILE_DATA, RESIZABLE > &grid, glm::ivec2 start, REPLACE_FUNC &&replace, SHOULD_FLOOD_FUNC &&should_flood)
Performs a flood-fill algorithm on grid.
void apply_cellular_automata(grid< TILE_DATA, RESIZABLE > &current_iteration, irec2 const &rect, FUNC &&func)
Applies a cellular automata generation function on (a region of) the grid.
constexpr decltype(auto) at(random_access_range auto &range, std::integral auto index)
Returns a reference to the value at index of range.
Definition ranges.h:61
A (constexpr) value struct that represents a set of bits mapped to an enum (implemented as a bitset).
Definition enum_flags.h:60
A container for squares in a 2D square grid.
Definition square_grid.h:43
auto for_each_neighbor(glm::ivec2 of, change_tile_callback< TILE_DATA > auto &&func)
TODO: set_* functions that mirror for_each_*, e.g. set_rect(rect, tile);.
auto for_each_tile_in_rect(irec2 const &tile_rect, change_tile_callback< TILE_DATA > auto &&func)
TODO: deduce thos.
auto apply(glm::ivec2 to, FUNC &&func)
Modifiers.