Home Page Downloads Contact Us

Free Open Source Artificial Intelligence C++ Parts

aiParts Open Source Project  

Home Page
Open Source
Contact
Free Downloads
Releases and Credits
Software Status
License
v0.9.3 README File
About rrproj
assigning people and/or equipment to projects
High-Hope Technique
History of the AI
View Source Files
and how they are organized
Making Programs
Development Notes
Using aiParts
Your Application
Support and Services

aiParts Source File

//**********************************************************************
//  aipEmotion.h   -   Emotion  -  a kind of running sum of goodness.
//
//  Provides: aipEmotion  aipFear  aipGreed  aipCuriosity  aipHope
//
//  This header file declares classes to implement the Emotion 
//  AI pattern.  
//
//  See www.aipatterns.org (or www.agt.net/public/bmarshal/aipatterns)
//  for information on Emotion AI pattern.
//
//  An emotion has a set of aspects.
//
//  Copyright (c)  2005, 2008  Brian Marshall
//
//  See the license at end of this file.
//
//  Developers/Contributers:
//    [BRM] Brian Marshall - Calgary - bmarshal@agt.net
//
//  08/06/16  [BRM] removed delete_aspect() and delete_emotion();
//                  small changes for portability
//  05/11/14  [BRM] simplified base class aipCompEmotion
//                  aipHope::weaken(), strengthen(), set_g() 
//                    removed and default to those from aipCompEmotion
//                  aipHope::weaken_fear(), strengthen_greed(), etc.
//                    have been removed
//                  made const: aipHope::greed(), fear(), curiosity()
//  05/10/24  [BRM] made emotion slowly_degrade optional
//                  simplified set_g() and reset()
//                  added floor() and ceiling() functions
//                  removed public non-const access to hope components
//  05/08/17  [BRM] Development begins.
//
//----------------------------------------------------------------------
//        Notes
//
//  Calling a 'weaken' function on a (non-compound) emotion will 
//  never turn a value that is not aipNeutral to aipNeutral.
//
//  If set_g(), weaken() or strengthen() are used with compound
//  emotions, they have to be overriden.  The best way to use
//  compound-emotions, including aipHope, is to attach aspects
//  to the emotion-aspects.  For example, a subclass of aipAspect
//  can be added to the fear in aipHope, with the code to affect
//  that fear in the take_msg() function of the aspect.
//
//----------------------------------------------------------------------

#ifndef aipEmotion_h_guard
#define aipEmotion_h_guard

#include "aipPandemonium.h"

//----------------------------------------------------------------------
//  Classes.  Sub-classing is shown by indentation.

//  class  aipG  is a typedef for  aipGoodness

// class aipBase;                     ( in aipBase.h )
//   class aipDemon;                  ( in aipPandemonium.h )
       class aipAspect;        // Aspect affecting an emotion
         class aipEmotion;         // Kind of running sum of goodness
           class aipPosEmotion;    // Positive emotion
             class aipGreed;       // Wanting a known good
             class aipCuriosity;   // Interested in potiential good
           class aipNegEmotion;    // Negative emotion
             class aipFear;        // Wanting to avoid a known bad
           class aipCompEmotion;   // Compound emotion
             class aipHope;        // Fear + Greed + Curiosity
// class aipDemonItr;                 ( in aipPandemonium.h )
     class aipAspectItr;       // Aspect Iterator
     class aipEmotionItr;      // Emotion Iterator


//----------------------------------------------------------------------
//  Constants

//  From aipBase.h - 
//      long Intensity Constants (for function arguments)...
//   aipIntensity_None        aipIntensity_Slightly  
//   aipIntensity_A_Little    aipIntensity_Somewhat    
//   aipIntensity_A_Fair_Bit  aipIntensity_Quite_A_Bit
//   aipIntensity_A_Lot
//   

//======================================================================
//  aipAspect  -  an aspect that affects an emotion

class aipAspect : public aipDemon {

  aipEmotion  * m_owner_emotion;

public:

  aipAspect () { m_owner_emotion = 0; }
  virtual ~aipAspect () {}

  void set_owner_emotion (aipEmotion *x) { m_owner_emotion = x; }

  aipEmotion * emotion () const { return m_owner_emotion; }

  virtual void take_msg (aipMsg *m) {}

};


