home *** CD-ROM | disk | FTP | other *** search
/ AI Game Programming Wisdom / AIGameProgrammingWisdom.iso / SourceCode / 06 General Architectures / 04 Christian / ie.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-10  |  15.1 KB  |  638 lines

  1.  
  2. #include "ie.h"
  3. #include "iegoal.h"
  4. #include "ieexec.h"
  5. #include "ierule.h"
  6.  
  7. #include <assert.h>
  8.  
  9. static bool dbg = false;
  10.  
  11. //===========================================================================
  12. // Name: 
  13. // start 
  14. //
  15. // Description: 
  16. // Start an inference engine goal set.
  17. //
  18. // Parameters: 
  19. // name - The name of the goal set.
  20. // 
  21. // Return Value: 
  22. // None.
  23. //
  24. // Remarks: 
  25. //
  26. //===========================================================================
  27. void IE::start ( char * name, IEOwner * owner )
  28. {
  29.     m_name      = name;
  30.     m_owner     = owner;
  31.     m_curGoal   = NULL;
  32.     m_curRule   = NULL;
  33.     m_nextGoal  = NULL;
  34. }
  35.  
  36. //===========================================================================
  37. // Name: 
  38. // end 
  39. //
  40. // Description: 
  41. // End the goal set. Link up the goal pointers in the rules.
  42. //
  43. // Parameters: 
  44. // None.
  45. //
  46. // Return Value: 
  47. // None.
  48. //
  49. // Remarks: 
  50. // 
  51. //===========================================================================
  52. void IE::end ()
  53. {
  54.     // link the rules to their goals via the goal name
  55.     linkRuleGoals();
  56.  
  57.     // set current goal to the first goal
  58.     m_curGoal = m_goalList.front();
  59.  
  60.     // push  goal on stack
  61.     pushGoal ( m_curGoal );    
  62.  
  63. }
  64.  
  65. //===========================================================================
  66. // Name: 
  67. // makeGoal 
  68. //
  69. // Description: 
  70. // Make a new goal and add it to the end of the goal list.
  71. //
  72. // Parameters: 
  73. // name - The name of the goal.
  74. //
  75. // Return Value: 
  76. // None.
  77. //
  78. // Remarks: 
  79. //
  80. //===========================================================================
  81. void IE::makeGoal ( IEExec * exec )
  82. {    
  83.     if ( !exec )
  84.         return;
  85.  
  86.     // new goal
  87.     m_curGoal = new IEGoal ( exec );
  88.  
  89.     // initialize goal
  90.     exec->init( m_owner );
  91.  
  92.     // add it to the end of the goal list
  93.     m_goalList.push_back ( m_curGoal );
  94. }
  95.  
  96. //===========================================================================
  97. // Name: 
  98. // makeRule 
  99. //
  100. // Description: 
  101. // Make a new rule and add it to the current goal.
  102. //
  103. // Parameters: 
  104. // condition - Pointer to the conditional object for the rule.
  105. // lineInfo  - Description of the line the makeRule macro is on. (for debug)
  106. //
  107. // Return Value: 
  108. // None.
  109. //
  110. // Remarks: 
  111. // This method expects a 'current' goal to have been established by a call
  112. // to makeGoal.
  113. //===========================================================================
  114. void IE::makeRule ( IEExec * condition, char * lineInfo )
  115. {
  116.     // make sure there is a current goal established
  117.     if ( ! m_curGoal )
  118.     {
  119.         printf ( "ERROR: No goal specified for rule at %s.\n", lineInfo );
  120.         return;
  121.     }
  122.  
  123.     // check the type of the conditional object to make
  124.     // sure it matches the type of the goal set
  125. #if 0
  126.     if ( condition->getType() != m_type )
  127.     {
  128.         printf ( "ERROR: Condition %s at %s invalid type of %d.\n",
  129.             condition->getName(), lineInfo, condition->getType() );
  130.         return;
  131.     }
  132. #endif
  133.  
  134.     // make a new rule
  135.     m_curRule = new IERule( condition );
  136.  
  137.     // initialize rule condition exec
  138.     condition->init( m_owner );
  139.  
  140.     // add the rule to the current goal
  141.     m_curGoal->addRule ( m_curRule );
  142. }
  143.  
  144. //===========================================================================
  145. // Name: 
  146. // addRuleGoto 
  147. //
  148. // Description: 
  149. // Make the current rule a goto rule.
  150. //
  151. // Parameters: 
  152. // goalName - The name of the goal to goto to.
  153. // lineInfo - Debug info for the macro setting the goto portion. (debug)
  154. //
  155. // Return Value: 
  156. // None.
  157. //
  158. // Remarks: 
  159. // This method expects a current rule to have been established via makeRule.
  160. //===========================================================================
  161. void IE::addRuleGoto ( char * goalName, char * lineInfo )
  162. {
  163.     if ( noRule ( lineInfo ) )
  164.         return;
  165.  
  166.     m_curRule->setGoal ( goalName, lineInfo );
  167.     m_curRule->setType ( IERule::Goto );
  168.  
  169.     m_curRule->m_name = "If_";
  170.     m_curRule->m_name += m_curRule->m_condition->getName();
  171.     m_curRule->m_name += "_Goto_";
  172.     m_curRule->m_name += goalName;
  173. }
  174.  
  175. //===========================================================================
  176. // Name: 
  177. // addRuleGosub
  178. //
  179. // Description: 
  180. // Make the current rule a gosub rule.
  181. //
  182. // Parameters: 
  183. // goalName - The name of the goal to gosub.
  184. // lineInfo - Debug info for the macro setting the gosub portion. (debug)
  185. //
  186. // Return Value: 
  187. // None.
  188. //
  189. // Remarks: 
  190. // This method expects a current rule to have been established via makeRule.
  191. //===========================================================================
  192. void IE::addRuleGosub ( char * goalName, char * lineInfo )
  193. {
  194.     if ( noRule ( lineInfo ) )
  195.         return;
  196.  
  197.     m_curRule->setGoal ( goalName, lineInfo );
  198.     m_curRule->setType ( IERule::Gosub );
  199.  
  200.     m_curRule->m_name = "If_";
  201.     m_curRule->m_name += m_curRule->m_condition->getName();
  202.     m_curRule->m_name += "_Gosub_";
  203.     m_curRule->m_name += goalName;
  204. }
  205.  
  206. //===========================================================================
  207. // Name: 
  208. // addRuleReturn 
  209. //
  210. // Description: 
  211. // Make the current rule a return rule.
  212. //
  213. // Parameters: 
  214. // lineInfo - Debug info for the macro setting the return portion. (debug)
  215. //
  216. // Return Value: 
  217. // None.
  218. //
  219. // Remarks: 
  220. // This method expects a current rule to have been established via makeRule.
  221. // A goal name is not need because a return rule will return to the goal
  222. // that transfered to the current goal, whether through a goto or gosub.
  223. //===========================================================================
  224. void IE::addRuleReturn ( char * lineInfo )
  225. {
  226.     if ( noRule ( lineInfo ) )
  227.         return;
  228.  
  229.     m_curRule->setType ( IERule::Return );
  230.     m_curRule->setGoal ( m_curGoal );
  231.  
  232.     m_curRule->m_name = "If_";
  233.     m_curRule->m_name += m_curRule->m_condition->getName();
  234.     m_curRule->m_name += "_Return";
  235. }
  236.  
  237.  
  238. //===========================================================================
  239. // Name: 
  240. // update 
  241. //
  242. // Description: 
  243. // Main update for the inference engine. Processes goal start, finish, and
  244. // rule sets. Pushs, Pops, and transfers goal control based on returns from
  245. // rule conditionals.
  246. //
  247. // Parameters: 
  248. // None.
  249. //
  250. // Return Value: 
  251. // None.
  252. //
  253. // Remarks: 
  254. //
  255. //===========================================================================
  256. void IE::update ()
  257. {
  258.     assert ( m_curGoal );
  259.  
  260.     // if at the start of the current goal
  261.     checkStart();
  262.  
  263.     // if trying to finish the current goal
  264.     if ( ! checkFinish() )
  265.         return;
  266.  
  267.     // process all rules for all goals on the stack
  268.     std::list<IEGoal *>::iterator goalItr;
  269.     std::list<IERule *>::iterator ruleItr;
  270.  
  271.     IEGoal * goal;
  272.     IERule * rule;
  273.  
  274.     // first, see if goal alread on the stack
  275.     goalItr = m_goalStack.begin();
  276.  
  277.     bool ruleFired = false;
  278.  
  279.     while ( goalItr != m_goalStack.end() && ! ruleFired )
  280.     {
  281.         goal = *goalItr++;
  282.  
  283.         ruleItr = goal->m_rules.begin();
  284.  
  285.         while ( ruleItr != goal->m_rules.end() )
  286.         {            
  287.             rule = *ruleItr++;
  288.  
  289.             // if rule already fired then skip (for rules on stack)
  290.             if ( rule->m_fired )
  291.                 continue;
  292.  
  293.             if ( dbg ) printf ( "Rule %s tested.\n", rule->getName() );
  294.  
  295.             if ( rule->m_condition->update() == true )
  296.             {
  297.                 if ( dbg ) printf ( "\tFired.\n" );
  298.  
  299.                 rule->m_fired = true;
  300.  
  301.                 // get the goal for this rule
  302.                 m_nextGoal = rule->getGoal();
  303.                 assert( m_nextGoal );
  304.  
  305.                 if ( dbg ) printf ( "\tNext goal %s.\n", m_nextGoal->getName() );
  306.  
  307.                 // set finish for the current goal to allow
  308.                 // cleanup (call of finish())
  309.                 m_curGoal->setFinish( true );
  310.  
  311.                 // pop current goal off the stack if not gosub rule,
  312.                 // next goal will be replacing it
  313.                 if ( rule->m_type != IERule::Gosub )
  314.                     popGoal( m_curGoal );
  315.  
  316.                 ruleFired = true;
  317.  
  318.                 break;
  319.             }
  320.         }
  321.     }
  322.  
  323.     // excute main goal update, unless rule fired
  324.     if ( ! ruleFired )
  325.     {
  326.         m_curGoal->update();
  327.     }
  328.     // go ahead and check finish this frame to possibly be ready for the next
  329.     else
  330.     {
  331.         checkFinish();
  332.     }
  333.  
  334.     if ( dbg ) printf ( "Goal %s updated.\n", m_curGoal->getName() );
  335. }
  336.  
  337. //===========================================================================
  338. // Name: 
  339. // checkStart 
  340. //
  341. // Description: 
  342. // Checks for start condition and performs start if it needs to.
  343. //
  344. // Parameters: 
  345. // None.
  346. //
  347. // Return Value: 
  348. // None.
  349. //
  350. // Remarks: 
  351. //
  352. //===========================================================================
  353. void IE::checkStart ()
  354. {
  355.     if ( m_curGoal->atStart() )
  356.     {
  357.         // call start
  358.         m_curGoal->start();
  359.  
  360.         m_curGoal->setStart ( false );
  361.  
  362.         if ( dbg ) printf ( "Goal %s start.\n", m_curGoal->getName() );
  363.  
  364.         m_curGoal->resetFiredRules();
  365.     }
  366. }
  367.  
  368. //===========================================================================
  369. // Name: 
  370. // checkFinish 
  371. //
  372. // Description: 
  373. // Checks for finish condition
  374. //
  375. // Parameters: 
  376. // None.
  377. //
  378. // Return Value: 
  379. // Returns false if not finished, else true.
  380. //
  381. // Remarks: 
  382. //
  383. //===========================================================================
  384. bool IE::checkFinish ()
  385. {
  386.     if ( m_curGoal->atFinish() )
  387.     {
  388.         if ( dbg ) printf ( "Goal %s at finish.\n", m_curGoal->getName() );
  389.  
  390.         // call finish method, if not finished
  391.         // then return and process no more
  392.         if ( m_curGoal->finish() == false )
  393.         {
  394.             if ( dbg ) printf ( "Goal %s net yet finished.\n", m_curGoal->getName() );
  395.             return false;
  396.         }
  397.  
  398.         // goal is finished, reset it
  399.         m_curGoal->reset();
  400.  
  401.         // set last goal of next goal so it will know who 
  402.         // transferred control to it
  403.         m_nextGoal->m_lastGoal = m_curGoal;
  404.  
  405.         if ( dbg ) printf ( "Goal %s finished.\n", m_curGoal->getName() );
  406.  
  407.         // prepare next goal
  408.         m_curGoal = m_nextGoal;
  409.  
  410.         // push new goal on stack, or if it is already
  411.         // on the stack then simply set the stack to it
  412.         pushGoal ( m_curGoal );    
  413.     }
  414.  
  415.     return true;
  416. }
  417.  
  418. //===========================================================================
  419. // Name: 
  420. // noRule 
  421. //
  422. // Description: 
  423. // Tests for a current rule and prints error info if there is not one.
  424. //
  425. // Parameters: 
  426. // lineInfo - Debug info about the current line of a macro.
  427. //
  428. // Return Value: 
  429. // True if there is no current rule. False otherwise.
  430. //
  431. // Remarks: 
  432. //
  433. //===========================================================================
  434. bool IE::noRule ( char * lineInfo )
  435. {
  436.     if ( ! m_curRule )
  437.     {
  438.         printf ( "ERROR: No rule specified at %s.\n", lineInfo );
  439.         return true;
  440.     }
  441.  
  442.     return false;
  443. }
  444.  
  445. //===========================================================================
  446. // Name: 
  447. // linkRuleGoals 
  448. //
  449. // Description: 
  450. // Links rules with the goals they are referencing via name. 
  451. //
  452. // Parameters: 
  453. // None.
  454. //
  455. // Return Value: 
  456. // None.
  457. //
  458. // Remarks: 
  459. // If a rule refers to a goal that is not found then error info is printed
  460. // about the line the rule macro was on.
  461. //===========================================================================
  462. void IE::linkRuleGoals ()
  463. {
  464.     std::list<IEGoal *>::iterator goalItr;
  465.     std::list<IERule *>::iterator ruleItr;
  466.  
  467.     IEGoal * goal;
  468.     IERule * rule;
  469.  
  470.     goalItr = m_goalList.begin();
  471.  
  472.     // iterate through goals
  473.     while ( goalItr != m_goalList.end() )
  474.     {
  475.         goal = *goalItr++;
  476.  
  477.         // for every rule in the goal
  478.         ruleItr = goal->m_rules.begin();
  479.  
  480.         while ( ruleItr != goal->m_rules.end() )
  481.         {
  482.             rule = *ruleItr++;
  483.  
  484.             // if there is a goal name then find it
  485.             if ( rule->m_goalName.length() > 0 )
  486.             {
  487.                 IEGoal * ruleGoal = findGoal ( rule->m_goalName );
  488.  
  489.                 if ( ruleGoal == NULL )
  490.                 {
  491.                     printf ( "ERROR: Goal %s at %s does not exist.\n",
  492.                         rule->m_goalName, rule->m_lineInfo );                    
  493.                 }
  494.                 else
  495.                 {
  496.                     rule->setGoal ( ruleGoal );
  497.                 }
  498.             }
  499.         }
  500.     }
  501. }
  502.  
  503. //===========================================================================
  504. // Name: 
  505. // findGoal 
  506. //
  507. // Description: 
  508. // Finds a goal in the goal list given a name.
  509. //
  510. // Parameters: 
  511. // goalName - The name of the goal being searched for.
  512. //
  513. // Return Value: 
  514. // A pointer to the found goal or NULL.
  515. //
  516. // Remarks: 
  517. //
  518. //===========================================================================
  519. IEGoal * IE::findGoal ( std::string & goalName )
  520. {
  521.     std::list<IEGoal *>::iterator goalItr;
  522.  
  523.     IEGoal * goal;
  524.  
  525.     goalItr = m_goalList.begin();
  526.  
  527.     while ( goalItr != m_goalList.end() )
  528.     {
  529.         goal = *goalItr;
  530.  
  531.         if ( goal->m_name == goalName )
  532.             return goal;
  533.  
  534.         ++goalItr;
  535.     }
  536.  
  537.     return NULL;
  538. }
  539.  
  540. //===========================================================================
  541. // Name: 
  542. // pushGoal 
  543. //
  544. // Description: 
  545. // Pushes a goal onto the goal stack, but first looks to see if it is already
  546. // on the stack and pops everybody above it if it is.
  547. //
  548. // Parameters: 
  549. // addGoal - The goal to put on the top of the stack.
  550. //
  551. // Return Value: 
  552. // None.
  553. //
  554. // Remarks: 
  555. //
  556. //===========================================================================
  557. void IE::pushGoal ( IEGoal * addGoal )
  558. {
  559.     std::list<IEGoal *>::iterator goalItr;
  560.  
  561.     IEGoal * goal;
  562.  
  563.     // first, see if goal alread on the stack
  564.     goalItr = m_goalStack.begin();
  565.  
  566.     while ( goalItr != m_goalStack.end() )
  567.     {
  568.         goal = *goalItr;
  569.  
  570.         // if found
  571.         if ( goal == addGoal )
  572.         {
  573.             goalItr = m_goalStack.end();
  574.  
  575.             --goalItr;
  576.  
  577.             // pop stack off above goal
  578.             while ( goal != *goalItr )
  579.             {
  580.                 m_goalStack.pop_back ();
  581.  
  582.                 --goalItr;
  583.             }
  584.  
  585.             // done, quit
  586.             return;
  587.         }
  588.  
  589.         ++goalItr;
  590.     }
  591.  
  592.     // not on stack so put it there
  593.     m_goalStack.push_back ( addGoal );
  594. }
  595.  
  596. //===========================================================================
  597. // Name: 
  598. // popGoal  
  599. //
  600. // Description: 
  601. // Pops a goal and every goal above it off the stack.
  602. //
  603. // Parameters: 
  604. // goal - The goal to take off the stack.
  605. //
  606. // Return Value: 
  607. // None.
  608. //
  609. // Remarks: 
  610. //
  611. //===========================================================================
  612. void IE::popGoal  ( IEGoal * goal2Pop )
  613. {
  614.     std::list<IEGoal *>::iterator goalItr;
  615.  
  616.     IEGoal * goal;
  617.  
  618.     goalItr = m_goalStack.end();
  619.  
  620.     --goalItr;
  621.  
  622.     // pop upto and including goal2Pop
  623.     while ( !m_goalStack.empty() )
  624.     {
  625.         goal = *goalItr--;
  626.  
  627.         m_goalStack.pop_back();
  628.  
  629.         // quit if at goal2Pop
  630.         if ( goal == goal2Pop )
  631.             return;
  632.     }
  633.  
  634.     // shouldn't reach here
  635.     printf ( "ERROR: Goal %s does not exsit on the goal stack.\n",
  636.         goal2Pop->getName() );
  637. }
  638.