aiParts |
Free Open Source Artificial Intelligence C++ Parts |
|
Home Page Open Source Contact Us Free Downloads Releases and Credits Software Status License 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.
//
//
//**********************************************************************
|