//======================================================================
//  aipEmotion  -  an abstract base class.
//
//  The heart of an emotion is m_g, a goodness that changes as a 
//  result of calls to strengthen() or weaken(),
//  or as a result of calls to take_msg(), which:
//     - calls pre_msg_behavior()
//     - calls take_msg() for each aspect of the emotion
//     - calls post_msg_behavior()
//
//  Subclasses can override pre_msg_behavior() and post_msg_behavior().
//  Instances of subclasses can have aspects added to them.
//  Subclasses should, in general, NOT override take_msg()

class aipEmotion : public aipAspect {

  aipG             m_g;         // current emotion goodness
  aipPandemonium * m_aspects;   // aspects that affect m_g

  aipG   m_g_before_take_msg;   // m_g before take_msg() is called.
  aipG   m_g_before_prev_msg;   // m_g before take_msg() is called.

  int    m_should_slowly_degrade;  // 0 = no

protected:

  aipG  g_before_take_msg () const { return m_g_before_take_msg; }
  aipG  g_before_prev_msg () const { return m_g_before_prev_msg; }

  virtual void pre_msg_behavior  (aipMsg *m =0) {}

  virtual void slowly_degrade ();

  virtual void post_msg_behavior (aipMsg *m =0) {
    if (m_should_slowly_degrade) slowly_degrade();
  }

  aipPandemonium * aspect_pandemonium() const {    // for iterators
    return m_aspects;
  }

public:

  aipEmotion ();
  virtual ~aipEmotion ();

  void add_aspect (aipAspect *x);

  void enable_slowly_degrade  () { m_should_slowly_degrade = 1; }
  void disable_slowly_degrade () { m_should_slowly_degrade = 0; }

  virtual void dump_to_ptr (char *p) const;  // used for debugging

  aipAspectItr aspect_iterator() const;

  virtual void set_g (aipG x);

  virtual aipG g() const { return m_g; }

  virtual void take_msg (aipMsg *m);

  virtual void strengthen (long intensity_constant) =0;
  virtual void weaken     (long intensity_constant) =0;

  void floor   (aipG x);
  void ceiling (aipG x);

  virtual void reset (aipG x =aipNeutral);

};


//======================================================================
//  Basic-classes:  aipPosEmotion, aipNegEmotion, aipCompEmotion
//
//  aipPosEmotion and aipNegEmotion are generally used as base-classes
//    although they can be used as-is if desired.
//
//  aipCompEmotion is generally a base class, and set_g() 
//  is generally be overridden.
//
//----------------------------------------------------------------------
//  aipPosEmotion  -  emotion where goodness is Neutral or Positive

class aipPosEmotion : public aipEmotion {

public:

  aipPosEmotion () {}
  virtual ~aipPosEmotion () {}

  virtual void set_g (aipG x);

  virtual void strengthen (long intensity_constant);
  virtual void weaken     (long intensity_constant);

};


//----------------------------------------------------------------------
//  aipNegEmotion  -  emotion where goodness is Neutral or Negative

class aipNegEmotion : public aipEmotion {

public:

  aipNegEmotion () {}
  virtual ~aipNegEmotion () {}

  virtual void set_g (aipG x);

  virtual void strengthen (long intensity_constant);
  virtual void weaken     (long intensity_constant);

};


//----------------------------------------------------------------------
//  aipCompEmotion  -  compond emotion - aspects are emotions
//
//  Emotions are composites (they descend from aipAspect).  
//  aipCompEmotion is used to create emotions where the aspects
//  are other emotions.  It provides these behaviors:
//    - calc_compound() calculates the goodness - default is:
//             the sum of the goodness of the aspect-emotions
//    - set_g(aipNeutral) sets all aspect-emotions to aipNeutral
//          by default, any other argument has no effect
//
//    - post_msg_behavior(), called by take_msg(), 
//          calls calc_compound().
//
//  set_g() must be overridden for any value except aipNeutral.
//
//  weaken() and strengthen() must be overriden to do anything.
//
//  set_g() and calc_compound() may be overriden to make them
//  faster - knowing the components instead of the default
//  implementation that uses iterators.


class aipCompEmotion : public aipEmotion {

protected:

  void calc_compound();

  virtual void post_msg_behavior (aipMsg *m =0);

public:

  aipCompEmotion () {}
  virtual ~aipCompEmotion () {}

  void add_aspect (aipAspect *x) {}     // use add_emotion

  void add_emotion (aipEmotion *x);

  aipEmotionItr emotion_iterator() const;

       // any of the following functions that are used
       // should be overriden  (except set_g(aipNeutral) works)

  virtual void set_g (aipG x);      // probably override this

  virtual void strengthen (long intensity_constant) {}
  virtual void weaken     (long intensity_constant) {}

};


