fix(hexgrid): Removing hexgrid

Hexgrids are not currently functional, so it is being removed
This commit is contained in:
James P. Howard, II
2023-01-19 08:46:44 -05:00
parent 5d58df48b2
commit f333f96bca
3 changed files with 1 additions and 577 deletions

View File

@@ -1,326 +0,0 @@
/*-
* Copyright (c) 2022 The Johns Hopkins University Applied Physics
* Laboratory LLC
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
#ifndef KAMI_HEXGRID_H
//! @cond SuppressGuard
#define KAMI_HEXGRID_H
//! @endcond
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <map>
#include <memory>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <kami/domain.h>
#include <kami/grid.h>
#include <kami/kami.h>
namespace kami {
/**
* @brief Two-dimensional coordinates
*/
class LIBKAMI_EXPORT HexCoord : public GridCoord {
protected:
inline double distance_chebyshev(std::shared_ptr<HexCoord> &p) const {
return static_cast<double>(fmax(abs(_x_coord - p->_x_coord), abs(_x_coord - p->_x_coord)));
};
inline double distance_euclidean(std::shared_ptr<HexCoord> &p) const {
return sqrt(pow(_x_coord - p->_x_coord, 2) + pow(_x_coord - p->_x_coord, 2));
};
inline double distance_manhattan(std::shared_ptr<HexCoord> &p) const {
return static_cast<double>(abs(_x_coord - p->_x_coord) + abs(_x_coord - p->_x_coord));
};
public:
/**
* @brief Constructor for two-dimensional coordinates
*/
HexCoord(int x_coord, int y_coord)
: _x_coord(x_coord), _y_coord(y_coord) {};
/**
* @brief Get the coordinate in the first dimension or `x`.
*/
[[nodiscard]] int get_x_location() const;
/**
* @brief Get the coordinate in the second dimension or `y`.
*/
[[nodiscard]] int get_y_location() const;
/**
* @brief Convert the coordinate to a human-readable string.
*
* @return a human-readable form of the `Coord` as `std::string`.
*/
[[nodiscard]] std::string to_string() const override;
/**
* @brief Find the distance between two points
*
* @details Find the distance between two points using the
* specified metric. There are three options provided by
* the `GridDistanceType` class.
*
* However, the coordinate class is not aware of the
* properties of the `HexGrid` it is operating on. Accordingly,
* if the direct path is measured, without accounting for
* and toroidal wrapping of the underlying `HexGrid`.
*
* @param p the point to measure the distance to
* @param distance_type specify the distance type
*
* @returns the distance as a `double`
*/
std::optional<double> distance(std::shared_ptr<Coord> &p, GridDistanceType distance_type) const override;
/**
* @brief Test if two coordinates are equal
*/
friend bool operator==(const HexCoord &, const HexCoord &);
/**
* @brief Test if two coordinates are not equal
*/
friend bool operator!=(const HexCoord &, const HexCoord &);
/**
* @brief Output a given coordinate to the specified stream
*/
friend std::ostream &operator<<(std::ostream &, const HexCoord &);
private:
int _x_coord, _y_coord;
};
/**
* @brief A two-dimensional grid where each cell may contain agents
*
* @details The grid is linear and may wrap around in its only dimension.
*
* @see `MultiHexGrid`
* @see `SoloHexGrid`
*/
class LIBKAMI_EXPORT HexGrid : public GridDomain {
public:
/**
* @brief Constructor
*
* @param[in] maximum_x the length of the grid in the first dimension
* @param[in] maximum_y the length of the grid in the second dimension
* @param[in] wrap_x should the grid wrap around on itself in the first
* dimension
* @param[in] wrap_y should the grid wrap around on itself in the second
* dimension
*/
explicit HexGrid(unsigned int maximum_x, unsigned int maximum_y, bool wrap_x = false, bool wrap_y = false);
/**
* @brief Place agent on the grid at the specified location.
*
* @param[in] agent_id the `AgentID` of the agent to add.
* @param[in] coord the coordinates of the agent.
*
* @returns false if the agent is not placed at the specified
* location, otherwise, true.
*/
virtual std::optional<AgentID> add_agent(const AgentID agent_id, const HexCoord &coord) = 0;
/**
* @brief Remove agent from the grid.
*
* @param[in] agent_id the `AgentID` of the agent to remove.
*
* @returns false if the agent is not removed, otherwise, true.
*/
std::optional<AgentID> delete_agent(const AgentID agent_id);
/**
* @brief Remove agent from the grid at the specified location
*
* @param[in] agent_id the `AgentID` of the agent to remove.
* @param[in] coord the coordinates of the agent.
*
* @returns false if the agent is not removed, otherwise, true.
*/
std::optional<AgentID> delete_agent(const AgentID agent_id, const HexCoord &coord);
/**
* @brief Move an agent to the specified location.
*
* @param[in] agent_id the `AgentID` of the agent to move.
* @param[in] coord the coordinates of the agent.
*/
std::optional<AgentID> move_agent(const AgentID agent_id, const HexCoord &coord);
/**
* @brief Inquire if the specified location is empty.
*
* @param[in] coord the coordinates of the query.
*
* @return true if the location has no `Agent`s occupying it, false
* otherwise.
*/
[[nodiscard]] bool is_location_empty(const HexCoord &coord) const;
/**
* @brief Inquire if the specified location is valid within the grid.
*
* @param[in] coord the coordinates of the query.
*
* @return true if the location specified is valid, false otherwise.
*/
[[nodiscard]] bool is_location_valid(const HexCoord &coord) const;
/**
* @brief Get the location of the specified agent.
*
* @param[in] agent_id the `AgentID` of the agent in question.
*
* @return the location of the specified `Agent`
*/
[[nodiscard]] std::optional<HexCoord> get_location_by_agent(const AgentID &agent_id) const;
/**
* @brief Get the contents of the specified location.
*
* @param[in] coord the coordinates of the query.
*
* @return a pointer to a `set` of `AgentID`s. The pointer is to the
* internal copy of the agent list at the location, therefore, any changes
* to that object will update the state of the gird. Further, the pointer
* should not be deleted when no longer used.
*/
[[nodiscard]] std::optional<std::shared_ptr<std::set<AgentID>>>
get_location_contents(const HexCoord &coord) const;
/**
* @brief Inquire to whether the grid wraps in the `x` dimension.
*
* @return true if the grid wraps, and false otherwise
*/
[[nodiscard]] bool get_wrap_x() const;
/**
* @brief Inquire to whether the grid wraps in the `y` dimension.
*
* @return true if the grid wraps, and false otherwise
*/
[[nodiscard]] bool get_wrap_y() const;
/**
* @brief Return the neighborhood of the specified Agent
*
* @param[in] agent_id the `AgentID` of the agent in question.
* @param[in] neighborhood_type the neighborhood type.
* @param[in] include_center should the center-point, occupied by the agent,
* be in the list.
*
* @return a set of `GridCoord1D` that includes all of the coordinates
* for all adjacent points.
*
* @see `NeighborhoodType`
*/
[[nodiscard]] std::optional<std::shared_ptr<std::unordered_set<HexCoord>>>
get_neighborhood(AgentID agent_id, bool include_center, GridNeighborhoodType neighborhood_type) const;
/**
* @brief Return the neighborhood of the specified location
*
* @param[in] coord the coordinates of the specified location.
* @param[in] neighborhood_type the neighborhood type.
* @param[in] include_center should the center-point, occupied by the agent,
* be in the list.
*
* @return a set of `HexCoord` that includes all of the coordinates
* for all adjacent points.
*
* @see `NeighborhoodType`
*/
[[nodiscard]] std::optional<std::shared_ptr<std::unordered_set<HexCoord>>>
get_neighborhood(const HexCoord &coord, bool include_center, GridNeighborhoodType neighborhood_type) const;
/**
* @brief Get the size of the grid in the `x` dimension.
*
* @return the length of the grid in the `x` dimension
*/
[[nodiscard]] unsigned int get_maximum_x() const;
/**
* @brief Get the size of the grid in the `y` dimension.
*
* @return the length of the grid in the `xy dimension
*/
[[nodiscard]] unsigned int get_maximum_y() const;
protected:
/**
* @brief A map containing the `AgentID`s of all agents assigned to this
* grid.
*/
std::unique_ptr<std::unordered_multimap<HexCoord, AgentID>> _agent_grid;
/**
* @brief A map containing the grid location of each agent.
*/
std::unique_ptr<std::map<AgentID, HexCoord>> _agent_index;
/**
* @brief Automatically adjust a coordinate location for wrapping.
*
* @param[in] coord the coordinates of the specified location.
*
* @return the adjusted coordinate wrapped if appropriate.
*/
[[nodiscard]] HexCoord coord_wrap(const HexCoord &coord) const;
private:
unsigned int _maximum_x, _maximum_y;
bool _wrap_x, _wrap_y;
};
} // namespace kami
//! @cond SuppressHashMethod
namespace std {
template<>
struct hash<kami::HexCoord> {
size_t operator()(const kami::HexCoord &key) const {
return ((hash<int>()(key.get_x_location()) ^ (hash<int>()(key.get_y_location()) << 1)) >> 1);
}
};
} // namespace std
//! @endcond
#endif // KAMI_HEXGRID_H

