Grail (C++)  1.3.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 {
25  using ConditionFunction = std::function<bool(const WorldState&)>;
26  using PlannerHeuristic = std::function<double(const WorldState&, const std::vector<ConditionFunction>&)>;
27 
29  class Planner
30  {
31  public:
32  struct Config
33  {
34  Config() noexcept
35  {
36  }
37 
38  PlannerHeuristic heuristic = nullptr;
39  std::size_t iterationLimit = 500;
40  int maxPlanLength = -1;
41  double maxPlanCost = -1;
42  std::size_t initialNodeCapacity = 128;
43  };
44 
45  struct AbstractPlan
46  {
47  std::vector<Action> actions{};
48  float totalCost = 0.0f;
49  };
50 
51  Planner();
52  Planner(std::unique_ptr<WorldState> initialState, const Config& config = Config{});
53 
58  void SetIterationLimit(std::size_t iterationLimit);
59 
64  void SetMaxPlanLength(int maxLength);
65 
70  void SetMaxPlanCost(double maxCost);
71 
76  void SetHeuristic(PlannerHeuristic heuristic);
77 
82  void ResetConfig(const Config& config);
83 
86  void PushCondition(ConditionFunction condition);
87 
93  AbstractPlan GetPartialPlan() const;
94 
101  data::PlannerIterationSnapshot GetPlanSnapshot(std::size_t goalNodeIndex, std::size_t iteration) const;
102 
108  void Iterate(std::size_t iterationCount) noexcept;
109 
118  void IterateWithSnapshot(std::size_t iterationCount,
120  std::size_t minDebugSnapshotIteration = 0,
121  std::size_t maxDebugSnapshotIteration = std::numeric_limits<std::size_t>::max())
122  noexcept;
123 
129  void SetPlanFoundCallback(const std::function<void(const AbstractPlan&)> callbackFunction);
130 
135  void SetPlanningFailedCallback(const std::function<void()> callbackFunction);
136 
141  void Reset(std::unique_ptr<WorldState> initialState);
142 
148  bool IsComputing() const;
149 
150  private:
151  //helper structs start
152  struct Edge;
153 
154  struct Node
155  {
156  WorldState state;
157  int depth = 0;
158  double score = 0;
159  double distanceFromGoal = std::numeric_limits<double>::max();
160  std::shared_ptr<Edge> pathEdge = nullptr;
161 
162  Node(Node&& other) noexcept;
163  Node(const WorldState& state);
164  Node(WorldState&& state);
165  Node& operator=(Node&& other) noexcept;
166  };
167 
168  struct Edge
169  {
170  Edge(std::size_t sourceIndex, std::size_t destinationIndex, Action&& action);
171  Edge(Edge&& otherEdge) = default;
172 
173  std::size_t sourceIndex = 0;
174  std::size_t destinationIndex = 0;
175  Action action;
176  };
177 
178  struct EdgePriority
179  {
180  EdgePriority(const std::shared_ptr<Edge>& edge, double dijkstraScore, double aStarScore);
181 
182  std::shared_ptr<Edge> edge;
183  double dijkstraScore;
184  double aStarScore;
185  };
186 
187  class EdgePriorityComparer
188  {
189  public:
190  bool operator()(const EdgePriority& one, const EdgePriority& other)
191  {
192  return one.aStarScore > other.aStarScore;
193  }
194  };
195 
196  //helper structs end
197 
198  void AddNode(Node&& node);
199  bool IsGoalAchieved(const WorldState& state) const;
200 
201  std::unique_ptr<WorldState> initialState;
202  Config plannerConfig = {};
203 
204  std::vector<ConditionFunction> goalConditions = {};
205  std::function<void(const AbstractPlan&)> onPlanFound = nullptr;
206  std::function<void()> onPlanningFailed = nullptr;
207 
208  //cached data for iterative approach
209  std::size_t nextNodeIndex = 0;
210  std::size_t nodeClosestToGoalIndex = std::numeric_limits<std::size_t>::max();
211  std::size_t lastChosenNodeIndex = std::numeric_limits<std::size_t>::max();
212  int maxNodeDepth = 0;
213  std::priority_queue<EdgePriority, std::vector<EdgePriority>, EdgePriorityComparer> edges{};
214  std::vector<Node> generatedNodes{};
215  std::vector<std::size_t> closedNodeIndices{};
216  std::size_t currentIteration = 0;
217  bool isPlanningFinished = true;
218  };
219 }
220 }
221 #endif //GRAIL_PLANNER_H
grail::planner::Planner::SetHeuristic
void SetHeuristic(PlannerHeuristic heuristic)
SetHeuristic - Gives planner a way to evaluate calculated plans.
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 needed to achieve goal conditions.
Definition: Planner.cpp:44
grail::planner::Action
Definition: Action.hh:12
grail::planner::Planner::AbstractPlan
Definition: Planner.hh:45
grail::planner::WorldState
A class representing planner world state.
Definition: WorldState.hh:16
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
The main class responsible for finding paths in plan space.
Definition: Planner.hh:29
grail::planner::Planner::ResetConfig
void ResetConfig(const Config &config)
ResetConfig - Sets planner config: max iteration, cost, length, plan heuristic, and node count.
Definition: Planner.cpp:54
grail::data::PlannerReasonerSnapshot
Definition: PlannerSnapshots.h:92
grail::planner::Planner::Config
Definition: Planner.hh:32
grail::planner::Planner::Iterate
void Iterate(std::size_t iterationCount) noexcept
Iterate - Formulate a plan trying to meet goalConditions from initialState. Evaluates plan using node...
Definition: Planner.cpp:261
grail::planner::Planner::SetIterationLimit
void SetIterationLimit(std::size_t iterationLimit)
SetIterationLimit - sets maximum number of plans that can be generated during calculations.
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