//======================================================================
//  aipFear, aipGreed, aipCuriosity, aipHope
//
//----------------------------------------------------------------------
//  aipFear  -  how bad something might be.


class aipFear : public aipNegEmotion {

public:

  aipFear () {}
  virtual ~aipFear () {}

  virtual void dump_to_ptr (char *p) const;  // used for debugging

};


//----------------------------------------------------------------------
//  aipGreed -  how good something is known to be.


class aipGreed : public aipPosEmotion {

public:

  aipGreed () {}
  virtual ~aipGreed () {}

  virtual void dump_to_ptr (char *p) const;  // used for debugging

};


//----------------------------------------------------------------------
//  aipCuriosity  -  how good something unknown might be.


class aipCuriosity : public aipPosEmotion {

public:

  aipCuriosity () {}
  virtual ~aipCuriosity () {}

  virtual void dump_to_ptr (char *p) const;  // used for debugging

};


//----------------------------------------------------------------------
//  aipHope  -  Fear plus Greed plus Curiosity - the feeling about
//                whether things are going to work out well.
//
//  The behavior is simplistic in this class.  Subclasses may
//  define pre_msg_behavior() and post_msg_behavior() that considers 
//  application-specific aspects. 

class aipHope : public aipCompEmotion {

  aipFear       * m_fear;
  aipGreed      * m_greed;
  aipCuriosity  * m_curiosity;

protected:

  void calc_compound () {
    if (m_fear && m_greed && m_curiosity) {
      aipEmotion::set_g (
           m_fear->g() + m_greed->g() + m_curiosity->g() );
    }
  }

  virtual void post_msg_behavior (aipMsg *m =0);

public:

  aipHope ();
  virtual ~aipHope () {}

  void enable_slowly_degrade  ();
  void disable_slowly_degrade ();

  virtual void dump_to_ptr (char *p) const;  // used for debugging

  aipFear      * fear      () const { return m_fear;      }
  aipGreed     * greed     () const { return m_greed;     }
  aipCuriosity * curiosity () const { return m_curiosity; }

  virtual void set_g (aipG x);

  virtual void set_fear (aipG x);
  virtual void set_greed (aipG x);
  virtual void set_curiosity (aipG x);

};


//======================================================================
//  Aspect Iterators
//
//----------------------------------------------------------------------
//  aipAspectItr  -  Iterator for aspects in a pandemonium

class aipAspectItr : public aipDemonItr {

public:

  aipAspectItr () {}

  aipAspectItr (aipPandemonium *p) {
    set_demon_itr (p,0);
  }

  aipAspectItr (const aipAspectItr& x) {
    set_demon_itr (x.pandemonium(), x.current());
  }

  virtual ~aipAspectItr () {}

  aipAspectItr& operator = (const aipAspectItr& x) {
    set_demon_itr (x.pandemonium(), x.current());
    return *this;
  }

  aipAspect * first() { return (aipAspect*)aipDemonItr::first(); }
  aipAspect * next()  { return (aipAspect*)aipDemonItr::next();  }

};

//----------------------------------------------------------------------
//  aipEmotionItr  -  Iterator for emotion in a pandemonium

class aipEmotionItr : public aipDemonItr {

public:

  aipEmotionItr () {}

  aipEmotionItr (aipPandemonium *p) {
    set_demon_itr(p,0);
  }

  aipEmotionItr (const aipEmotionItr& x) {
    set_demon_itr (x.pandemonium(), x.current());
  }

  virtual ~aipEmotionItr () {}

  aipEmotionItr& operator = (const aipEmotionItr& x) {
    set_demon_itr (x.pandemonium(), x.current());
    return *this;
  }

  aipEmotion * first() { return (aipEmotion*)aipDemonItr::first(); }
  aipEmotion * next()  { return (aipEmotion*)aipDemonItr::next();  }

};

//======================================================================

#endif

//======================================================================
//                           License
//
//   Permission is hereby granted, free of charge, to any 
//   person obtaining a copy of this software and associated 
//   documentation files (the "Software"), to deal in the Software 
//   without restriction, including without limitation the rights 
//   to use, copy, modify, merge, publish, distribute, sublicense, 
//   and/or sell copies of the Software, and to permit persons to 
//   whom the Software is furnished to do so, subject to the 
//   following conditions:
//
//   The copyright notice and this license shall be included in all 
//   copies or substantial portions of the Software.
//
//   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
//   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
//   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
//   NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 
//   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
//   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
//   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 
//   OTHER DEALINGS IN THE SOFTWARE.
//
//**********************************************************************