Grail (C++)  1.4.0
A multi-platform, modular, universal engine for embedding advanced AI in games.
Planner.hh
1 // Copyright QED Software 2023.
2 
3 #ifndef GRAIL_PLANNER_H
4 #define GRAIL_PLANNER_H
5 
6 #include "../../GrailData/DebugInfo/PlannerSnapshots.h"
7 #include "Action/Action.hh"
8 #include "WorldState/WorldState.hh"
9 
10 #include <cstdlib>
11 #include <functional>
12 #include <limits>
13 #include <map>
14 #include <memory>
15 #include <queue>
16 #include <vector>
17 
18 namespace grail
19 {
20  #undef max
21  #undef min
22 
23 namespace planner
24 {
26  using ConditionFunction = std::function<bool(const WorldState&)>;
27 
32  using PlannerHeuristic = std::function<double(const WorldState&, const std::vector<ConditionFunction>&)>;
33 
39  class Planner
40  {
41  public:
43  struct Config
44  {
45  Config() noexcept
46  {
47  }
48 
53  PlannerHeuristic heuristic = nullptr;
54 
56  std::size_t iterationLimit = 500;
57 
59  int maxPlanLength = -1;
60 
62  double maxPlanCost = -1;
63 
64  std::size_t initialNodeCapacity = 128;
65  };
66 
70  struct AbstractPlan
71  {
72  std::vector<Action> actions{};
73  float totalCost = 0.0f;
74  };
75 
76  Planner();
77 
83  Planner(std::unique_ptr<WorldState> initialState, const Config& config = Config{});
84 
90  void SetIterationLimit(std::size_t iterationLimit);
91 
95  void SetMaxPlanLength(int maxLength);
96 
101  void SetMaxPlanCost(double maxCost);
102 
108  void SetHeuristic(PlannerHeuristic heuristic);
109 
113  void SetConfig(const Config& config);
114 
118  void PushCondition(ConditionFunction condition);
119 
125  AbstractPlan GetPartialPlan() const;
126 
133  data::PlannerIterationSnapshot GetPlanSnapshot(std::size_t goalNodeIndex, std::size_t iteration) const;
134 
141  void Iterate(std::size_t iterationCount) noexcept;
142 
151  void IterateWithSnapshot(std::size_t iterationCount,
153  std::size_t minDebugSnapshotIteration = 0,
154  std::size_t maxDebugSnapshotIteration = std::numeric_limits<std::size_t>::max())
155  noexcept;
156 
162  void SetPlanFoundCallback(const std::function<void(const AbstractPlan&)> callbackFunction);
163 
168  void SetPlanningFailedCallback(const std::function<void()> callbackFunction);
169 
174  void Reset(std::unique_ptr<WorldState> initialState);
175 
181  bool IsComputing() const;
182 
183  private:
184  //helper structs start
185  struct Edge;
186 
187  struct Node
188  {
189  WorldState state;
190  int depth = 0;
191  double score = 0;
192  double distanceFromGoal = std::numeric_limits<double>::max();
193  std::shared_ptr<Edge> pathEdge = nullptr;
194 
195  Node(Node&& other) noexcept;
196  Node(const WorldState& state);
197  Node(WorldState&& state);
198  Node& operator=(Node&& other) noexcept;
199  };
200 
201  struct Edge
202  {
203  Edge(std::size_t sourceIndex, std::size_t destinationIndex, Action&& action);
204  Edge(Edge&& otherEdge) = default;
205 
206  std::size_t sourceIndex = 0;
207  std::size_t destinationIndex = 0;
208  Action action;
209  };
210 
211  struct EdgePriority
212  {
213  EdgePriority(const std::shared_ptr<Edge>& edge, double dijkstraScore, double aStarScore);
214 
215  std::shared_ptr<Edge> edge;
216  double dijkstraScore;
217  double aStarScore;
218  };
219 
220  class EdgePriorityComparer
221  {
222  public:
223  bool operator()(const EdgePriority& one, const EdgePriority& other)
224  {
225  return one.aStarScore > other.aStarScore;
226  }
227  };
228 
229  //helper structs end
230 
231  void AddNode(Node&& node);
232  bool IsGoalAchieved(const WorldState& state) const;
233 
234  std::unique_ptr<WorldState> initialState;
235  Config plannerConfig = {};
236 
237  std::vector<ConditionFunction> goalConditions = {};
238  std::function<void(const AbstractPlan&)> onPlanFound = nullptr;
239  std::function<void()> onPlanningFailed = nullptr;
240 
241  //cached data for iterative approach
242  std::size_t nextNodeIndex = 0;
243  std::size_t nodeClosestToGoalIndex = std::numeric_limits<std::size_t>::max();
244  std::size_t lastChosenNodeIndex = std::numeric_limits<std::size_t>::max();
245  int maxNodeDepth = 0;
246  std::priority_queue<EdgePriority, std::vector<EdgePriority>, EdgePriorityComparer> edges{};
247  std::vector<Node> generatedNodes{};
248  std::vector<std::size_t> closedNodeIndices{};
249  std::size_t currentIteration = 0;
250  bool isPlanningFinished = true;
251  };
252 }
253 }
254 #endif //GRAIL_PLANNER_H
grail::planner::Planner::SetHeuristic
void SetHeuristic(PlannerHeuristic heuristic)
Definition: Planner.cpp:49
grail::planner::Planner::SetPlanFoundCallback
void SetPlanFoundCallback(const std::function< void(const AbstractPlan &)> callbackFunction)
SetPlanFoundCallback - Binds a function handle to call if a sufficient plan is found....
Definition: Planner.cpp:381
grail::planner::Planner::IsComputing
bool IsComputing() const
IsComputing - Returns true if no suitable plan was found and planning hasn't failed....
Definition: Planner.cpp:405
grail::planner::Planner::SetMaxPlanCost
void SetMaxPlanCost(double maxCost)
SetMaxPlanCost - Limits generated plans cost (measured as the sum of costs of actions it consists of)...
Definition: Planner.cpp:44
grail::planner::Action
Definition: Action.hh:16
grail::planner::Planner::AbstractPlan
Represents a formulated plan as a sequence of actions and a cost.
Definition: Planner.hh:70
grail::planner::Planner::SetConfig
void SetConfig(const Config &config)
ResetConfig - Sets planner config: max iteration, cost, length, plan heuristic, and node count.
Definition: Planner.cpp:54
grail::planner::WorldState
Definition: WorldState.hh:20
grail::planner::Planner::PushCondition
void PushCondition(ConditionFunction condition)
Definition: Planner.cpp:59
grail::planner::Planner::SetMaxPlanLength
void SetMaxPlanLength(int maxLength)
SetMaxPlanLength - Limits generated plans to not exceed given number of steps to achieve goal conditi...
Definition: Planner.cpp:39
grail::planner::Planner::GetPlanSnapshot
data::PlannerIterationSnapshot GetPlanSnapshot(std::size_t goalNodeIndex, std::size_t iteration) const
GetPlanSnapshot - Get debug data on a single iteration of a plan.
Definition: Planner.cpp:64
grail::planner::Planner::GetPartialPlan
AbstractPlan GetPartialPlan() const
GetPartialPlan - returns currently best plan, regardless if goal conditions are met....
Definition: Planner.cpp:87
grail::planner::Planner::IterateWithSnapshot
void IterateWithSnapshot(std::size_t iterationCount, data::PlannerReasonerSnapshot &snapshot, std::size_t minDebugSnapshotIteration=0, std::size_t maxDebugSnapshotIteration=std::numeric_limits< std::size_t >::max()) noexcept
IterateWithSnapshot - Formulates a plan trying to meet goalConditions from initialState....
Definition: Planner.cpp:105
grail::data::PlannerIterationSnapshot
Definition: PlannerSnapshots.h:68
grail::planner::Planner
Definition: Planner.hh:39
grail::data::PlannerReasonerSnapshot
Definition: PlannerSnapshots.h:92
grail::planner::Planner::Config
The Planner's run-time configuration parameters.
Definition: Planner.hh:43
grail::planner::Planner::Config::heuristic
PlannerHeuristic heuristic
Definition: Planner.hh:53
grail::planner::Planner::Config::iterationLimit
std::size_t iterationLimit
The maximum number of iterations per single planning instance.
Definition: Planner.hh:56
grail::planner::Planner::Config::maxPlanLength
int maxPlanLength
The maximum number of actions (steps) a plan can take. Set -1 for unlimited plans.
Definition: Planner.hh:59
grail::planner::Planner::Iterate
void Iterate(std::size_t iterationCount) noexcept
Formulate a plan trying to meet goalConditions from initialState. It will call "OnPlanningFailed" or ...
Definition: Planner.cpp:261
grail::planner::Planner::SetIterationLimit
void SetIterationLimit(std::size_t iterationLimit)
SetIterationLimit - sets maximum number of iterations per each execution of the planning problem....
Definition: Planner.cpp:34
grail::planner::Planner::Reset
void Reset(std::unique_ptr< WorldState > initialState)
Reset - Resets planner to given world state. Any existing plans and goal conditions will be cleared.
Definition: Planner.cpp:391
grail::planner::Planner::SetPlanningFailedCallback
void SetPlanningFailedCallback(const std::function< void()> callbackFunction)
SetPlanningFailedCallback - Binds a function handle to call if no sufficient plan was found.
Definition: Planner.cpp:386
grail::planner::Planner::Config::maxPlanCost
double maxPlanCost
An upper bound on the plan cost measured as the sum of costs of actions it consists of....
Definition: Planner.hh:62