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.cpp  -  function bodies for aipEmotion.h
//
//  Copyright (c)  1999, 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] small changes for portability
//  05/11/19  [BRM] emotion take_msg() calls pandemonium take_msg()
//  05/11/15  [BRM] hope: fear, greed, curiosity now aspects
//  05/10/24  [BRM] aipHope::set_g - simplified and slightly changed
//                  weaken functions now do not weaken to aipNeutral
//  05/10/24  [BRM] made emotion slowly_degrade optional
//  05/09/10  [BRM] development began
//
//----------------------------------------------------------------------

#include "aipEmotion.h"
#include <string.h>
#include <stdio.h>

//======================================================================
//  aipAspect  -  Aspect to an emotion
//
//    All function bodies are in the header file
//
//======================================================================
//  aipEmotion  -  a pure virtual base class.
//
//----------------------------------------------------------------------
//  Constructor

aipEmotion::aipEmotion () {

  m_g = aipNeutral;

  m_aspects = new aipPandemonium;

  m_g_before_take_msg = aipNeutral;
  m_g_before_prev_msg = aipNeutral;

  m_should_slowly_degrade = 1;

}

//----------------------------------------------------------------------
//  Destructor

aipEmotion::~aipEmotion () {

  if (m_aspects) delete m_aspects;

}

//----------------------------------------------------------------------
//  add_aspect  -  add and aspect to this emotion

void aipEmotion::add_aspect (aipAspect *x) {

  x->set_owner_emotion(this);

  m_aspects->add(x);

}

//----------------------------------------------------------------------
//  dump_to_ptr

void aipEmotion::dump_to_ptr (char *p) const {

  long x = m_g.numeric_value();
  x = (x<-999999) ? -999999 : ( (x>999999) ? 999999 : x );
  sprintf (p,"%ld",x);

}

//----------------------------------------------------------------------
//  aspect_iterator - return an iterator to the aspects of this emotion.

aipAspectItr aipEmotion::aspect_iterator() const {

  aipAspectItr i(aspect_pandemonium());

  return i;

}

//----------------------------------------------------------------------
//  slowly_degrade

void aipEmotion::slowly_degrade () {

  if ( g() != aipNeutral && g() == g_before_take_msg() && 
                            g() == g_before_prev_msg() ) {
    weaken(aipIntensity_Slightly);
  }

}

//----------------------------------------------------------------------
//  take_msg  - take a message and distribute to aspects
//
//  Subclasses should, in general, NOT override this function.
//  Subclasses can define specific behavior by overriding the
//  pre_msg_behavior() and post_msg_behavior() functions.  
//  Instances can have aspects added to them.

void aipEmotion::take_msg (aipMsg *m) {

  m_g_before_prev_msg = m_g_before_take_msg;
  m_g_before_take_msg = m_g;

  pre_msg_behavior(m);

  m_aspects->take_msg(m);

  post_msg_behavior(m);

}

//----------------------------------------------------------------------
//  set_g

void aipEmotion::set_g (aipG x) { m_g  = x; }

//----------------------------------------------------------------------
//  floor and ceiling

void aipEmotion::floor   (aipG x) { if (m_g < x) set_g(x); }

void aipEmotion::ceiling (aipG x) { if (m_g > x) set_g(x); }

//----------------------------------------------------------------------
//  reset m_g

void aipEmotion::reset (aipG x) { set_g(x); }

//======================================================================
//  aipPosEmotion  -  emotion where goodness is Neutral or Positive
//
//----------------------------------------------------------------------
//  set_g

void aipPosEmotion::set_g (aipG x) {

  aipEmotion::set_g ( (x < aipNeutral) ? aipNeutral : x );

}

//----------------------------------------------------------------------
//  strengthen

void aipPosEmotion::strengthen (long intensity_constant) {

  aipG x = aipNeutral;

  if (intensity_constant == aipIntensity_Slightly) {
    x = aipVerySlightlyGood;
  } else if (intensity_constant == aipIntensity_A_Little) {
    x = aipSlightlyGood;
  } else if (intensity_constant == aipIntensity_Somewhat) {
    x = aipLittleBitGood;
  } else if (intensity_constant == aipIntensity_A_Fair_Bit) {
    x = aipSomewhatGood;
  } else if (intensity_constant == aipIntensity_Quite_A_Bit) {
    x = aipFairlyGood;
  } else if (intensity_constant == aipIntensity_A_Lot) {
    x = aipQuiteGood;
  } 

  set_g (g() + x);

}

//----------------------------------------------------------------------
//  weaken  (so long as the value does not fall to aipNeutral)

