diff options
author | Loek Le Blansch <loek@pipeframe.xyz> | 2024-10-23 19:16:19 +0200 |
---|---|---|
committer | Loek Le Blansch <loek@pipeframe.xyz> | 2024-10-23 19:16:19 +0200 |
commit | 1e0a52b03fe655d7073ef20703dbb2e7646f74d3 (patch) | |
tree | f1709c2e9565d78c791653e71e6a4b26b3138423 | |
parent | 277157b3e06b2deeacbdbc8bf6190de19f88169d (diff) |
add XY struct for 2d points and offsets
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | Canvas.cpp | 56 | ||||
-rw-r--r-- | Canvas.h | 7 | ||||
-rw-r--r-- | Exception.cpp | 14 | ||||
-rw-r--r-- | Exception.h | 6 | ||||
-rw-r--r-- | PathfindingContext.cpp | 27 | ||||
-rw-r--r-- | PathfindingContext.h | 16 | ||||
-rw-r--r-- | SetNeighborTileBehavior.cpp | 16 | ||||
-rw-r--r-- | SetNeighborTileBehavior.h | 4 | ||||
-rw-r--r-- | StepTileCommand.cpp | 10 | ||||
-rw-r--r-- | StepTileCommand.h | 8 | ||||
-rw-r--r-- | Tile.cpp | 19 | ||||
-rw-r--r-- | Tile.h | 3 | ||||
-rw-r--r-- | ViewController.cpp | 16 | ||||
-rw-r--r-- | ViewController.h | 5 | ||||
-rw-r--r-- | XY.cpp | 35 | ||||
-rw-r--r-- | XY.h | 13 |
17 files changed, 157 insertions, 99 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 034f9ee..51a2557 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,6 +55,7 @@ add_executable(main NaiveCollisionChecker.cpp CycleCollisionMethodCommand.cpp PathfindingContext.cpp + XY.cpp ) target_link_libraries(main @@ -1,7 +1,9 @@ +#include <cassert> #include <cstdio> #include <string> #include "Canvas.h" +#include "Exception.h" #include "util.h" #include "Museum.h" @@ -9,20 +11,32 @@ using namespace std; Canvas::Canvas(Museum & museum) : museum(museum), tile_behavior(museum), tile_color() { } -Tile & Canvas::get_tile(unsigned x, unsigned y) { - return *this->tiles[this->pos_to_index(x, y)]; +Tile * & Canvas::get_tile_unsafe(const XY & pos) { + size_t index = pos.y * this->data.columns + pos.x; + return this->tiles[index]; } -void Canvas::set_tile(TileData data) { - size_t index = this->pos_to_index(data.x, data.y); - if (this->tiles[index] != nullptr) - delete this->tiles[index]; - this->tiles[index] = new Tile(this->museum, data); +Tile & Canvas::get_tile(const XY & pos) { + Exception outside_range("get_tile: position (%d, %d) outside canvas", pos.x, pos.y); + if (pos.x < 0) throw outside_range; + if (pos.y < 0) throw outside_range; + if (pos.x >= this->data.columns) throw outside_range; + if (pos.y >= this->data.rows) throw outside_range; + + Tile * tile = get_tile_unsafe(pos); + assert(tile != nullptr); + + return *tile; } -size_t Canvas::pos_to_index(unsigned x, unsigned y) { - size_t index = y * this->data.columns + x; - return index; +void Canvas::set_tile(TileData data) { + Tile * & tile = this->get_tile_unsafe({ + static_cast<int>(data.x), + static_cast<int>(data.y) + }); + if (tile != nullptr) + delete tile; + tile = new Tile(this->museum, data); } void Canvas::update() { @@ -33,9 +47,9 @@ void Canvas::update() { void Canvas::set_data(CanvasData data) { this->data = data; this->tiles.resize(this->data.rows * this->data.columns); - for (size_t y = 0; y < this->data.rows; y++) { - for (size_t x = 0; x < this->data.columns; x++) { - if (this->tiles[this->pos_to_index(x, y)] != nullptr) + for (int y = 0; y < this->data.rows; y++) { + for (int x = 0; x < this->data.columns; x++) { + if (this->get_tile_unsafe({ x, y }) != nullptr) continue; this->set_tile({ .x = static_cast<unsigned int>(x), @@ -56,15 +70,15 @@ Canvas::~Canvas() { string Canvas::to_string(bool truecolor) { string out = ""; - for (size_t y = 0; y < this->data.rows; y++) { - for (size_t x = 0; x < this->data.columns; x++) { - Tile & tile = this->get_tile(x, y); - string type_str = tile.data.type; + for (int y = 0; y < this->data.rows; y++) { + for (int x = 0; x < this->data.columns; x++) { + Tile * tile = this->get_tile_unsafe({ x, y }); + string type_str = tile->data.type; if (type_str.length() == 0) type_str = "."; if (truecolor) out += stringf("\e[38;2;0;0;0;48;2;%d;%d;%dm", - tile.color.red, tile.color.green, tile.color.blue); + tile->color.red, tile->color.green, tile->color.blue); out += stringf("%-2s ", type_str.c_str()); } @@ -80,7 +94,11 @@ void Canvas::update_steps() { if (artist->step == false) continue; artist->step = false; - this->get_tile(artist->data.x, artist->data.y).behavior->step(artist); + Tile * tile = this->get_tile_unsafe({ + static_cast<int>(artist->data.x), + static_cast<int>(artist->data.y) + }); + tile->behavior->step(artist); } } @@ -5,6 +5,7 @@ #include "CanvasData.h" #include "Tile.h" +#include "XY.h" #include "TileBehaviorFactory.h" #include "TileColorFactory.h" @@ -18,7 +19,7 @@ public: std::string to_string(bool truecolor = false); public: - virtual Tile & get_tile(unsigned x, unsigned y); + virtual Tile & get_tile(const XY &); virtual void set_tile(TileData data); public: @@ -36,9 +37,9 @@ private: private: std::vector<Tile *> tiles; - Museum & museum; + virtual Tile * & get_tile_unsafe(const XY &); private: - size_t pos_to_index(unsigned x, unsigned y); + Museum & museum; }; diff --git a/Exception.cpp b/Exception.cpp index d9765da..423f4e9 100644 --- a/Exception.cpp +++ b/Exception.cpp @@ -4,25 +4,21 @@ #include "Exception.h" -Exception::~Exception() { - if (error != NULL) - free(error); -} +using namespace std; const char * Exception::what() { - return error; + return error.get(); } void Exception::va_format(va_list args, const char * fmt) { va_list args_copy; va_copy(args_copy, args); - size_t sz = vsnprintf(NULL, 0, fmt, args_copy) + 1; - if (error != NULL) free(error); - error = (char *) malloc(sz); va_end(args_copy); - vsnprintf(error, sz, fmt, args); + this->error = unique_ptr<char>(static_cast<char *>(malloc(sz))); + + vsnprintf(this->error.get(), sz, fmt, args); } Exception::Exception(const char * fmt, ...) { diff --git a/Exception.h b/Exception.h index 31c517b..633cb4f 100644 --- a/Exception.h +++ b/Exception.h @@ -2,16 +2,16 @@ #include <cstdarg> #include <exception> +#include <memory> class Exception : public std::exception { public: Exception(const char * fmt, ...); - virtual ~Exception(); - virtual const char * what(); + const char * what(); protected: Exception() = default; void va_format(va_list args, const char * fmt); - char * error = NULL; + std::unique_ptr<char> error = NULL; }; diff --git a/PathfindingContext.cpp b/PathfindingContext.cpp index a1d31f6..cfebb44 100644 --- a/PathfindingContext.cpp +++ b/PathfindingContext.cpp @@ -1,4 +1,5 @@ #include "PathfindingContext.h" +#include "XY.h" #include "Museum.h" #include "NullTileBehavior.h" @@ -6,28 +7,26 @@ using namespace std; PathfindingContext::PathfindingContext(Museum & m) : museum(m) {} -void PathfindingContext::set_start(const pair<int, int> & point) { +void PathfindingContext::set_start(const XY & point) { if (!this->valid_point(point)) return; this->start_point = point; } -void PathfindingContext::set_end(const pair<int, int> & point) { +void PathfindingContext::set_end(const XY & point) { if (!this->valid_point(point)) return; this->end_point = point; } -bool PathfindingContext::valid_point(const std::pair<int, int> & point) { - // check if out of bounds - Canvas & canvas = this->museum.canvas; - if (point.first < 0) return false; - if (point.second < 0) return false; - if (point.first >= canvas.data.columns) return false; - if (point.second >= canvas.data.rows) return false; - - // check if square is empty (has null behavior) - Tile & tile = canvas.get_tile(point.first, point.second); - TileBehavior * behavior = tile.behavior.get(); - if (dynamic_cast<NullTileBehavior *>(behavior) != nullptr) return false; +bool PathfindingContext::valid_point(const XY & point) { + try { + // check if square is empty (has null behavior) + Tile & tile = this->museum.canvas.get_tile(point); + TileBehavior * behavior = tile.behavior.get(); + if (dynamic_cast<NullTileBehavior *>(behavior) != nullptr) return false; + } catch (...) { + // get_tile throws an exception if the point is outside the canvas bounds + return false; + } return true; } diff --git a/PathfindingContext.h b/PathfindingContext.h index ce46a55..19fd93d 100644 --- a/PathfindingContext.h +++ b/PathfindingContext.h @@ -1,6 +1,6 @@ #pragma once -#include <utility> +#include "XY.h" class Museum; @@ -9,15 +9,15 @@ public: PathfindingContext(Museum &); public: - void set_start(const std::pair<int, int> & point); - const std::pair<int, int> & get_start() { return this->start_point; } - void set_end(const std::pair<int, int> & point); - const std::pair<int, int> & get_end() { return this->end_point; } - bool valid_point(const std::pair<int, int> & point); + void set_start(const XY & point); + const XY & get_start() { return this->start_point; } + void set_end(const XY & point); + const XY & get_end() { return this->end_point; } + bool valid_point(const XY & point); private: - std::pair<int, int> start_point = { -1, -1 }; - std::pair<int, int> end_point = { -1, -1 }; + XY start_point = { -1, -1 }; + XY end_point = { -1, -1 }; private: Museum & museum; diff --git a/SetNeighborTileBehavior.cpp b/SetNeighborTileBehavior.cpp index 7b7ede7..0314e42 100644 --- a/SetNeighborTileBehavior.cpp +++ b/SetNeighborTileBehavior.cpp @@ -8,16 +8,16 @@ using namespace std; void SetNeighborTileBehavior::step(Artist * artist) { this->interactions++; - if (dx != 0 || dy != 0) return; + if (this->offset.x != 0 || this->offset.y != 0) return; if (artist == nullptr) return; - if (artist->data.vx == 0) dx = 1; - if (artist->data.vy == 0) dy = 1; + if (artist->data.vx == 0) this->offset.x = 1; + if (artist->data.vy == 0) this->offset.y = 1; } -static void update_neighbor(Tile & here, int dx, int dy) { - if (dx == 0 && dy == 0) return; - Tile * neighbor = here.get_neighbor(dx, dy); +static void update_neighbor(Tile & here, const XY & offset) { + if (offset.x == 0 && offset.y == 0) return; + Tile * neighbor = here.get_neighbor(offset); if (neighbor == &here) return; if (neighbor == nullptr) return; @@ -28,8 +28,8 @@ static void update_neighbor(Tile & here, int dx, int dy) { void SetNeighborTileBehavior::update(Tile & tile) { if (this->interactions < 1) return; - update_neighbor(tile, this->dx, this->dy); - update_neighbor(tile, -this->dx, -this->dy); + update_neighbor(tile, this->offset); + update_neighbor(tile, -this->offset); tile.set_type(CreateArtistTileBehavior::type); } diff --git a/SetNeighborTileBehavior.h b/SetNeighborTileBehavior.h index 53bfbc0..c52edf3 100644 --- a/SetNeighborTileBehavior.h +++ b/SetNeighborTileBehavior.h @@ -1,6 +1,7 @@ #pragma once #include "TileBehavior.h" +#include "XY.h" class SetNeighborTileBehavior : public TileBehavior { friend class TileBehaviorFactory; @@ -13,7 +14,6 @@ public: static constexpr const char * type = "B"; private: - int dx = 0; - int dy = 0; + XY offset = { 0, 0 }; }; diff --git a/StepTileCommand.cpp b/StepTileCommand.cpp index bac9f5d..beefd34 100644 --- a/StepTileCommand.cpp +++ b/StepTileCommand.cpp @@ -3,16 +3,10 @@ using namespace std; -StepTileCommand::StepTileCommand(Canvas & c, pair<unsigned int, unsigned int> tile) : canvas(c) { - this->x = tile.first; - this->y = tile.second; -} +StepTileCommand::StepTileCommand(Canvas & c, const XY & tile) : canvas(c), tile_pos(tile) { } void StepTileCommand::execute() { - Canvas & canvas = this->canvas; - if (this->x >= canvas.data.columns) return; - if (this->y >= canvas.data.rows) return; - Tile & tile = canvas.get_tile(this->x, this->y); + Tile & tile = this->canvas.get_tile(this->tile_pos); tile.behavior->step(nullptr); tile.update(); } diff --git a/StepTileCommand.h b/StepTileCommand.h index 24d0b36..c9a2d8b 100644 --- a/StepTileCommand.h +++ b/StepTileCommand.h @@ -1,21 +1,19 @@ #pragma once -#include <utility> - #include "Command.h" +#include "XY.h" class Canvas; class StepTileCommand : public Command { public: - StepTileCommand(Canvas & c, std::pair<unsigned int, unsigned int> tile); + StepTileCommand(Canvas & c, const XY & tile); public: virtual void execute(); private: Canvas & canvas; - unsigned int x; - unsigned int y; + XY tile_pos; }; @@ -28,14 +28,15 @@ void Tile::update() { this->behavior->update(*this); } -Tile * Tile::get_neighbor(int dx, int dy) { - Canvas & canvas = this->museum.canvas; - int x = this->data.x + dx; - int y = this->data.y + dy; - if (x < 0) return nullptr; - if (x >= canvas.data.columns) return nullptr; - if (y < 0) return nullptr; - if (y >= canvas.data.columns) return nullptr; - return &canvas.get_tile(x, y); +Tile * Tile::get_neighbor(const XY & offset) { + XY here { + .x = static_cast<int>(this->data.x), + .y = static_cast<int>(this->data.y), + }; + try { + return &this->museum.canvas.get_tile(here + offset); + } catch (...) { + return nullptr; + } } @@ -5,6 +5,7 @@ #include "TileData.h" #include "Color.h" #include "TileBehavior.h" +#include "XY.h" class Museum; @@ -21,7 +22,7 @@ public: void set_data(TileData & data); void set_type(const std::string & type); void update(); - Tile * get_neighbor(int dx, int dy); + Tile * get_neighbor(const XY & offset); private: Museum & museum; diff --git a/ViewController.cpp b/ViewController.cpp index 67fd77c..40e624a 100644 --- a/ViewController.cpp +++ b/ViewController.cpp @@ -39,9 +39,9 @@ void ViewController::update_size() { } void ViewController::update_tiles() { - for (unsigned y = 0; y < this->museum.canvas.data.rows; y++) { - for (unsigned x = 0; x < this->museum.canvas.data.columns; x++) { - Tile & tile = this->museum.canvas.get_tile(x, y); + for (int y = 0; y < this->museum.canvas.data.rows; y++) { + for (int x = 0; x < this->museum.canvas.data.columns; x++) { + Tile & tile = this->museum.canvas.get_tile({ x, y }); Rectangle rect = { .x = static_cast<float>(x * scale), .y = static_cast<float>(y * scale), @@ -66,10 +66,10 @@ void ViewController::update_artists() { } } -void ViewController::draw_pathfinding_dot(pair<unsigned int, unsigned int> point, const Color & color) { +void ViewController::draw_pathfinding_dot(const XY & point, const Color & color) { this->view.fill_rect(center({ - .x = static_cast<float>(point.first * scale), - .y = static_cast<float>(point.second * scale), + .x = static_cast<float>(point.x * scale), + .y = static_cast<float>(point.y * scale), .width = static_cast<float>(pathfinding_size), .height = static_cast<float>(pathfinding_size), }), color); @@ -177,8 +177,8 @@ void ViewController::ev_mousedown(MouseCode button) { void ViewController::ev_mousemove(unsigned x, unsigned y) { this->mouse_pos = { - static_cast<float>(x) / static_cast<float>(this->scale), - static_cast<float>(y) / static_cast<float>(this->scale), + .x = static_cast<int>(x / this->scale), + .y = static_cast<int>(y / this->scale), }; } diff --git a/ViewController.h b/ViewController.h index f05d62b..d50dfb1 100644 --- a/ViewController.h +++ b/ViewController.h @@ -7,6 +7,7 @@ #include "KeyboardCode.h" #include "MouseCode.h" #include "Rectangle.h" +#include "XY.h" class View; class Museum; @@ -32,7 +33,7 @@ private: void update_quadtree_recursive(QuadTreeCollisionChecker * tree); private: - void draw_pathfinding_dot(std::pair<unsigned int, unsigned int>, const Color &); + void draw_pathfinding_dot(const XY &, const Color &); Rectangle center(Rectangle); private: @@ -52,6 +53,6 @@ private: unsigned int pathfinding_size = scale - 4; private: - std::pair<float, float> mouse_pos = { 0, 0 }; + XY mouse_pos; }; @@ -0,0 +1,35 @@ +#include "XY.h" + +XY XY::operator - () const { + return XY { + .x = -x, + .y = -y, + }; +} + +XY XY::operator + (const XY & rhs) const { + return XY { + .x = x + rhs.x, + .y = y + rhs.y, + }; +} + +XY XY::operator - (const XY & rhs) const { + return XY { + .x = x - rhs.x, + .y = y - rhs.y, + }; +} + +XY& XY::operator += (const XY & rhs) { + this->x += rhs.x; + this->y += rhs.y; + return *this; +} + +XY& XY::operator -= (const XY & rhs) { + this->x -= rhs.x; + this->y -= rhs.y; + return *this; +} + @@ -0,0 +1,13 @@ +#pragma once + +struct XY { + int x = 0; + int y = 0; + + XY operator + (const XY &) const; + XY operator - () const; + XY operator - (const XY &) const; + XY& operator += (const XY &); + XY& operator -= (const XY &); +}; + |