Grail (C++)  1.2.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 
54  void SetIterationLimit(std::size_t iterationLimit);
55  void SetMaxPlanLength(int maxLength);
56  void SetMaxPlanCost(double maxCost);
57  void SetHeuristic(PlannerHeuristic heuristic);
58  void ResetConfig(const Config& config);
59 
62  void PushCondition(ConditionFunction condition);
63  AbstractPlan GetPartialPlan() const;
64  data::PlannerIterationSnapshot GetPlanSnapshot(std::size_t goalNodeIndex, std::size_t iteration) const;
65  void Iterate(std::size_t iterationCount) noexcept;
66  void IterateWithSnapshot(std::size_t iterationCount,
68  std::size_t minDebugSnapshotIteration = 0,
69  std::size_t maxDebugSnapshotIteration = std::numeric_limits<std::size_t>::max())
70  noexcept;
71  void SetPlanFoundCallback(const std::function<void(const AbstractPlan&)> callbackFunction);
72  void SetPlanningFailedCallback(const std::function<void()> callbackFunction);
73  void Reset(std::unique_ptr<WorldState> initialState);
74  bool IsComputing() const;
75  //REVIEW: dox comments would be nice for the particular methods above
76 
77  private:
78  //helper structs start
79  struct Edge;
80 
81  struct Node
82  {
83  WorldState state;
84  int depth = 0;
85  double score = 0;
86  double distanceFromGoal = std::numeric_limits<double>::max();
87  std::shared_ptr<Edge> pathEdge = nullptr;
88 
89  Node(Node&& other) noexcept;
90  Node(const WorldState& state);
91  Node(WorldState&& state);
92  Node& operator=(Node&& other) noexcept;
93  };
94 
95  struct Edge
96  {
97  Edge(std::size_t sourceIndex, std::size_t destinationIndex, Action&& action);
98  Edge(Edge&& otherEdge) = default;
99 
100  std::size_t sourceIndex = 0;
101  std::size_t destinationIndex = 0;
102  Action action;
103  };
104 
105  struct EdgePriority
106  {
107  EdgePriority(const std::shared_ptr<Edge>& edge, double dijkstraScore, double aStarScore);
108 
109  std::shared_ptr<Edge> edge;
110  double dijkstraScore;
111  double aStarScore;
112  };
113 
114  class EdgePriorityComparer
115  {
116  public:
117  bool operator()(const EdgePriority& one, const EdgePriority& other)
118  {
119  return one.aStarScore > other.aStarScore;
120  }
121  };
122 
123  //helper structs end
124 
125  void AddNode(Node&& node);
126  bool IsGoalAchieved(const WorldState& state) const;
127 
128  std::unique_ptr<WorldState> initialState;
129  Config plannerConfig = {};
130 
131  std::vector<ConditionFunction> goalConditions = {};
132  std::function<void(const AbstractPlan&)> onPlanFound = nullptr;
133  std::function<void()> onPlanningFailed = nullptr;
134 
135  //cached data for iterative approach
136  std::size_t nextNodeIndex = 0;
137  std::size_t nodeClosestToGoalIndex = std::numeric_limits<std::size_t>::max();
138  std::size_t lastChosenNodeIndex = std::numeric_limits<std::size_t>::max();
139  int maxNodeDepth = 0;
140  std::priority_queue<EdgePriority, std::vector<EdgePriority>, EdgePriorityComparer> edges{};
141  std::vector<Node> generatedNodes{};
142  std::vector<std::size_t> closedNodeIndices{};
143  std::size_t currentIteration = 0;
144  bool isPlanningFinished = true;
145  };
146 }
147 }
148 #endif //GRAIL_PLANNER_H
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::data::PlannerIterationSnapshot
Definition: PlannerSnapshots.h:53
grail::planner::Planner
The main class responsible for finding paths in plan space.
Definition: Planner.hh:29
grail::data::PlannerReasonerSnapshot
Definition: PlannerSnapshots.h:73
grail::planner::Planner::Config
Definition: Planner.hh:32