-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #17 from mdkdoc15/david_r
TrackingAgent with Alerter
- Loading branch information
Showing
9 changed files
with
835 additions
and
416 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,132 +1,217 @@ | ||
// | ||
// Created by Matthew Kight on 9/24/23. | ||
// | ||
/** | ||
* @file AgentFactory.hpp | ||
* @author Matt Kight, David Rackerby | ||
* | ||
* A factory class that abstracts away the initialization of adding an agent to a world | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include "../core/AgentBase.hpp" | ||
#include "AStarAgent.hpp" | ||
#include "PacingAgent.hpp" | ||
#include "PathAgent.hpp" | ||
#include "TrackingAgent.hpp" | ||
#include "AgentLibary.hpp" | ||
|
||
#include "../core/Entity.hpp" | ||
#include "../core/WorldBase.hpp" | ||
|
||
namespace walle { | ||
|
||
// Forward-declare since it's easier to understand how AddXAgent works when the structs are defined nearby | ||
struct PacingAgentData; | ||
struct PathAgentData; | ||
struct AStarAgentData; | ||
struct TrackingAgentData; | ||
|
||
class AgentFactory { | ||
private: | ||
cse491::WorldBase &world; | ||
|
||
public: | ||
AgentFactory() = delete; | ||
|
||
/** | ||
* Constructor for AgentFactory | ||
* @param world we are adding agents too | ||
*/ | ||
explicit AgentFactory(cse491::WorldBase &world) : world(world) {} | ||
|
||
AStarAgent &AddAStarAgent(const AStarAgentData &agent_data); | ||
cse491::PacingAgent &AddPacingAgent(const PacingAgentData &agent_data); | ||
TrackingAgent &AddTrackingAgent(const TrackingAgentData &agent_data); | ||
PathAgent &AddPathAgent(const PathAgentData &agent_data); | ||
|
||
}; // class AgentFactory | ||
|
||
/** | ||
* Stores data for AgentBase | ||
*/ | ||
struct BaseAgentData { | ||
std::string name; | ||
cse491::GridPosition position; | ||
char symbol = '*'; | ||
}; | ||
/// Name of the agent | ||
std::string name; | ||
|
||
/// Agent's position | ||
cse491::GridPosition position; | ||
|
||
/// Agent's representation | ||
char symbol = '*'; | ||
|
||
struct AStarAgentData : public BaseAgentData { | ||
int recalculate_after_x_turns = 5; | ||
cse491::GridPosition target; | ||
}; | ||
|
||
/** | ||
* Stores data for a PacingAgent | ||
*/ | ||
struct PacingAgentData : public BaseAgentData { | ||
bool vertical = false; | ||
/// Whether the PacingAgent is moving up and down (vertical) or left and right(!vertical) | ||
bool vertical = false; | ||
}; | ||
|
||
struct TrackingAgentData : public BaseAgentData { | ||
std::string path; | ||
std::vector<cse491::GridPosition> vector_path; | ||
cse491::Entity *target; | ||
int tracking_distance = 5; | ||
cse491::GridPosition start_pos; | ||
}; | ||
/** | ||
* Add a PacingAgent to the world | ||
* @param agent_data data for agent we want to create | ||
* @return self | ||
*/ | ||
cse491::PacingAgent &AgentFactory::AddPacingAgent(const PacingAgentData &agent_data) { | ||
auto &entity = world.AddAgent<cse491::PacingAgent>(agent_data.name).SetPosition(agent_data.position).SetProperty( | ||
"symbol", | ||
agent_data.symbol); | ||
auto &agent = DownCastAgent<cse491::PacingAgent>(entity); | ||
agent.SetVertical(agent_data.vertical); | ||
return agent; | ||
} | ||
|
||
/** | ||
* Stores data for a PathAgent | ||
*/ | ||
struct PathAgentData : public BaseAgentData { | ||
std::string path; | ||
std::vector<cse491::GridPosition> vector_path; | ||
/// Starting index into the vector of GridPositions | ||
int index; | ||
|
||
/// String representation of the path traveled (e.g. "n s e w" for north south east west) | ||
std::string string_path; | ||
|
||
/// Set of grid positions that are applied to the agent's position during one step (constructed from string_path) | ||
std::vector<cse491::GridPosition> vector_path; | ||
}; | ||
|
||
class AgentFactory { | ||
private: | ||
cse491::WorldBase &world; | ||
public: | ||
AgentFactory() = delete; | ||
/** | ||
* Constructor for AgentFactory | ||
* @param world we are adding agents too | ||
*/ | ||
AgentFactory(cse491::WorldBase &world) : world(world) {} | ||
|
||
/** | ||
* Add Agent to the world | ||
* @param agent_data data for agent we want to create | ||
* @return self | ||
*/ | ||
AStarAgent &AddAStarAgent(const AStarAgentData &agent_data) { | ||
auto &entity = world.AddAgent<walle::AStarAgent>(agent_data.name).SetPosition(agent_data.position).SetProperty( | ||
"symbol", | ||
agent_data.symbol); | ||
assert(dynamic_cast<walle::AStarAgent *>(&entity)); | ||
auto &agent = static_cast<walle::AStarAgent &>(entity); | ||
agent.SetGoalPosition(agent_data.target); | ||
agent.SetRecalculate(agent_data.recalculate_after_x_turns); | ||
|
||
return agent; | ||
} | ||
/** | ||
* Add Agent to the world | ||
* @param agent_data data for agent we want to create | ||
* @return self | ||
*/ | ||
cse491::PacingAgent &AddPacingAgent(const PacingAgentData &agent_data) { | ||
auto | ||
&entity = world.AddAgent<cse491::PacingAgent>(agent_data.name).SetPosition(agent_data.position).SetProperty( | ||
"symbol", | ||
agent_data.symbol); | ||
assert(dynamic_cast<cse491::PacingAgent *>(&entity)); | ||
auto &agent = static_cast<cse491::PacingAgent &>(entity); | ||
agent.SetVertical(agent_data.vertical); | ||
return agent; | ||
} | ||
/** | ||
* Add Agent to the world | ||
* @param agent_data data for agent we want to create | ||
* @return self | ||
*/ | ||
TrackingAgent &AddTrackingAgent(const TrackingAgentData &agent_data) { | ||
auto &entity = | ||
world.AddAgent<walle::TrackingAgent>(agent_data.name).SetPosition(agent_data.position).SetProperty( | ||
"symbol", | ||
agent_data.symbol); | ||
assert(dynamic_cast<walle::TrackingAgent *>(&entity)); | ||
auto &agent = static_cast<walle::TrackingAgent &>(entity); | ||
if (!agent_data.path.empty()) | ||
agent.SetProperty<std::basic_string_view<char>>("path", | ||
agent_data.path); | ||
else | ||
agent.SetPath(agent_data.vector_path); | ||
agent.SetTarget(agent_data.target); | ||
agent.SetTrackingDistance(agent_data.tracking_distance); | ||
agent.SetStartPosition(agent_data.start_pos); | ||
agent.Initialize(); | ||
return agent; | ||
} | ||
|
||
/** | ||
* Add Agent to the world | ||
* @param agent_data data for agent we want to create | ||
* @return self | ||
*/ | ||
PathAgent &AddPathAgent(const PathAgentData &agent_data) { | ||
auto &entity = | ||
world.AddAgent<walle::PathAgent>(agent_data.name).SetPosition(agent_data.position).SetProperty( | ||
"symbol", | ||
agent_data.symbol); | ||
assert(dynamic_cast<walle::PathAgent *>(&entity)); | ||
auto &agent = static_cast<walle::PathAgent &>(entity); | ||
if (!agent_data.path.empty()) | ||
agent.SetProperty<std::basic_string_view<char>>("path", | ||
agent_data.path); // TODO add another option to provide grid point | ||
else | ||
agent.SetPath(agent_data.vector_path); | ||
agent.Initialize(); | ||
return agent; | ||
} | ||
/** | ||
* Add a PathAgent to the world | ||
* @param agent_data data for agent we want to create | ||
* @return self | ||
*/ | ||
PathAgent &AgentFactory::AddPathAgent(const PathAgentData &agent_data) { | ||
auto &entity = world.AddAgent<walle::PathAgent>(agent_data.name).SetPosition(agent_data.position).SetProperty( | ||
"symbol", | ||
agent_data.symbol); | ||
auto &agent = DownCastAgent<walle::PathAgent>(entity); | ||
if (!agent_data.string_path.empty()) { | ||
agent.SetProperty<std::basic_string_view<char>>("path", | ||
agent_data.string_path); // TODO add another option to provide grid point | ||
} else { | ||
agent.SetPath(agent_data.vector_path); | ||
} | ||
agent.Initialize(); | ||
return agent; | ||
} | ||
|
||
/** | ||
* Stores data for an AStarAgent | ||
*/ | ||
struct AStarAgentData : public BaseAgentData { | ||
/// Number of steps after which the shortest path is recalculated | ||
int recalculate_after_x_turns = 5; | ||
|
||
/// The final position in the world that the AStarAgent is travelling to | ||
cse491::GridPosition goal_pos; | ||
}; | ||
|
||
/** | ||
* Add an AStarAgent to the world | ||
* @param agent_data data for agent we want to create | ||
* @return self | ||
*/ | ||
AStarAgent &AgentFactory::AddAStarAgent(const AStarAgentData &agent_data) { | ||
auto &entity = world.AddAgent<walle::AStarAgent>(agent_data.name).SetPosition(agent_data.position).SetProperty( | ||
"symbol", | ||
agent_data.symbol); | ||
auto &agent = DownCastAgent<walle::AStarAgent>(entity); | ||
agent.SetGoalPosition(agent_data.goal_pos); | ||
agent.SetRecalculate(agent_data.recalculate_after_x_turns); | ||
return agent; | ||
} | ||
|
||
/** | ||
* Stores data for a TrackingAgent | ||
*/ | ||
struct TrackingAgentData : public BaseAgentData { | ||
/// Set of grid positions that are applied to the agent's position during one step (constructed from string_path) like in PathAgent | ||
std::vector<cse491::GridPosition> vector_path; | ||
|
||
/// String representation of the path traveled (e.g. "n s e w" for north south east west) like in PathAgent | ||
std::string string_path; | ||
|
||
/// Goal Entity being tracked (must not be null or else the agent simply behaves like a PathAgent) | ||
cse491::Entity *target; | ||
|
||
/// Distance that the TrackingAgent can "see" such that when the target enters that range, it begins tracking | ||
int tracking_distance = 5; | ||
|
||
/// Where the TrackingAgent begins from patrolling from and returns two after the target moves out of range | ||
cse491::GridPosition start_pos; | ||
|
||
/// Shared reference to an Alerter, which is non-null if the agent should be able to tell other agents to immediately | ||
/// focus on their targets | ||
/// @remark You should be using the **same** shared pointer across multiple instances of TrackingAgentData in order | ||
/// to make the TrackingAgents part of the same network. This means you need to copy around this shared pointer | ||
/// when using the factory | ||
std::shared_ptr<Alerter> alerter = nullptr; | ||
|
||
/// Use initial values | ||
TrackingAgentData() = default; | ||
|
||
/// Set all values | ||
TrackingAgentData(std::string name, | ||
cse491::GridPosition curr_pos, | ||
char symbol, | ||
std::string path, | ||
cse491::Entity * target, | ||
int tracking_dist, | ||
cse491::GridPosition start_pos, | ||
std::shared_ptr<Alerter> alerter) | ||
: BaseAgentData({std::move(name), curr_pos, symbol}), | ||
vector_path(StrToOffsets(path)), | ||
string_path(std::move(path)), | ||
target(target), | ||
tracking_distance(tracking_dist), | ||
start_pos(start_pos), | ||
alerter(alerter) {} | ||
}; | ||
|
||
/** | ||
* Add a TrackingAgent to the world | ||
* @param agent_data data for agent we want to create | ||
* @return self | ||
*/ | ||
TrackingAgent &AgentFactory::AddTrackingAgent(const TrackingAgentData &agent_data) { | ||
auto &entity = world.AddAgent<walle::TrackingAgent>(agent_data.name).SetPosition(agent_data.position).SetProperty( | ||
"symbol", | ||
agent_data.symbol); | ||
auto &agent = DownCastAgent<TrackingAgent>(entity); | ||
if (!agent_data.string_path.empty()) { | ||
agent.SetProperty<std::basic_string_view<char>>("path", agent_data.string_path); | ||
} else { | ||
agent.SetPath(agent_data.vector_path); | ||
} | ||
agent.SetTarget(agent_data.target); | ||
agent.SetTrackingDistance(agent_data.tracking_distance); | ||
agent.SetStartPosition(agent_data.start_pos); | ||
if (agent_data.alerter != nullptr) { | ||
agent.SetProperty("alerter", agent_data.alerter); | ||
} | ||
agent.Initialize(); | ||
return agent; | ||
} | ||
|
||
} // namespace walle |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.