From 1e0a52b03fe655d7073ef20703dbb2e7646f74d3 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Wed, 23 Oct 2024 19:16:19 +0200 Subject: add XY struct for 2d points and offsets --- CMakeLists.txt | 1 + Canvas.cpp | 56 ++++++++++++++++++++++++++++++--------------- Canvas.h | 7 +++--- Exception.cpp | 14 ++++-------- Exception.h | 6 ++--- PathfindingContext.cpp | 27 +++++++++++----------- PathfindingContext.h | 16 ++++++------- SetNeighborTileBehavior.cpp | 16 ++++++------- SetNeighborTileBehavior.h | 4 ++-- StepTileCommand.cpp | 10 ++------ StepTileCommand.h | 8 +++---- Tile.cpp | 19 +++++++-------- Tile.h | 3 ++- ViewController.cpp | 16 ++++++------- ViewController.h | 5 ++-- XY.cpp | 35 ++++++++++++++++++++++++++++ XY.h | 13 +++++++++++ 17 files changed, 157 insertions(+), 99 deletions(-) create mode 100644 XY.cpp create mode 100644 XY.h 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 diff --git a/Canvas.cpp b/Canvas.cpp index ce51e5c..b7cc8a5 100644 --- a/Canvas.cpp +++ b/Canvas.cpp @@ -1,7 +1,9 @@ +#include #include #include #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(data.x), + static_cast(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(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(artist->data.x), + static_cast(artist->data.y) + }); + tile->behavior->step(artist); } } diff --git a/Canvas.h b/Canvas.h index 6f59c15..e25c4b9 100644 --- a/Canvas.h +++ b/Canvas.h @@ -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 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(static_cast(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 #include +#include 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 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 & point) { +void PathfindingContext::set_start(const XY & point) { if (!this->valid_point(point)) return; this->start_point = point; } -void PathfindingContext::set_end(const pair & 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 & 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(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(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 +#include "XY.h" class Museum; @@ -9,15 +9,15 @@ public: PathfindingContext(Museum &); public: - void set_start(const std::pair & point); - const std::pair & get_start() { return this->start_point; } - void set_end(const std::pair & point); - const std::pair & get_end() { return this->end_point; } - bool valid_point(const std::pair & 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 start_point = { -1, -1 }; - std::pair 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 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 - #include "Command.h" +#include "XY.h" class Canvas; class StepTileCommand : public Command { public: - StepTileCommand(Canvas & c, std::pair tile); + StepTileCommand(Canvas & c, const XY & tile); public: virtual void execute(); private: Canvas & canvas; - unsigned int x; - unsigned int y; + XY tile_pos; }; diff --git a/Tile.cpp b/Tile.cpp index cd1e820..92da9e7 100644 --- a/Tile.cpp +++ b/Tile.cpp @@ -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(this->data.x), + .y = static_cast(this->data.y), + }; + try { + return &this->museum.canvas.get_tile(here + offset); + } catch (...) { + return nullptr; + } } diff --git a/Tile.h b/Tile.h index ccf8d3b..7e44b09 100644 --- a/Tile.h +++ b/Tile.h @@ -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(x * scale), .y = static_cast(y * scale), @@ -66,10 +66,10 @@ void ViewController::update_artists() { } } -void ViewController::draw_pathfinding_dot(pair point, const Color & color) { +void ViewController::draw_pathfinding_dot(const XY & point, const Color & color) { this->view.fill_rect(center({ - .x = static_cast(point.first * scale), - .y = static_cast(point.second * scale), + .x = static_cast(point.x * scale), + .y = static_cast(point.y * scale), .width = static_cast(pathfinding_size), .height = static_cast(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(x) / static_cast(this->scale), - static_cast(y) / static_cast(this->scale), + .x = static_cast(x / this->scale), + .y = static_cast(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, 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 mouse_pos = { 0, 0 }; + XY mouse_pos; }; diff --git a/XY.cpp b/XY.cpp new file mode 100644 index 0000000..ad1262b --- /dev/null +++ b/XY.cpp @@ -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; +} + diff --git a/XY.h b/XY.h new file mode 100644 index 0000000..2aac824 --- /dev/null +++ b/XY.h @@ -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 &); +}; + -- cgit v1.2.3