Skip to content

Commit

Permalink
+ implemented weighted-random utility selector
Browse files Browse the repository at this point in the history
  • Loading branch information
andrew-gresyk committed Jul 3, 2019
1 parent 5f2272f commit 9ffd3b1
Show file tree
Hide file tree
Showing 52 changed files with 7,156 additions and 4,149 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ cmake-*

/binaries-*
/hfsm_test.dir
/projects/code-lite/compile_commands.json
/projects/code-lite/test-gcc-tdm/CMakeLists.txt
/projects/code-lite/test-gcc-tdm/compile_flags.txt
13 changes: 10 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,22 @@ Check [Wiki](https://github.com/andrew-gresyk/HFSM2/wiki/Tutorial) for basic usa
- Hierarchical, with composite (sub-machine) and orthogonal regions
- Gamedev-friendly, supports explicit `State::update()`
- Also supports traditional event-based workflow with `State::react()`
- Planning support.
- Utility theory support.
- Scaleable, supports state re-use via state injections
- Dynamic planning support
- Utility theory support (both max score and ranked weighted random)
- Scaleable, supports robust state re-use via state injections
- Debug-assisted, includes automatic structure and activity visualization API with `#define HFSM_ENABLE_STRUCTURE_REPORT`
- Built-in logging support
- Convenient, minimal boilerplate

---

## 3rd Party Libraries

- [Catch2](https://github.com/catchorg/Catch2) unit testing framework.
- [xoshiro](http://xoshiro.di.unimi.it/) pseuto-random number generators.

---

## Get Updates

- [Blog](https://andrew-gresyk.github.io/)
Expand Down
15 changes: 8 additions & 7 deletions hfsm.natvis
Original file line number Diff line number Diff line change
Expand Up @@ -188,36 +188,37 @@

<!-- · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · -->

<Type Name="hfsm2::detail::_S&lt;*&gt;">
<Type Name="hfsm2::detail::S_&lt;*&gt;">
<DisplayString>{TYPE}</DisplayString>
<Expand HideRawView="true" />
</Type>

<!-- · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · -->

<Type Name="hfsm2::detail::_C&lt;*&gt;">
<Type Name="hfsm2::detail::C_&lt;*&gt;">
<DisplayString>({_headState})</DisplayString>
</Type>

<Type Name="hfsm2::detail::_CS&lt;*&gt;">
<DisplayString>{{{lHalf} {rHalf}}}</DisplayString>
<Type Name="hfsm2::detail::CS_&lt;*&gt;">
<DisplayString Optional="true">{{ {lHalf} {rHalf} }}</DisplayString>
<DisplayString Optional="true">{{{state}}}</DisplayString>
</Type>

<!-- · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · -->

<Type Name="hfsm2::detail::_O&lt;*&gt;">
<Type Name="hfsm2::detail::O_&lt;*&gt;">
<DisplayString>[{_headState}]</DisplayString>
</Type>

<Type Name="hfsm2::detail::_OS&lt;*&gt;">
<Type Name="hfsm2::detail::OS_&lt;*&gt;">
<DisplayString Optional="true">{initial} {remaining}</DisplayString>
<DisplayString>{initial}</DisplayString>
<Expand HideRawView="true" />
</Type>

<!-- · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · -->

<Type Name="hfsm2::detail::_R&lt;*&gt;">
<Type Name="hfsm2::detail::R_&lt;*&gt;">
<DisplayString Optional="true">{_structure}</DisplayString>
<Expand>
<ExpandedItem Optional="true">_structure</ExpandedItem>
Expand Down
70 changes: 44 additions & 26 deletions include/hfsm2/detail/control.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ class ControlT {
friend struct O_;

template <typename, typename>
friend class _R;
friend class R_;

using Args = TArgs;
using Logger = typename Args::Logger;
using Context = typename Args::Context;
using Random_ = typename Args::Random_;
using StateList = typename Args::StateList;
using RegionList = typename Args::RegionList;

Expand All @@ -47,10 +48,12 @@ class ControlT {

protected:
HFSM_INLINE ControlT(Context& context,
Random_& random,
StateRegistry& stateRegistry,
PlanData& planData,
Logger* const HFSM_IF_LOGGER(logger))
: _context{context}
, _random{random}
, _stateRegistry{stateRegistry}
, _planData{planData}
HFSM_IF_LOGGER(, _logger{logger})
Expand Down Expand Up @@ -98,6 +101,7 @@ class ControlT {

protected:
Context& _context;
Random_& _random;
StateRegistry& _stateRegistry;
PlanData& _planData;
RegionID _regionId = 0;
Expand All @@ -120,7 +124,7 @@ class PlanControlT
friend struct O_;

template <typename, typename>
friend class _R;
friend class R_;

using Args = TArgs;
using Context = typename Args::Context;
Expand Down Expand Up @@ -234,11 +238,12 @@ class FullControlT
friend struct O_;

template <typename, typename>
friend class _R;
friend class R_;

using Args = TArgs;
using Logger = typename Args::Logger;
using Context = typename Args::Context;
using Random_ = typename Args::Random_;
using StateList = typename Args::StateList;
using RegionList = typename Args::RegionList;
using Payload = typename Args::Payload;
Expand Down Expand Up @@ -269,11 +274,12 @@ class FullControlT

protected:
HFSM_INLINE FullControlT(Context& context,
Random_& random,
StateRegistry& stateRegistry,
PlanData& planData,
Requests& requests,
Logger* const logger)
: PlanControl{context, stateRegistry, planData, logger}
: PlanControl{context, random, stateRegistry, planData, logger}
, _requests{requests}
{}

Expand All @@ -300,53 +306,63 @@ class FullControlT
static constexpr RegionID regionId() { return (RegionID) RegionList::template index<T>(); }

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// TODO: test payload versions

HFSM_INLINE void changeTo(const StateID id);
HFSM_INLINE void changeTo(const StateID stateId, const Payload& payload);
HFSM_INLINE void changeTo (const StateID id);
HFSM_INLINE void changeTo (const StateID stateId, const Payload& payload);

HFSM_INLINE void restart (const StateID id);
HFSM_INLINE void restart (const StateID stateId, const Payload& payload);
HFSM_INLINE void restart (const StateID id);
HFSM_INLINE void restart (const StateID stateId, const Payload& payload);

HFSM_INLINE void resume (const StateID id);
HFSM_INLINE void resume (const StateID stateId, const Payload& payload);
HFSM_INLINE void resume (const StateID id);
HFSM_INLINE void resume (const StateID stateId, const Payload& payload);

HFSM_INLINE void utilize (const StateID id);
HFSM_INLINE void utilize (const StateID stateId, const Payload& payload);
HFSM_INLINE void utilize (const StateID id);
HFSM_INLINE void utilize (const StateID stateId, const Payload& payload);

HFSM_INLINE void schedule(const StateID id);
HFSM_INLINE void schedule(const StateID stateId, const Payload& payload);
HFSM_INLINE void randomize(const StateID id);
HFSM_INLINE void randomize(const StateID stateId, const Payload& payload);

HFSM_INLINE void schedule (const StateID id);
HFSM_INLINE void schedule (const StateID stateId, const Payload& payload);

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

template <typename TState>
HFSM_INLINE void changeTo() { changeTo(stateId<TState>()); }
HFSM_INLINE void changeTo () { changeTo (stateId<TState>()); }

template <typename TState>
HFSM_INLINE void changeTo (const Payload& payload) { changeTo (stateId<TState>(), payload); }

template <typename TState>
HFSM_INLINE void restart () { restart (stateId<TState>()); }

template <typename TState>
HFSM_INLINE void changeTo(const Payload& payload) { changeTo(stateId<TState>(), payload); }
HFSM_INLINE void restart (const Payload& payload) { restart (stateId<TState>(), payload); }

template <typename TState>
HFSM_INLINE void restart() { restart (stateId<TState>()); }
HFSM_INLINE void resume () { resume (stateId<TState>()); }

template <typename TState>
HFSM_INLINE void restart (const Payload& payload) { restart (stateId<TState>(), payload); }
HFSM_INLINE void resume (const Payload& payload) { resume (stateId<TState>(), payload); }

template <typename TState>
HFSM_INLINE void resume() { resume (stateId<TState>()); }
HFSM_INLINE void utilize () { utilize (stateId<TState>()); }

template <typename TState>
HFSM_INLINE void resume (const Payload& payload) { resume (stateId<TState>(), payload); }
HFSM_INLINE void utilize (const Payload& payload) { utilize (stateId<TState>(), payload); }

template <typename TState>
HFSM_INLINE void utilize() { utilize (stateId<TState>()); }
HFSM_INLINE void randomize() { randomize(stateId<TState>()); }

template <typename TState>
HFSM_INLINE void utilize (const Payload& payload) { utilize (stateId<TState>(), payload); }
HFSM_INLINE void randomize(const Payload& payload) { randomize(stateId<TState>(), payload); }

template <typename TState>
HFSM_INLINE void schedule() { schedule(stateId<TState>()); }
HFSM_INLINE void schedule () { schedule (stateId<TState>()); }

template <typename TState>
HFSM_INLINE void schedule(const Payload& payload) { schedule(stateId<TState>(), payload); }
HFSM_INLINE void schedule (const Payload& payload) { schedule (stateId<TState>(), payload); }

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Expand Down Expand Up @@ -378,11 +394,12 @@ class GuardControlT
friend struct S_;

template <typename, typename>
friend class _R;
friend class R_;

using Args = TArgs;
using Logger = typename Args::Logger;
using Context = typename Args::Context;
using Random_ = typename Args::Random_;
using StateList = typename Args::StateList;
using RegionList = typename Args::RegionList;
using Payload = typename Args::Payload;
Expand All @@ -402,12 +419,13 @@ class GuardControlT

private:
HFSM_INLINE GuardControlT(Context& context,
Random_& random,
StateRegistry& stateRegistry,
PlanData& planData,
Requests& requests,
const Requests& pendingChanges,
Logger* const logger)
: FullControl{context, stateRegistry, planData, requests, logger}
: FullControl{context, random, stateRegistry, planData, requests, logger}
, _pending{pendingChanges}
{}

Expand Down
34 changes: 34 additions & 0 deletions include/hfsm2/detail/control.inl
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,40 @@ FullControlT<TA>::utilize(const StateID stateId,

//------------------------------------------------------------------------------

template <typename TA>
void
FullControlT<TA>::randomize(const StateID stateId) {
if (!_locked) {
const Request request{Request::Type::RANDOMIZE, stateId};
_requests << request;

if (_regionIndex + _regionSize <= stateId || stateId < _regionIndex)
_status.outerTransition = true;

HFSM_LOG_TRANSITION(_originId, Transition::RANDOMIZE, stateId);
}
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

template <typename TA>
void
FullControlT<TA>::randomize(const StateID stateId,
const Payload& payload)
{
if (!_locked) {
const Request request{Request::Type::RANDOMIZE, stateId, payload};
_requests << request;

if (_regionIndex + _regionSize <= stateId || stateId < _regionIndex)
_status.outerTransition = true;

HFSM_LOG_TRANSITION(_originId, Transition::RANDOMIZE, stateId);
}
}

//------------------------------------------------------------------------------

template <typename TA>
void
FullControlT<TA>::schedule(const StateID stateId) {
Expand Down
5 changes: 5 additions & 0 deletions include/hfsm2/detail/debug/logger_interface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ struct LoggerInterfaceT {
const StateID /*prong*/,
const Utilty /*utilty*/)
{}

virtual void recordRandomResolution(const StateID /*head*/,
const StateID /*prong*/,
const Utilty /*utilty*/)
{}
};

using LoggerInterface = LoggerInterfaceT<float>;
Expand Down
4 changes: 4 additions & 0 deletions include/hfsm2/detail/debug/shared.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace hfsm2 {

enum class Method : ShortIndex {
RANK,
UTILITY,
ENTRY_GUARD,
ENTER,
Expand All @@ -24,6 +25,7 @@ enum class Transition : ShortIndex {
RESTART,
RESUME,
UTILIZE,
RANDOMIZE,
SCHEDULE,

COUNT
Expand Down Expand Up @@ -68,6 +70,7 @@ static inline
const char*
methodName(const Method method) {
switch (method) {
case Method::RANK: return "rank";
case Method::UTILITY: return "utility";
case Method::ENTRY_GUARD: return "entryGuard";
case Method::ENTER: return "enter";
Expand Down Expand Up @@ -95,6 +98,7 @@ transitionName(const Transition transition) {
case Transition::RESTART: return "restart";
case Transition::RESUME: return "resume";
case Transition::UTILIZE: return "utilize";
case Transition::RANDOMIZE: return "randomize";
case Transition::SCHEDULE: return "schedule";

default:
Expand Down
3 changes: 3 additions & 0 deletions include/hfsm2/detail/debug/structure_report.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ HFSM_INLINE get(const typename RequestT<TPayload>::Type type) {
case Request::UTILIZE:
return Transition::UTILIZE;

case Request::RANDOMIZE:
return Transition::RANDOMIZE;

case Request::SCHEDULE:
return Transition::SCHEDULE;

Expand Down
11 changes: 8 additions & 3 deletions include/hfsm2/detail/injections.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class InjectionT {

protected:
using Context = typename TArgs::Context;
using Rank = typename TArgs::Rank;
using Utility = typename TArgs::Utility;
using StateList = typename TArgs::StateList;
using RegionList = typename TArgs::RegionList;
Expand Down Expand Up @@ -76,7 +77,11 @@ template <typename TFirst>
struct B_<TFirst>
: TFirst
{
HFSM_INLINE float utility (const typename TFirst::Control&) { return typename TFirst::Utility{1.0f}; }
HFSM_INLINE typename TFirst::Rank
rank (const typename TFirst::Control&) { return typename TFirst::Rank {0}; }

HFSM_INLINE typename TFirst::Utility
utility (const typename TFirst::Control&) { return typename TFirst::Utility{1.0f}; }

HFSM_INLINE void entryGuard (typename TFirst::GuardControl&) {}

Expand Down Expand Up @@ -112,10 +117,10 @@ struct B_<TFirst>
HFSM_INLINE void widePostExit (typename TFirst::Context& context);

template <typename T>
static constexpr StateID stateId() { return typename TFirst::StateList ::template index<T>(); }
static constexpr StateID stateId() { return typename TFirst::StateList ::template index<T>(); }

template <typename T>
static constexpr RegionID regionId() { return (RegionID) typename TFirst::RegionList::template index<T>(); }
static constexpr RegionID regionId() { return (RegionID) typename TFirst::RegionList::template index<T>(); }
};

template <typename TArgs>
Expand Down
Loading

0 comments on commit 9ffd3b1

Please sign in to comment.