void aipPosEmotion::weaken (long intensity_constant) {

  aipG cur_g = g();

  if (cur_g < aipSlightlyGood) return;

  aipG x = aipNeutral;

  if (intensity_constant == aipIntensity_Slightly) {
    x = aipVerySlightlyGood + cur_g.calc_fraction(1,8);
  } else if (intensity_constant == aipIntensity_A_Little) {
    x = aipVerySlightlyGood + cur_g.calc_fraction(1,6);
  } else if (intensity_constant == aipIntensity_Somewhat) {
    x = aipVerySlightlyGood + cur_g.calc_fraction(1,4);
  } else if (intensity_constant == aipIntensity_A_Fair_Bit) {
    x = aipVerySlightlyGood + cur_g.calc_fraction(3,8);
  } else if (intensity_constant == aipIntensity_Quite_A_Bit) {
    x = aipVerySlightlyGood + cur_g.calc_fraction(1,2);
  } else if (intensity_constant == aipIntensity_A_Lot) {
    x = aipVerySlightlyGood + cur_g.calc_fraction(3,4);
  } 

  if (x >= cur_g) x = cur_g - 1;

  set_g (cur_g - x);  // virtual function ensures in is not negative.

}


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

void aipNegEmotion::set_g (aipG x) {

  aipEmotion::set_g ( (x > aipNeutral) ? aipNeutral : x );

}

//----------------------------------------------------------------------
//  strengthen

void aipNegEmotion::strengthen (long intensity_constant) {

  aipG x = aipNeutral;

  if (intensity_constant == aipIntensity_Slightly) {
    x = aipVerySlightlyBad;
  } else if (intensity_constant == aipIntensity_A_Little) {
    x = aipSlightlyBad;
  } else if (intensity_constant == aipIntensity_Somewhat) {
    x = aipLittleBitBad;
  } else if (intensity_constant == aipIntensity_A_Fair_Bit) {
    x = aipSomewhatBad;
  } else if (intensity_constant == aipIntensity_Quite_A_Bit) {
    x = aipFairlyBad;
  } else if (intensity_constant == aipIntensity_A_Lot) {
    x = aipQuiteBad;
  } 

  set_g (g() + x);

}

//----------------------------------------------------------------------
//  weaken  (so long as the value does not rise to aipNeutral)

void aipNegEmotion::weaken (long intensity_constant) {

  aipG cur_g = g();

  if (cur_g > aipSlightlyBad) return;

  aipG x = aipNeutral;

  if (intensity_constant == aipIntensity_Slightly) {
    x = aipVerySlightlyBad + cur_g.calc_fraction(1,8);
  } else if (intensity_constant == aipIntensity_A_Little) {
    x = aipVerySlightlyBad + cur_g.calc_fraction(1,6);
  } else if (intensity_constant == aipIntensity_Somewhat) {
    x = aipVerySlightlyBad + cur_g.calc_fraction(1,4);
  } else if (intensity_constant == aipIntensity_A_Fair_Bit) {
    x = aipVerySlightlyBad + cur_g.calc_fraction(3,8);
  } else if (intensity_constant == aipIntensity_Quite_A_Bit) {
    x = aipVerySlightlyBad + cur_g.calc_fraction(1,2);
  } else if (intensity_constant == aipIntensity_A_Lot) {
    x = aipVerySlightlyBad + cur_g.calc_fraction(3,4);
  } 

  if (x <= cur_g) x = cur_g + 1;

  set_g (cur_g - x);  // virtual function ensures in is not positive.

}

//======================================================================
//  aipCompEmotion  -  compound emotion - aspects are emotions
//
//----------------------------------------------------------------------
//  calc_compound  -  calculate m_g as the sum of the goodness of
//                    each emotion-aspect.
//
//  Subclasses may want to override this function, for efficiency
//  reasons, if nothing else.

void aipCompEmotion::calc_compound () {

  aipG g = aipNeutral;

  aipEmotionItr itr = emotion_iterator();
  for ( aipEmotion *e=itr.first(); e; e=itr.next() ) {
    g += e->g();
  }

  aipEmotion::set_g(g);  // compound emotion is sum of its aspects

}

//----------------------------------------------------------------------
//  add_emotion  -  set the owning emotion

void aipCompEmotion::add_emotion (aipEmotion *x) {

  x->set_owner_emotion(this);

  aipEmotion::add_aspect(x);

  calc_compound();

}

//----------------------------------------------------------------------
//  set_g  -  works only if argument is aipNeutral
//
//  If different behavior is required, override this function.

void aipCompEmotion::set_g (aipG x) {

  if (x != aipNeutral) return;

  aipEmotionItr itr = emotion_iterator();
  for ( aipEmotion *e=itr.first(); e; e=itr.next() ) {
    e->aipEmotion::set_g(aipNeutral);
  }

  aipEmotion::set_g(aipNeutral);

}