View File

@@ -33,14 +33,12 @@
#include <kami/grid1d.h>
#include <kami/grid2d.h>
#include <kami/hexgrid.h>
namespace kami {
typedef std::variant<
GridCoord1D,
GridCoord2D,
HexCoord
GridCoord2D
> Position;
}

View File

@@ -1,248 +0,0 @@
/*-
* Copyright (c) 2022 The Johns Hopkins University Applied Physics
* Laboratory LLC
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <kami/agent.h>
#include <kami/domain.h>
#include <kami/hexgrid.h>
#include <map>
#include <memory>
#include <optional>
#include <unordered_map>
#include <utility>
#include <vector>
namespace kami {
int HexCoord::get_x_location() const {
return _x_coord;
}
int HexCoord::get_y_location() const {
return _y_coord;
}
std::string HexCoord::to_string() const {
return std::string("(" + std::to_string(_x_coord) + ", " + std::to_string(_y_coord) + ")");
}
std::optional<double> HexCoord::distance(std::shared_ptr<Coord> &p, GridDistanceType distance_type) const {
auto p2d = std::static_pointer_cast<HexCoord>(p);
switch (distance_type) {
case GridDistanceType::Chebyshev:
return distance_chebyshev(p2d);
case GridDistanceType::Manhattan:
return distance_manhattan(p2d);
case GridDistanceType::Euclidean:
return distance_euclidean(p2d);
}
return std::nullopt;
}
bool operator==(const HexCoord &lhs, const HexCoord &rhs) {
return (lhs._x_coord == rhs._x_coord && lhs._y_coord == rhs._y_coord);
}
bool operator!=(const HexCoord &lhs, const HexCoord &rhs) {
return !(lhs == rhs);
}
std::ostream &operator<<(std::ostream &lhs, const HexCoord &rhs) {
return lhs << rhs.to_string();
}
HexGrid::HexGrid(unsigned int maximum_x, unsigned int maximum_y, bool wrap_x,
bool wrap_y) {
_maximum_x = maximum_x;
_maximum_y = maximum_y;
_wrap_x = wrap_x;
_wrap_y = wrap_y;
_agent_grid = std::make_unique<std::unordered_multimap<HexCoord, AgentID>>();
_agent_index = std::make_unique<std::map<AgentID, HexCoord>>();
}
std::optional<AgentID> HexGrid::delete_agent(AgentID agent_id) {
auto coord = get_location_by_agent(agent_id);
if (!coord)
return std::nullopt;
return delete_agent(agent_id, coord.value());
}
std::optional<AgentID> HexGrid::delete_agent(AgentID agent_id, const HexCoord &coord) {
auto agent_location = _agent_grid->find(coord);
if (agent_location == _agent_grid->end())
return std::nullopt;
for (auto test_agent_id = agent_location; test_agent_id != _agent_grid->end(); test_agent_id++)
if (test_agent_id->second == agent_id) {
_agent_grid->erase(test_agent_id);
_agent_index->erase(agent_id);
return agent_id;
}
return std::nullopt;
}
bool HexGrid::is_location_valid(const HexCoord &coord) const {
auto x = coord.get_x_location();
auto y = coord.get_y_location();
return (x >= 0 && x < static_cast<int>(_maximum_x) &&
y >= 0 && y < static_cast<int>(_maximum_y));
}
bool HexGrid::is_location_empty(const HexCoord &coord) const {
auto grid_location = _agent_grid->equal_range(coord);
return grid_location.first == grid_location.second;
}
std::optional<AgentID> HexGrid::move_agent(const AgentID agent_id, const HexCoord &coord) {
auto coord_current = get_location_by_agent(agent_id);
if (!coord_current)
return std::nullopt;
if (!delete_agent(agent_id, coord_current.value()))
return std::nullopt;
return add_agent(agent_id, coord);
}
std::optional<std::shared_ptr<std::unordered_set<HexCoord>>>
HexGrid::get_neighborhood(const AgentID agent_id, const bool include_center,
const GridNeighborhoodType neighborhood_type) const {
auto coord = get_location_by_agent(agent_id);
if (!coord)
return std::nullopt;
return std::move(get_neighborhood(coord.value(), include_center, neighborhood_type));
}
std::optional<std::shared_ptr<std::unordered_set<HexCoord>>>
HexGrid::get_neighborhood(const HexCoord &coord, const bool include_center,
const GridNeighborhoodType neighborhood_type) const {
auto neighborhood = std::make_unique<std::unordered_set<HexCoord>>();
auto x = coord.get_x_location();
auto y = coord.get_y_location();
// We assume our starting position is valid
if (include_center)
neighborhood->insert(coord);
// N, E, S, W
{
auto new_location = coord_wrap(HexCoord(x, y - 1));
if (is_location_valid(new_location))
neighborhood->insert(coord_wrap(new_location));
}
{
auto new_location = coord_wrap(HexCoord(x, y + 1));
if (is_location_valid(new_location))
neighborhood->insert(coord_wrap(new_location));
}
{
auto new_location = coord_wrap(HexCoord(x + 1, y));
if (is_location_valid(new_location))
neighborhood->insert(coord_wrap(new_location));
}
{
auto new_location = coord_wrap(HexCoord(x - 1, y));
if (is_location_valid(new_location))
neighborhood->insert(coord_wrap(new_location));
}
if (neighborhood_type == GridNeighborhoodType::Moore) {
// NE, SE, SW, NW
{
auto new_location = coord_wrap(HexCoord(x + 1, y - 1));
if (is_location_valid(new_location))
neighborhood->insert(coord_wrap(new_location));
}
{
auto new_location = coord_wrap(HexCoord(x + 1, y + 1));
if (is_location_valid(new_location))
neighborhood->insert(coord_wrap(new_location));
}
{
auto new_location = coord_wrap(HexCoord(x - 1, y + 1));
if (is_location_valid(new_location))
neighborhood->insert(coord_wrap(new_location));
}
{
auto new_location = coord_wrap(HexCoord(x - 1, y - 1));
if (is_location_valid(new_location))
neighborhood->insert(coord_wrap(new_location));
}
}
return std::move(neighborhood);
}
std::optional<std::shared_ptr<std::set<AgentID>>> HexGrid::get_location_contents(const HexCoord &coord) const {
auto agent_ids = std::make_shared<std::set<AgentID>>();
if (!is_location_valid(coord))
return std::nullopt;
if (is_location_empty(coord))
return agent_ids;
auto agent_range = _agent_grid->equal_range(coord);
if (agent_range.first == agent_range.second)
return agent_ids;
for (auto i = agent_range.first; i != agent_range.second; i++)
agent_ids->insert(i->second);
return agent_ids;
}
bool HexGrid::get_wrap_x() const { return _wrap_x; }
bool HexGrid::get_wrap_y() const { return _wrap_y; }
unsigned int HexGrid::get_maximum_x() const { return _maximum_x; }
unsigned int HexGrid::get_maximum_y() const { return _maximum_y; }
std::optional<HexCoord> HexGrid::get_location_by_agent(const AgentID &agent_id) const {
auto coord = _agent_index->find(agent_id);
if (coord == _agent_index->end())
return std::nullopt;
return coord->second;
}
HexCoord HexGrid::coord_wrap(const HexCoord &coord) const {
auto x = coord.get_x_location();
auto y = coord.get_y_location();
if (_wrap_x)
x = (x + static_cast<int>(_maximum_x)) % static_cast<int>(_maximum_x);
if (_wrap_x)
y = (y + static_cast<int>(_maximum_y)) % static_cast<int>(_maximum_y);
return {x, y};
}
} // namespace kami