header_utils
Loading...
Searching...
No Matches
square_grid.h
1
4
5#pragma once
6
7#include "squares.h"
8#include <vector>
9
11{
12 template <typename T>
13 concept void_or_boolean = std::same_as<void, T> || std::convertible_to<T, bool>;
14 /*
15 template <typename FUNC, typename TILE_DATA>
16 concept tile_callback =
17 requires (FUNC func) { { func(glm::ivec2{ 0, 0 }) } -> void_or_boolean; } ||
18 requires (FUNC func, TILE_DATA& ref) { { func(glm::ivec2{ 0, 0 }, ref) } -> void_or_boolean; } ||
19 requires (FUNC func, TILE_DATA& ref) { { func(ref, glm::ivec2{ 0, 0 }) } -> void_or_boolean; } ||
20 requires (FUNC func, TILE_DATA& ref) { { func(ref) } -> void_or_boolean; };
21 */
22 template <typename FUNC>
23 concept tile_callback = requires (FUNC func) { { func(glm::ivec2{ 0, 0 }) } -> void_or_boolean; };
24 template <typename FUNC, typename T>
25 concept query_tile_callback = requires (FUNC func, T const& td) { { func(glm::ivec2{ 0, 0 }, td) } -> std::convertible_to<bool>; };
26 template <typename FUNC, typename T>
27 concept change_tile_callback = requires (FUNC func, T& td) { { func(glm::ivec2{ 0, 0 }, td) }; };
28
29 template <typename TILE_DATA, bool RESIZABLE = true>
30 struct grid
31 {
32 public:
33
34 static constexpr bool resizable = RESIZABLE;
35 using tile_data_type = TILE_DATA;
36
37 grid() requires RESIZABLE = default;
38 grid(int w, int h, TILE_DATA const& default_tile) { Reset(w, h, default_tile); }
39 grid(glm::ivec2 size, TILE_DATA const& default_tile) : grid(size.x, size.y, default_tile) {}
40 grid(int w, int h) { Reset(w, h); }
41 explicit grid(glm::ivec2 size) : grid(size.x, size.y) {}
42
43 void reset(int w, int h, TILE_DATA const& default_tile) requires RESIZABLE { Reset(w, h, default_tile); }
44
45 void reset(int w, int h) requires RESIZABLE { Reset(w, h); }
46
47 void reset(glm::ivec2 size) requires RESIZABLE { Reset(size.x, size.y); }
48 void reset(glm::ivec2 size, TILE_DATA const& default_tile) requires RESIZABLE { Reset(size.x, size.y, default_tile); }
49
50 template <change_tile_callback<TILE_DATA> TILE_RESET_FUNC>
51 void resetFrom(glm::ivec2 size, TILE_RESET_FUNC&& tile_reset) requires RESIZABLE { Reset(size.x, size.y, std::forward<TILE_RESET_FUNC>(tile_reset)); }
52
54
55 [[nodiscard]] TILE_DATA& operator[](int i) { return mTiles[i]; }
56 [[nodiscard]] TILE_DATA const& operator[](int i) const { return mTiles[i]; }
57
58 [[nodiscard]] TILE_DATA& operator[](glm::ivec2 v) { return mTiles[index(v)]; }
59 [[nodiscard]] TILE_DATA const& operator[](glm::ivec2 v) const { return mTiles[index(v)]; }
60
61 [[nodiscard]] bool is_valid(int x, int y) const noexcept { return x >= 0 && y >= 0 && x < mWidth && y < mHeight; }
62 [[nodiscard]] bool is_valid(glm::vec2 world_pos, glm::vec2 tile_size) const noexcept { return is_valid(world_pos_to_tile_pos(world_pos, tile_size)); }
63 [[nodiscard]] bool is_valid(glm::ivec2 pos) const noexcept { return is_valid(pos.x, pos.y); }
64 [[nodiscard]] bool is_index_valid(int index) const noexcept { return index >= 0 && index < (int)mTiles.size(); }
65
66 [[nodiscard]] bool is_valid(int x, int y, int edge_width) const noexcept { return x >= edge_width && y >= edge_width && x < mWidth - edge_width && y < mHeight - edge_width; }
67 [[nodiscard]] bool is_valid(glm::vec2 world_pos, glm::vec2 tile_size, int edge_width) const noexcept { return is_valid(world_pos_to_tile_pos(world_pos, tile_size), edge_width); }
68 [[nodiscard]] bool is_valid(glm::ivec2 pos, int edge_width) const noexcept { return is_valid(pos.x, pos.y, edge_width); }
69
70 [[nodiscard]] inline int index(int x, int y) const noexcept { return x + y * mWidth; }
71 [[nodiscard]] inline int index(glm::ivec2 pos) const noexcept { return pos.x + pos.y * mWidth; }
72 [[nodiscard]] inline int valid_index(int x, int y) const noexcept { return is_valid(x, y) ? x + y * mWidth : -1; }
73 [[nodiscard]] inline int valid_index(glm::ivec2 pos) const noexcept { return is_valid(pos) ? pos.x + pos.y * mWidth : -1; }
74
75 [[nodiscard]] TILE_DATA const* at(glm::ivec2 pos) const noexcept { if (!is_valid(pos)) return nullptr; return &mTiles[index(pos)]; }
76 [[nodiscard]] TILE_DATA const* at(int x, int y) const noexcept { return at(glm::ivec2{ x, y }); }
77 [[nodiscard]] TILE_DATA* at(glm::ivec2 pos) noexcept { if (!is_valid(pos)) return nullptr; return &mTiles[index(pos)]; }
78 [[nodiscard]] TILE_DATA* at(int x, int y) noexcept { return at(glm::ivec2{ x, y }); }
79 [[nodiscard]] TILE_DATA const* at_index(int index) const noexcept { return is_index_valid(index) ? &mTiles[index] : nullptr; }
80 [[nodiscard]] TILE_DATA* at_index(int index) noexcept { return is_index_valid(index) ? &mTiles[index] : nullptr; }
81
82 [[nodiscard]] TILE_DATA const& safe_at(glm::ivec2 pos, TILE_DATA const& outside) const noexcept { if (auto at = this->at(pos)) return *at; return outside; }
83 [[nodiscard]] TILE_DATA const& safe_at(int x, int y, TILE_DATA const& outside) const noexcept { return safe_at(glm::ivec2{ x, y }, outside); }
84 [[nodiscard]] TILE_DATA& safe_at(glm::ivec2 pos, TILE_DATA& outside) noexcept { if (auto at = this->at(pos)) return *at; return outside; }
85 [[nodiscard]] TILE_DATA& safe_at(int x, int y, TILE_DATA& outside) noexcept { return safe_at(glm::ivec2{ x, y }, outside); }
86
87 [[nodiscard]] int width() const noexcept { return mWidth; }
88 [[nodiscard]] int height() const noexcept { return mHeight; }
89 [[nodiscard]] glm::ivec2 size() const noexcept { return { mWidth, mHeight }; }
90 [[nodiscard]] irec2 perimeter() const noexcept { return irec2::from_size({}, size()); }
91 [[nodiscard]] irec2 bounds() const noexcept { return perimeter(); }
92 [[nodiscard]] rec2 bounds(glm::vec2 tile_size) const noexcept { return perimeter() * tile_size; }
93 [[nodiscard]] std::span<TILE_DATA const> tiles() const { return mTiles; }
94 [[nodiscard]] std::span<TILE_DATA> tiles() { return mTiles; }
95 [[nodiscard]] size_t tile_count() const noexcept { return mTiles.size(); }
96
97 /*
100 bool IsReachable(glm::ivec2 src_tile, glm::ivec2 dest_tile);
101 */
102
103 enum class iteration_flags
104 {
105 with_self,
106 only_valid,
107 diagonals
108 };
109
111
112 template <enum_flags<iteration_flags> FLAGS = enum_flags<iteration_flags>{ iteration_flags::with_self, iteration_flags::only_valid }, typename FUNC >
113 auto for_each_neighbor(glm::ivec2 of, FUNC&& func) const
114 {
115 static constexpr auto ONLY_VALID = FLAGS.contain(iteration_flags::only_valid);
116 using return_type = decltype(this->apply<ONLY_VALID>(glm::ivec2{ 0, 0 }, func));
117
118 if constexpr (std::is_void_v<return_type>)
119 {
120 if constexpr (FLAGS.contain(iteration_flags::with_self))
122 apply<ONLY_VALID>({ of.x - 1, of.y }, func);
123 apply<ONLY_VALID>({ of.x + 1, of.y }, func);
124 apply<ONLY_VALID>({ of.x, of.y - 1 }, func);
125 apply<ONLY_VALID>({ of.x, of.y + 1 }, func);
126
127 if constexpr (FLAGS.contain(iteration_flags::diagonals))
128 {
129 apply<ONLY_VALID>({ of.x - 1, of.y - 1 }, func);
130 apply<ONLY_VALID>({ of.x + 1, of.y + 1 }, func);
131 apply<ONLY_VALID>({ of.x + 1, of.y - 1 }, func);
132 apply<ONLY_VALID>({ of.x - 1, of.y + 1 }, func);
133 }
134 }
135 else
136 {
137 if constexpr (FLAGS.contain(iteration_flags::with_self))
138 if (auto ret = apply<ONLY_VALID>(of, func)) return ret;
139 if (auto ret = apply<ONLY_VALID>({ of.x - 1, of.y }, func)) return ret;
140 if (auto ret = apply<ONLY_VALID>({ of.x + 1, of.y }, func)) return ret;
141 if (auto ret = apply<ONLY_VALID>({ of.x, of.y - 1 }, func)) return ret;
142 if (auto ret = apply<ONLY_VALID>({ of.x, of.y + 1 }, func)) return ret;
143
144 if constexpr (FLAGS.contain(iteration_flags::diagonals))
145 {
146 if (auto ret = apply<ONLY_VALID>({ of.x - 1, of.y - 1 }, func)) return ret;
147 if (auto ret = apply<ONLY_VALID>({ of.x + 1, of.y + 1 }, func)) return ret;
148 if (auto ret = apply<ONLY_VALID>({ of.x + 1, of.y - 1 }, func)) return ret;
149 if (auto ret = apply<ONLY_VALID>({ of.x - 1, of.y + 1 }, func)) return ret;
150 }
151 return return_type{};
152 }
153 }
154
155 template <enum_flags<iteration_flags> FLAGS = enum_flags<iteration_flags>{ iteration_flags::with_self, iteration_flags::only_valid }, typename FUNC >
156 auto for_each_selected_neighbor(glm::ivec2 of, direction_set neighbor_set, FUNC&& func) const
157 {
158 static constexpr auto ONLY_VALID = FLAGS.contain(iteration_flags::only_valid);
159 using return_type = decltype(this->apply<ONLY_VALID>(glm::ivec2{ 0, 0 }, func));
160
161 if constexpr (std::is_void_v<return_type>)
162 {
163 if constexpr (FLAGS.contain(iteration_flags::with_self))
165
166 neighbor_set.for_each([this, of, &func](direction d) {
167 apply<ONLY_VALID>(of + to_ivec(d), func);
168 });
169 }
170 else
171 {
172 if constexpr (FLAGS.contain(iteration_flags::with_self))
173 if (auto ret = apply<ONLY_VALID>(of, func)) return ret;
174
175 return neighbor_set.for_each([this, of, &func](direction d) {
176 return apply<ONLY_VALID>(of + to_ivec(d), func);
177 });
178 }
179 }
180
181 template <enum_flags<iteration_flags> FLAGS = enum_flags<iteration_flags>{ iteration_flags::only_valid }, typename FUNC>
182 auto for_each_tile_in_rect(this auto&& self, irec2 const& tile_rect, FUNC&& func)
183 {
184 static constexpr auto ONLY_VALID = FLAGS.contain(iteration_flags::only_valid);
185 using return_type = decltype(self.template apply<ONLY_VALID>(glm::ivec2{ 0, 0 }, func));
186
187 irec2 rect = tile_rect;
188 if constexpr (ONLY_VALID)
189 rect = tile_rect.clipped_to(self.bounds());
190
191 for (int y = rect.top(); y < rect.bottom(); y++)
192 for (int x = rect.left(); x < rect.right(); x++)
193 {
194 if constexpr (std::is_void_v<return_type>)
195 self.template apply<ONLY_VALID>({ x, y }, func);
196 else
197 {
198 if (auto ret = self.template apply<ONLY_VALID>({ x, y }, func))
199 return ret;
200 }
201 }
202
203 return return_type{};
204 }
205
206 template <enum_flags<iteration_flags> FLAGS = enum_flags<iteration_flags>{ iteration_flags::only_valid }, typename FUNC >
207 auto for_each_tile_in_perimeter(irec2 const& tile_rect, FUNC&& func) const
208 {
209 static constexpr auto ONLY_VALID = FLAGS.contain(iteration_flags::only_valid);
210 using return_type = decltype(this->apply<ONLY_VALID>(glm::ivec2{ 0, 0 }, func));
211
212 irec2 rect = tile_rect;
213 if constexpr (ONLY_VALID)
214 rect = tile_rect.clipped_to(bounds());
215
216 if constexpr (std::is_void_v<return_type>)
217 {
218 for (int x = rect.left(); x < rect.right(); x++)
219 {
220 apply<ONLY_VALID>({ x, rect.top() }, func);
221 apply<ONLY_VALID>({ x, rect.bottom() - 1 }, func);
222 }
223 for (int y = rect.top() + 1; y < rect.bottom() - 1; y++)
224 {
225 apply<ONLY_VALID>({ rect.left(), y }, func);
226 apply<ONLY_VALID>({ rect.right() - 1, y }, func);
227 }
228 }
229 else
230 {
231 for (int x = rect.left(); x < rect.right(); x++)
232 {
233 if (auto ret = apply<ONLY_VALID>({ x, rect.top() }, func)) return ret;
234 if (auto ret = apply<ONLY_VALID>({ x, rect.bottom() - 1 }, func)) return ret;
235 }
236 for (int y = rect.top() + 1; y < rect.bottom() - 1; y++)
237 {
238 if (auto ret = apply<ONLY_VALID>({ rect.left(), y }, func)) return ret;
239 if (auto ret = apply<ONLY_VALID>({ rect.right() - 1, y }, func)) return ret;
240 }
241
242 return return_type{};
243 }
244 }
245
246 template<enum_flags<iteration_flags> FLAGS = enum_flags<iteration_flags>{ iteration_flags::only_valid }, typename TILE_SET, typename FUNC >
247 auto for_each_tile_in_set(TILE_SET&& tiles, FUNC&& func) const
248 {
249 static constexpr auto ONLY_VALID = FLAGS.contain(iteration_flags::only_valid);
250 using return_type = decltype(this->apply<ONLY_VALID>(glm::ivec2{ 0, 0 }, func));
251
252 if constexpr (std::is_void_v<return_type>)
253 {
254 for (auto&& tile : tiles)
255 apply<ONLY_VALID>(tile, func);
256 }
257 else
258 {
259 for (auto&& tile : tiles)
260 if (auto ret = apply<ONLY_VALID>(tile, func)) return ret;
261 return return_type{};
262 }
263 }
264
265 template <enum_flags<iteration_flags> FLAGS = enum_flags<iteration_flags>{ iteration_flags::only_valid }, typename FUNC>
266 auto for_each_tile(this auto&& self, FUNC&& func)
267 {
268 irec2 rect = { 0, 0, self.mWidth, self.mHeight };
269 return self.template for_each_tile_in_rect<FLAGS>(rect, std::forward<FUNC>(func));
270 }
271
272 template <enum_flags<iteration_flags> FLAGS = enum_flags<iteration_flags>{ iteration_flags::only_valid }, typename FUNC>
273 auto for_each_tile_in_polygon(std::span<glm::vec2 const> poly_points, glm::vec2 tile_size, FUNC&& func) const;
274
275 template <enum_flags<iteration_flags> FLAGS = enum_flags<iteration_flags>{ iteration_flags::only_valid }, typename FUNC>
276 auto for_each_tile_in_row(int row, FUNC&& func) const;
277
278 template <enum_flags<iteration_flags> FLAGS = enum_flags<iteration_flags>{ iteration_flags::only_valid }, typename FUNC>
279 auto for_each_tile_in_column(int column, FUNC&& func) const;
280
283 template <typename FUNC>
284 bool line_cast(glm::ivec2 start, glm::ivec2 end, FUNC&& blocks_func, bool ignore_start) const
285 {
286 int delta_x{ end.x - start.x };
287 // if x1 == x2, then it does not matter what we set here
288 signed char const ix((delta_x > 0) - (delta_x < 0));
289 delta_x = std::abs(delta_x) << 1;
290
291 int delta_y(end.y - start.y);
292 // if y1 == y2, then it does not matter what we set here
293 signed char const iy((delta_y > 0) - (delta_y < 0));
294 delta_y = std::abs(delta_y) << 1;
295
296 if (!ignore_start && blocks_func(start))
297 return false;
298
299 if (delta_x >= delta_y)
300 {
301 // error may go below zero
302 int error(delta_y - (delta_x >> 1));
303
304 while (start.x != end.x)
305 {
306 // reduce error, while taking into account the corner case of error == 0
307 if ((error > 0) || (!error && (ix > 0)))
308 {
309 error -= delta_x;
310 start.y += iy;
311 }
312 // else do nothing
313
314 error += delta_y;
315 start.x += ix;
316
317 if (blocks_func(start))
318 return false;
319 }
320 }
321 else
322 {
323 // error may go below zero
324 int error(delta_x - (delta_y >> 1));
325
326 while (start.y != end.y)
327 {
328 // reduce error, while taking into account the corner case of error == 0
329 if ((error > 0) || (!error && (iy > 0)))
330 {
331 error -= delta_y;
332 start.x += ix;
333 }
334 // else do nothing
335
336 error += delta_x;
337 start.y += iy;
338
339 if (blocks_func(start))
340 return false;
341 }
342 }
343
344 return true;
345 }
346
348
349 template <bool ONLY_VALID = true, typename FUNC>
350 auto apply(this auto&& self, glm::ivec2 to, FUNC&& func)
351 {
352 //if constexpr (ONLY_VALID) if (!is_valid(to)) return return_type{};
353 using self_type = std::remove_reference_t<decltype(self)>;
354 using tile_data_type = std::conditional_t<std::is_const_v<self_type>, std::add_const_t<typename self_type::tile_data_type>, typename self_type::tile_data_type>;
355 using invocable_type = std::remove_cvref_t<FUNC>;
356 if constexpr (std::invocable<invocable_type, glm::ivec2, tile_data_type&>)
357 return (ONLY_VALID && self.is_valid(to)) ? func(to, *self.at(to)) : decltype(func(to, *self.at(to))){};
358 else if constexpr (std::invocable<invocable_type, tile_data_type&, glm::ivec2>)
359 return (ONLY_VALID && self.is_valid(to)) ? func(*self.at(to), to) : decltype(func(*self.at(to), to)){};
360 else if constexpr (std::invocable<invocable_type, tile_data_type&>)
361 return (ONLY_VALID && self.is_valid(to)) ? func(*self.at(to)) : decltype(func(*self.at(to))){};
362 else
363 return (ONLY_VALID && self.is_valid(to)) ? func(to) : decltype(func(to)){};
364 }
365
366 void flip_row(int row)
367 {
368 if (row >= 0 && row < mHeight)
369 std::reverse(GetRowStart(row), GetRowStart(row) + mWidth);
370 }
371
372 void flip_horizontal()
373 {
374 for (int i = 0; i < mHeight; i++)
375 std::reverse(GetRowStart(i), GetRowStart(i) + mWidth);
376 }
377
378 void flip_vertical()
379 {
380 for (int i = 0; i < mHeight / 2; i++)
381 std::swap_ranges(GetRowStart(i), GetRowStart(i) + mWidth, GetRowStart(mHeight - i - 1));
382 }
383
384 void rotate_row(int row, int by);
385 void rotate_column(int column, int by);
386
387 void shift_row(int row, int by, TILE_DATA const& add_tile);
388 void shift_column(int column, int by, TILE_DATA const& add_tile);
389
390 void rotate_rows(int by);
391 void rotate_columns(int by);
392
393 void shift_rows(int by, TILE_DATA const& add_tile)
394 {
395 if (by == 0) return;
396 else if (by > 0)
397 {
398 auto num_elems_to_shift = by * mWidth;
399 std::move_backward(mTiles.begin(), mTiles.begin() + (mTiles.size() - num_elems_to_shift), mTiles.end());
400 std::ranges::fill_n(mTiles.begin(), num_elems_to_shift, add_tile);
401 }
402 else if (by < 0)
403 {
404 auto num_elems_to_shift = -by * mWidth;
405 std::move(mTiles.begin() + num_elems_to_shift, mTiles.end(), mTiles.begin());
406 std::ranges::fill_n(mTiles.begin() + (mTiles.size() - num_elems_to_shift), num_elems_to_shift, add_tile);
407 }
408 }
409 void shift_columns(int by, TILE_DATA const& add_tile);
410
411 void rotate_180() requires RESIZABLE
412 {
413 for (int i = 0; i < mHeight / 2; i++)
414 std::swap_ranges(std::make_reverse_iterator(GetRowStart(i) + mWidth), std::make_reverse_iterator(GetRowStart(i)), GetRowStart(mHeight - i - 1));
415
417 if (mHeight % 1)
418 std::reverse(GetRowStart(mHeight / 2 + 1), GetRowStart(mHeight / 2 + 1) + mWidth);
419 }
420
421 void resize(glm::uvec2 new_size, const TILE_DATA& new_element) requires RESIZABLE
422 {
423 ResizeY(new_size.y, new_element);
424 ResizeX(new_size.x, new_element);
425 }
426
427 void clear() { for (auto& tile : mTiles) tile = {}; }
428 void clear(TILE_DATA const& to) { for (auto& tile : mTiles) tile = to; }
429
430 protected:
431
432 auto GetRowStart(int row) { return mTiles.begin() + row * mWidth; }
433 auto GetTileIterator(int x, int y) { return mTiles.begin() + index(x, y); }
434
435 void Reset(int w, int h, TILE_DATA const& default_tile)
436 {
437 if (w < 0) throw std::invalid_argument{ "width cannot be negative" };
438 if (h < 0) throw std::invalid_argument{ "height cannot be negative" };
439
440 mTiles.clear();
441 mWidth = w;
442 mHeight = h;
443 mTiles.resize(w * h, default_tile);
444 }
445
446 template <change_tile_callback<TILE_DATA> TILE_RESET_FUNC>
447 void Reset(int w, int h, TILE_RESET_FUNC&& tile_reset)
448 {
449 if (w < 0) throw std::invalid_argument{ "width cannot be negative" };
450 if (h < 0) throw std::invalid_argument{ "height cannot be negative" };
451
452 mTiles.clear();
453 mWidth = w;
454 mHeight = h;
455 mTiles.resize(w * h);
456 for_each_tile(tile_reset);
457 //for_each_tile([&tile_reset](glm::ivec2 t, TILE_DATA& tile) { tile_reset(); });
458 }
459
460 void Reset(int w, int h)
461 {
462 if (w < 0) throw std::invalid_argument{ "width cannot be negative" };
463 if (h < 0) throw std::invalid_argument{ "height cannot be negative" };
464
465 mTiles.clear();
466 mWidth = w;
467 mHeight = h;
468 mTiles.resize(w * h);
469 }
470
471 void ResizeY(int new_y, const TILE_DATA& new_element)
472 {
473 if (new_y < 0) throw std::invalid_argument("new_y cannot be negative");
474
475 const auto new_count = new_y * mWidth;
476 mTiles.resize(new_count, new_element);
477 mHeight = new_y;
478 }
479
480 void ResizeX(int new_x, const TILE_DATA& new_element)
481 {
482 if (new_x < 0) throw std::invalid_argument("new_x cannot be negative");
484 /*
485 std::vector<T> new_vector;
486 new_vector.reserve(new_size);
487 for (size_t y=0; y<mHeight; ++y)
488 {
489 for (size_t x=0; x<mSize.x; ++x)
490 {
491 new_vector.push_back(std::move(mTiles[y * mSize.x + x]));
492 }
493 for (size_t x=mSize.x; x<new_x; ++x)
494 {
495 new_vector.push_back(new_element);
496 }
497 }
498 mTiles = std::move(new_vector);
499 */
500 const auto new_count = new_x * mHeight;
501
502 if (new_x > mWidth)
503 {
504 mTiles.resize(new_count, new_element);
505
506 for (int yy = 0; yy < mHeight; ++yy)
507 {
508 auto y = mHeight - yy - 1;
509 const auto begin_range = y * mWidth;
510 const auto end_range = begin_range + mWidth;
511 const auto new_end_range = y * new_x + mWidth;
512 std::swap_ranges(std::make_reverse_iterator(mTiles.begin() + end_range), std::make_reverse_iterator(mTiles.begin() + begin_range), std::make_reverse_iterator(mTiles.begin() + new_end_range));
513 }
514 }
515 else
516 {
517 const auto dif = mWidth - new_x;
518 for (int y = 1; y < mHeight; ++y)
519 {
520 const auto begin_range = y * mWidth;
521 const auto end_range = begin_range + new_x;
522 std::move(mTiles.begin() + begin_range, mTiles.begin() + end_range, mTiles.begin() + begin_range - (dif * y));
523 }
524 mTiles.resize(new_count);
525 }
526
527 mWidth = new_x;
528 }
529
530 int mWidth = 0;
531 int mHeight = 0;
532 std::vector<TILE_DATA> mTiles;
533 };
534
535}
constexpr auto bit_count
Equal to the number of bits in the type.
Definition bits.h:33
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:59
constexpr bool valid_index(random_access_range auto &range, std::integral auto index)
Returns whether or not a given integer is a valid index to a random access range
Definition ranges.h:37
constexpr CONTAINER to(RANGE &&range, TYPES &&... args)
to<container>();
Definition ranges.h:369
A (constexpr) value struct that represents a set of bits mapped to an enum (implemented as a bitset)
Definition enum_flags.h:29