//----------------------------------------------------------------------
//  post_msg_behavior  -  called after take_msg() is called for aspects
//  The behavior apart from the aspects (emotion components).
//
//  Subclasses may want to override this function, but in any case,
//  calc_compound() must be called to set the emotion m_g.

void aipCompEmotion::post_msg_behavior (aipMsg *m) {

  if (m) calc_compound();

}

//----------------------------------------------------------------------
//  emotion_iterator

aipEmotionItr aipCompEmotion::emotion_iterator() const { 

  aipEmotionItr i(aspect_pandemonium());

  return i;

}


//======================================================================
//  aipFear  -  how bad something might be.
//
//----------------------------------------------------------------------
//  dump_to_ptr

void aipFear::dump_to_ptr (char *p) const {

  p[0] = 'f';
  p[1] = ':';
  aipEmotion::dump_to_ptr(p+2);

}

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

void aipGreed::dump_to_ptr (char *p) const {

  p[0] = 'g';
  p[1] = ':';
  aipEmotion::dump_to_ptr(p+2);

}

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

void aipCuriosity::dump_to_ptr (char *p) const {

  p[0] = 'c';
  p[1] = ':';
  aipEmotion::dump_to_ptr(p+2);

}


//======================================================================
//  aipHope  -  fear plus greed plus curiosity
//
//----------------------------------------------------------------------
//  Constructor
//
//  This requires no further initialization - by default, emotions
//  are created with a goodness of aipNeutral.

aipHope::aipHope () {

  m_fear = new aipFear;
  m_greed = new aipGreed;
  m_curiosity = new aipCuriosity;

  if (m_fear && m_greed && m_curiosity) {
    add_emotion (m_fear);
    add_emotion (m_greed);
    add_emotion (m_curiosity);
  }

}


//----------------------------------------------------------------------
//  enable_slowly_degrade

void aipHope::enable_slowly_degrade  () { 

  if (m_fear) m_fear->enable_slowly_degrade();
  if (m_greed) m_greed->enable_slowly_degrade();
  if (m_curiosity) m_curiosity->enable_slowly_degrade();

}

//----------------------------------------------------------------------
//  disable_slowly_degrade

void aipHope::disable_slowly_degrade  () { 

  if (m_fear) m_fear->disable_slowly_degrade();
  if (m_greed) m_greed->disable_slowly_degrade();
  if (m_curiosity) m_curiosity->disable_slowly_degrade();

}

//----------------------------------------------------------------------
//  dump_to_ptr

void aipHope::dump_to_ptr (char *p) const {

  strcpy (p, "h(fgc)(");
  long len = strlen(p);
  m_fear->aipEmotion::dump_to_ptr(p+len);
  strcat (p, ",");
  len = strlen(p);
  m_greed->aipEmotion::dump_to_ptr(p+len);
  strcat (p, ",");
  len = strlen(p);
  m_curiosity->aipEmotion::dump_to_ptr(p+len);
  strcat (p, ")");

}

//----------------------------------------------------------------------
//  set_g  -  set the goodness of this compound emotion

void aipHope::set_g (aipG x) {

  if (x != aipNeutral) return;

  if (!m_fear || !m_greed || !m_curiosity) return;

  m_fear->set_g      (aipNeutral);
  m_greed->set_g     (aipNeutral);
  m_curiosity->set_g (aipNeutral);

  aipEmotion::set_g (aipNeutral);

}

//----------------------------------------------------------------------
//  post_msg_behavior  -  called after take_msg() is called for aspects
//
//  This function does the same thing as the one it is overriding,
//  aipCompEmotion::post_msg_behavior(), but it is faster because
//  we already have pointers to all the aspect-emotions.

void aipHope::post_msg_behavior (aipMsg *m) {

  if (!m_fear || !m_greed || !m_curiosity) return;

  if (m) calc_compound();

}

//----------------------------------------------------------------------
//  set_fear

void aipHope::set_fear (aipG x) {

  m_fear->set_g(x);

  calc_compound();

}

//----------------------------------------------------------------------
//  set_greed

void aipHope::set_greed (aipG x) {

  m_greed->set_g(x);

  calc_compound();

}

//----------------------------------------------------------------------
//  set_curiosity

void aipHope::set_curiosity (aipG x) {

  m_curiosity->set_g(x);

  calc_compound();

}


//======================================================================
//  aipAspectItr  -  Aspect iterator
//
//    All function bodies are in the header file
//
//======================================================================
//  aipEmotionItr  -  Emotion iterator
//
//    All function bodies are in the header file
//
//======================================================================
//                           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.
//
//
//**********************************************************************