   /*******************************************************/
   /*      "C" Language Integrated Production System      */
   /*                                                     */
   /*             CLIPS Version 6.20  01/31/02            */
   /*                                                     */
   /*         CONFLICT RESOLUTION STRATEGY MODULE         */
   /*******************************************************/

/*************************************************************/
/* Purpose: Used to determine where a new activation is      */
/*   placed on the agenda based on the current conflict      */
/*   resolution strategy (depth, breadth, mea, lex,          */
/*   simplicity, or complexity). Also provides the           */
/*   set-strategy and get-strategy commands.                 */
/*                                                           */
/* Principal Programmer(s):                                  */
/*      Gary D. Riley                                        */
/*                                                           */
/* Contributing Programmer(s):                               */
/*                                                           */
/* Revision History:                                         */
/*                                                           */
/*************************************************************/

#define _CRSTRTGY_SOURCE_

#include <stdio.h>
#define _STDIO_INCLUDED_
#include <string.h>

#include "setup.h"

#if DEFRULE_CONSTRUCT

#include "constant.h"
#include "pattern.h"
#include "reteutil.h"
#include "argacces.h"
#include "agenda.h"
#include "envrnmnt.h"
#include "crstrtgy.h"

#define GetMatchingItem(x,i) (x->basis->binds[i].gm.theMatch->matchingItem)

/***************************************/
/* LOCAL INTERNAL FUNCTION DEFINITIONS */
/***************************************/

   static ACTIVATION             *PlaceDepthActivation(ACTIVATION *,ACTIVATION *);
#if CONFLICT_RESOLUTION_STRATEGIES
   static ACTIVATION             *PlaceBreadthActivation(ACTIVATION *,ACTIVATION *);
   static ACTIVATION             *PlaceLEXActivation(void *,ACTIVATION *,ACTIVATION *);
   static ACTIVATION             *PlaceMEAActivation(void *,ACTIVATION *,ACTIVATION *);
   static ACTIVATION             *PlaceComplexityActivation(ACTIVATION *,ACTIVATION *);
   static ACTIVATION             *PlaceSimplicityActivation(ACTIVATION *,ACTIVATION *);
   static ACTIVATION             *PlaceRandomActivation(ACTIVATION *,ACTIVATION *);
   static struct partialMatch    *SortPartialMatch(void *,struct partialMatch *);
   static int                     ComparePartialMatches(void *,ACTIVATION *,ACTIVATION *);
   static char                   *GetStrategyName(int);
#endif

/******************************************************************/
/* PlaceActivation: Coordinates placement of an activation on the */
/*   Agenda based on the current conflict resolution strategy.    */
/******************************************************************/
globle void PlaceActivation(
  void *theEnv,
  ACTIVATION **whichAgenda,
  ACTIVATION *newActivation)
  {
   ACTIVATION *placeAfter = NULL;

   /*================================================*/
   /* Set the flag which indicates that a change has */
   /* been made to the agenda.                       */
   /*================================================*/

   EnvSetAgendaChanged(theEnv,TRUE);

   /*=============================================*/
   /* Determine the location where the activation */
   /* should be placed in the agenda based on the */
   /* current conflict resolution strategy.       */
   /*==============================================*/

#if ! CONFLICT_RESOLUTION_STRATEGIES
   if (*whichAgenda != NULL) placeAfter = PlaceDepthActivation(*whichAgenda,newActivation);
#else
   if (*whichAgenda != NULL) switch (AgendaData(theEnv)->Strategy)
     {
      case DEPTH_STRATEGY:
        placeAfter = PlaceDepthActivation(*whichAgenda,newActivation);
        break;

      case BREADTH_STRATEGY:
        placeAfter = PlaceBreadthActivation(*whichAgenda,newActivation);
        break;

      case LEX_STRATEGY:
        placeAfter = PlaceLEXActivation(theEnv,*whichAgenda,newActivation);
        break;

      case MEA_STRATEGY:
        placeAfter = PlaceMEAActivation(theEnv,*whichAgenda,newActivation);
        break;

      case COMPLEXITY_STRATEGY:
        placeAfter = PlaceComplexityActivation(*whichAgenda,newActivation);
        break;

      case SIMPLICITY_STRATEGY:
        placeAfter = PlaceSimplicityActivation(*whichAgenda,newActivation);
        break;

      case RANDOM_STRATEGY:
        placeAfter = PlaceRandomActivation(*whichAgenda,newActivation);
        break;
     }
#endif

   /*==============================================================*/
   /* Place the activation at the appropriate place in the agenda. */
   /*==============================================================*/

   if (placeAfter == NULL) /* then place it at the beginning of then agenda. */
     {
      newActivation->next = *whichAgenda;
      *whichAgenda = newActivation;
      if (newActivation->next != NULL) newActivation->next->prev = newActivation;
     }
   else /* insert it in the agenda. */
     {
      newActivation->next = placeAfter->next;
      newActivation->prev = placeAfter;
      placeAfter->next = newActivation;
      if (newActivation->next != NULL)
        { newActivation->next->prev = newActivation; }
     }
  }

/*******************************************************************/
/* PlaceDepthActivation: Determines the location in the agenda     */
/*    where a new activation should be placed for the depth        */
/*    strategy. Returns a pointer to the activation after which    */
/*    the new activation should be placed (or NULL if the          */
/*    activation should be placed at the beginning of the agenda). */
/*******************************************************************/
static ACTIVATION *PlaceDepthActivation(
  ACTIVATION *actPtr,
  ACTIVATION *newActivation)
  {
   int salience;
   unsigned long timetag;
   ACTIVATION *lastAct;

   /*============================================*/
   /* Set up initial information for the search. */
   /*============================================*/

   salience = newActivation->salience;
   timetag = newActivation->timetag;
   lastAct = NULL;

   /*=========================================================*/
   /* Find the insertion point in the agenda. The activation  */
   /* is placed before activations of lower salience and      */
   /* after activations of higher salience. Among activations */
   /* of equal salience, the activation is placed before      */
   /* activations with an equal or lower timetag (yielding    */
   /* depth first traversal).                                 */
   /*=========================================================*/

   while (actPtr != NULL)
     {
      if (actPtr->salience > salience)
        {
         lastAct = actPtr;
         actPtr = actPtr->next;
        }
      else if (actPtr->salience < salience)
        { return(lastAct); }
      else if (timetag < actPtr->timetag)
        {
         lastAct = actPtr;
         actPtr = actPtr->next;
        }
      else
        { return(lastAct); }
     }

   /*===========================================*/
   /* Return the insertion point in the agenda. */
   /*===========================================*/

   return(lastAct);
  }

#if CONFLICT_RESOLUTION_STRATEGIES
/*******************************************************************/
/* PlaceBreadthActivation: Determines the location in the agenda   */
/*    where a new activation should be placed for the breadth      */
/*    strategy. Returns a pointer to the activation after which    */
/*    the new activation should be placed (or NULL if the          */
/*    activation should be placed at the beginning of the agenda). */
/*******************************************************************/
static ACTIVATION *PlaceBreadthActivation(
  ACTIVATION *actPtr,
  ACTIVATION *newActivation)
  {
   int salience;
   unsigned long timetag;
   ACTIVATION *lastAct;

   /*============================================*/
   /* Set up initial information for the search. */
   /*============================================*/

   salience = newActivation->salience;
   timetag = newActivation->timetag;
   lastAct = NULL;

   /*=========================================================*/
   /* Find the insertion point in the agenda. The activation  */
   /* is placed before activations of lower salience and      */
   /* after activations of higher salience. Among activations */
   /* of equal salience, the activation is placed after       */
   /* activations with a lessor timetag (yielding breadth     */
   /* first traversal).                                       */
   /*=========================================================*/

   while (actPtr != NULL)
     {
      if (actPtr->salience > salience)
        {
         lastAct = actPtr;
         actPtr = actPtr->next;
        }
      else if (actPtr->salience < salience)
        { return(lastAct); }
      else if (timetag > actPtr->timetag)
        {
         lastAct = actPtr;
         actPtr = actPtr->next;
        }
      else
       {  return(lastAct); }
     }

   /*===========================================*/
   /* Return the insertion point in the agenda. */
   /*===========================================*/

   return(lastAct);
  }

/*******************************************************************/
/* PlaceLEXActivation: Determines the location in the agenda       */
/*    where a new activation should be placed for the lex          */
/*    strategy. Returns a pointer to the activation after which    */
/*    the new activation should be placed (or NULL if the          */
/*    activation should be placed at the beginning of the agenda). */
/*******************************************************************/
static ACTIVATION *PlaceLEXActivation(
  void *theEnv,
  ACTIVATION *actPtr,
  ACTIVATION *newActivation)
  {
   int salience;
   unsigned long timetag;
   ACTIVATION *lastAct;
   int flag;

   /*===============================================*/
   /* Sort the fact identifiers for the activation. */
   /*===============================================*/

   if (newActivation->sortedBasis == NULL)
     { newActivation->sortedBasis = SortPartialMatch(theEnv,newActivation->basis); }

   /*============================================*/
   /* Set up initial information for the search. */
   /*============================================*/

   timetag = newActivation->timetag;
   salience = newActivation->salience;
   lastAct = NULL;

   /*=========================================================*/
   /* Find the insertion point in the agenda. The activation  */
   /* is placed before activations of lower salience and      */
   /* after activations of higher salience. Among activations */
   /* of equal salience, the OPS5 lex strategy is used for    */
   /* determining placement.                                  */
   /*=========================================================*/

   while (actPtr != NULL)
     {
      if (actPtr->salience > salience)
        {
         lastAct = actPtr;
         actPtr = actPtr->next;
        }
      else if (actPtr->salience < salience)
        { return(lastAct); }
      else
        {
         flag = ComparePartialMatches(theEnv,actPtr,newActivation);

         if (flag == LESS_THAN)
           {
            lastAct = actPtr;
            actPtr = actPtr->next;
           }
         else if (flag == GREATER_THAN)
           { return(lastAct); }
         else /* flag == EQUAL */
           {
            if (timetag > actPtr->timetag)
              {
               lastAct = actPtr;
               actPtr = actPtr->next;
              }
            else
             { return(lastAct); }
           }
        }
     }

   /*===========================================*/
   /* Return the insertion point in the agenda. */
   /*===========================================*/

   return(lastAct);
  }

/*******************************************************************/
/* PlaceMEAActivation: Determines the location in the agenda       */
/*    where a new activation should be placed for the mea          */
/*    strategy. Returns a pointer to the activation after which    */
/*    the new activation should be placed (or NULL if the          */
/*    activation should be placed at the beginning of the agenda). */
/*******************************************************************/
static ACTIVATION *PlaceMEAActivation(
  void *theEnv,
  ACTIVATION *actPtr,
  ACTIVATION *newActivation)
  {
   int salience;
   unsigned long timetag;
   ACTIVATION *lastAct;
   int flag;
   long int cWhoset, oWhoset;

   if (newActivation->sortedBasis == NULL)
     { newActivation->sortedBasis = SortPartialMatch(theEnv,newActivation->basis); }

   /*============================================*/
   /* Set up initial information for the search. */
   /*============================================*/

   timetag = newActivation->timetag;
   salience = newActivation->salience;
   lastAct = NULL;

   /*=========================================================*/
   /* Find the insertion point in the agenda. The activation  */
   /* is placed before activations of lower salience and      */
   /* after activations of higher salience. Among activations */
   /* of equal salience, the OPS5 mea strategy is used for    */
   /* determining placement.                                  */
   /*=========================================================*/

   while (actPtr != NULL)
     {
      if (actPtr->salience > salience)
        {
         lastAct = actPtr;
         actPtr = actPtr->next;
        }
      else if (actPtr->salience < salience)
        { return(lastAct); }
      else
        {
         cWhoset = -1;
         oWhoset = -1;
         if (GetMatchingItem(newActivation,0) != NULL)
           { cWhoset = GetMatchingItem(newActivation,0)->timeTag; }
         if (GetMatchingItem(actPtr,0) != NULL)
           { oWhoset = GetMatchingItem(actPtr,0)->timeTag; }
         if (oWhoset < cWhoset)
           {
            if (cWhoset > 0) flag = GREATER_THAN;
            else flag = LESS_THAN;
           }
         else if (oWhoset > cWhoset)
           {
            if (oWhoset > 0) flag = LESS_THAN;
            else flag = GREATER_THAN;
           }
         else
           { flag = ComparePartialMatches(theEnv,actPtr,newActivation); }

         if (flag == LESS_THAN)
           {
            lastAct = actPtr;
            actPtr = actPtr->next;
           }
         else if (flag == GREATER_THAN)
           { return(lastAct); }
         else /* flag == EQUAL */
           {
            if (timetag > actPtr->timetag)
              {
               lastAct = actPtr;
               actPtr = actPtr->next;
              }
            else
             { return(lastAct); }
           }
        }
     }

   /*===========================================*/
   /* Return the insertion point in the agenda. */
   /*===========================================*/

   return(lastAct);
  }

/*********************************************************************/
/* PlaceComplexityActivation: Determines the location in the agenda  */
/*    where a new activation should be placed for the complexity     */
/*    strategy. Returns a pointer to the activation  after which the */
/*    new activation should be placed (or NULL if the activation     */
/*    should be placed at the beginning of the agenda).              */
/*********************************************************************/
static ACTIVATION *PlaceComplexityActivation(
  ACTIVATION *actPtr,
  ACTIVATION *newActivation)
  {
   int salience, complexity;
   unsigned long timetag;
   ACTIVATION *lastAct;

   /*========================================*/
   /* Set up initial information for search. */
   /*========================================*/

   timetag = newActivation->timetag;
   salience = newActivation->salience;
   complexity = newActivation->theRule->complexity;
   lastAct = NULL;

   /*=========================================================*/
   /* Find the insertion point in the agenda. The activation  */
   /* is placed before activations of lower salience and      */
   /* after activations of higher salience. Among activations */
   /* of equal salience, the activation is placed before      */
   /* activations of equal or lessor complexity.              */
   /*=========================================================*/

   while (actPtr != NULL)
     {
      if (actPtr->salience > salience)
        {
         lastAct = actPtr;
         actPtr = actPtr->next;
        }
      else if (actPtr->salience < salience)
        { return(lastAct); }
      else if (complexity < (int) actPtr->theRule->complexity)
        {
         lastAct = actPtr;
         actPtr = actPtr->next;
        }
      else if (complexity > (int) actPtr->theRule->complexity)
        { return(lastAct); }
      else if (timetag > actPtr->timetag)
        {
         lastAct = actPtr;
         actPtr = actPtr->next;
        }
      else
        { return(lastAct); }
     }

   /*===========================================*/
   /* Return the insertion point in the agenda. */
   /*===========================================*/

   return(lastAct);
  }

/*********************************************************************/
/* PlaceSimplicityActivation: Determines the location in the agenda  */
/*    where a new activation should be placed for the simplicity     */
/*    strategy. Returns a pointer to the activation  after which the */
/*    new activation should be placed (or NULL if the activation     */
/*    should be placed at the beginning of the agenda).              */
/*********************************************************************/
static ACTIVATION *PlaceSimplicityActivation(
  ACTIVATION *actPtr,
  ACTIVATION *newActivation)
  {
   int salience, complexity;
   unsigned long timetag;
   ACTIVATION *lastAct;

   /*============================================*/
   /* Set up initial information for the search. */
   /*============================================*/

   timetag = newActivation->timetag;
   salience = newActivation->salience;
   complexity = newActivation->theRule->complexity;
   lastAct = NULL;

   /*=========================================================*/
   /* Find the insertion point in the agenda. The activation  */
   /* is placed before activations of lower salience and      */
   /* after activations of higher salience. Among activations */
   /* of equal salience, the activation is placed after       */
   /* activations of equal or greater complexity.             */
   /*=========================================================*/

   while (actPtr != NULL)
     {
      if (actPtr->salience > salience)
        {
         lastAct = actPtr;
         actPtr = actPtr->next;
        }
      else if (actPtr->salience < salience)
        { return(lastAct); }
      else if (complexity > (int) actPtr->theRule->complexity)
        {
         lastAct = actPtr;
         actPtr = actPtr->next;
        }
      else if (complexity < (int) actPtr->theRule->complexity)
        { return(lastAct); }
      else if (timetag > actPtr->timetag)
        {
         lastAct = actPtr;
         actPtr = actPtr->next;
        }
      else
       { return(lastAct); }
     }

   /*===========================================*/
   /* Return the insertion point in the agenda. */
   /*===========================================*/

   return(lastAct);
  }

/*******************************************************************/
/* PlaceRandomActivation: Determines the location in the agenda    */
/*    where a new activation should be placed for the random       */
/*    strategy. Returns a pointer to the activation  after which   */
/*    the new activation should be placed (or NULL if the          */
/*    activation should be placed at the beginning of the agenda). */
/*******************************************************************/
static ACTIVATION *PlaceRandomActivation(
  ACTIVATION *actPtr,
  ACTIVATION *newActivation)
  {
   int salience, randomID;
   unsigned long timetag;
   ACTIVATION *lastAct;

   /*============================================*/
   /* Set up initial information for the search. */
   /*============================================*/

   timetag = newActivation->timetag;
   salience = newActivation->salience;
   randomID = newActivation->randomID;
   lastAct = NULL;

   /*=========================================================*/
   /* Find the insertion point in the agenda. The activation  */
   /* is placed before activations of lower salience and      */
   /* after activations of higher salience. Among activations */
   /* of equal salience, the placement of the activation is   */
   /* determined through the generation of a random number.   */
   /*=========================================================*/

   while (actPtr != NULL)
     {
      if (actPtr->salience > salience)
        {
         lastAct = actPtr;
         actPtr = actPtr->next;
        }
      else if (actPtr->salience < salience)
        { return(lastAct); }
      else if (randomID > actPtr->randomID)
        {
         lastAct = actPtr;
         actPtr = actPtr->next;
        }
      else if (randomID < actPtr->randomID)
       { return(lastAct); }
      else if (timetag > actPtr->timetag)
        {
         lastAct = actPtr;
         actPtr = actPtr->next;
        }
      else
       { return(lastAct); }
     }

   /*===========================================*/
   /* Return the insertion point in the agenda. */
   /*===========================================*/

   return(lastAct);
  }

/******************************************************************/
/* SortPartialMatch: Copies a partial match and then sorts the    */
/*   fact-indices in the copied partial match in ascending order. */
/******************************************************************/
static struct partialMatch *SortPartialMatch(
  void *theEnv,
  struct partialMatch *binds)
  {
   struct partialMatch *nbinds;
   struct alphaMatch *temp;
   int flag, j, k;

   /*=================*/
   /* Copy the array. */
   /*=================*/

   nbinds = CopyPartialMatch(theEnv,binds,0,0);

   /*=================*/
   /* Sort the array. */
   /*=================*/

   for (flag = TRUE, k = binds->bcount - 1;
        flag == TRUE;
        k--)
     {
      flag = FALSE;
      for (j = 0 ; j < k ; j++)
        {
         if ((nbinds->binds[j].gm.theMatch->matchingItem != NULL) &&
             (nbinds->binds[j + 1].gm.theMatch->matchingItem != NULL))
           {
            if (nbinds->binds[j].gm.theMatch->matchingItem->timeTag <
                nbinds->binds[j + 1].gm.theMatch->matchingItem->timeTag)
              {
               temp = nbinds->binds[j].gm.theMatch;
               nbinds->binds[j].gm.theMatch = nbinds->binds[j+1].gm.theMatch;
               nbinds->binds[j+1].gm.theMatch = temp;
               flag = TRUE;
              }
           }
        }
     }

   /*===================*/
   /* Return the array. */
   /*===================*/

   return(nbinds);
  }

/**************************************************************************/
/* ComparePartialMatches: Compares two activations using the lex conflict */
/*   resolution strategy to determine which activation should be placed   */
/*   first on the agenda. This lexicographic comparison function is used  */
/*   for both the lex and mea strategies.                                 */
/**************************************************************************/
static int ComparePartialMatches(
  void *theEnv,
  ACTIVATION *actPtr,
  ACTIVATION *newActivation)
  {
   int cCount, oCount, mCount, i;

   /*=================================================*/
   /* If the activation already on the agenda doesn't */
   /* have a set of sorted timetags, then create one. */
   /*=================================================*/

   if (actPtr->sortedBasis == NULL)
     { actPtr->sortedBasis = SortPartialMatch(theEnv,actPtr->basis); }

   /*==============================================================*/
   /* Determine the number of timetags in each of the activations. */
   /* The number of timetags to be compared is the lessor of these */
   /* two numbers.                                                 */
   /*==============================================================*/

   cCount = newActivation->sortedBasis->bcount;
   oCount = actPtr->sortedBasis->bcount;
   if (oCount > cCount) mCount = cCount;
   else mCount = oCount;

   /*===========================================================*/
   /* Compare the sorted timetags one by one until there are no */
   /* more timetags to compare or the timetags being compared   */
   /* are not equal. If the timetags aren't equal, then the     */
   /* activation containing the larger timetag is placed before */
   /* the activation containing the smaller timetag.            */
   /*===========================================================*/

   for (i = 0 ; i < mCount ; i++)
     {
      if ((actPtr->sortedBasis->binds[i].gm.theMatch->matchingItem != NULL) &&
          (newActivation->sortedBasis->binds[i].gm.theMatch->matchingItem != NULL))
        {
         if (newActivation->sortedBasis->binds[i].gm.theMatch->matchingItem->timeTag <
             actPtr->sortedBasis->binds[i].gm.theMatch->matchingItem->timeTag)
           { return(LESS_THAN); }
         else if (newActivation->sortedBasis->binds[i].gm.theMatch->matchingItem->timeTag >
                  actPtr->sortedBasis->binds[i].gm.theMatch->matchingItem->timeTag)
           { return(GREATER_THAN); }
        }
      else if (newActivation->sortedBasis->binds[i].gm.theMatch->matchingItem != NULL)
        { return(GREATER_THAN); }
      else if (actPtr->sortedBasis->binds[i].gm.theMatch->matchingItem != NULL)
        { return(LESS_THAN); }
     }

   /*==========================================================*/
   /* If the sorted timetags are identical up to the number of */
   /* timetags contained in the smaller partial match, then    */
   /* the activation containing more timetags should be        */
   /* placed before the activation containing fewer timetags.  */
   /*==========================================================*/

   if (cCount < oCount) return(LESS_THAN);
   else if (cCount > oCount) return(GREATER_THAN);

   /*=========================================================*/
   /* If the sorted partial matches for both activations are  */
   /* identical (containing the same number and values of     */
   /* timetags), then the activation associated with the rule */
   /* having the highest complexity is placed before the      */
   /* other partial match.                                    */
   /*=========================================================*/

   if (newActivation->theRule->complexity < actPtr->theRule->complexity)
     { return(LESS_THAN); }
   else if (newActivation->theRule->complexity > actPtr->theRule->complexity)
     { return(GREATER_THAN); }

   /*================================================*/
   /* The two partial matches are equal for purposes */
   /* of placement on the agenda for the lex and mea */
   /* conflict resolution strategies.                */
   /*================================================*/

   return(EQUAL);
  }

/************************************/
/* EnvSetStrategy: C access routine */
/*   for the set-strategy command.  */
/************************************/
globle int EnvSetStrategy(
  void *theEnv,
  int value)
  {
   int oldStrategy;
   
   oldStrategy = AgendaData(theEnv)->Strategy;
   AgendaData(theEnv)->Strategy = value;

   if (oldStrategy != AgendaData(theEnv)->Strategy) EnvReorderAgenda(theEnv,NULL);

   return(oldStrategy);
  }

/************************************/
/* EnvGetStrategy: C access routine */
/*   for the get-strategy command.  */
/************************************/
globle int EnvGetStrategy(
  void *theEnv)
  {
   return(AgendaData(theEnv)->Strategy);
  }

/********************************************/
/* GetStrategyCommand: H/L access routine   */
/*   for the get-strategy command.          */
/********************************************/
globle SYMBOL_HN *GetStrategyCommand(
  void *theEnv)
  {
   EnvArgCountCheck(theEnv,"get-strategy",EXACTLY,0);

   return((SYMBOL_HN *) EnvAddSymbol(theEnv,GetStrategyName(EnvGetStrategy(theEnv))));
  }

/********************************************/
/* SetStrategyCommand: H/L access routine   */
/*   for the set-strategy command.          */
/********************************************/
globle SYMBOL_HN *SetStrategyCommand(
  void *theEnv)
  {
   DATA_OBJECT argPtr;
   char *argument;
   int oldStrategy;
   
   oldStrategy = AgendaData(theEnv)->Strategy;

   /*=====================================================*/
   /* Check for the correct number and type of arguments. */
   /*=====================================================*/

   if (EnvArgCountCheck(theEnv,"set-strategy",EXACTLY,1) == -1)
     { return((SYMBOL_HN *) EnvAddSymbol(theEnv,GetStrategyName(EnvGetStrategy(theEnv)))); }

   if (EnvArgTypeCheck(theEnv,"set-strategy",1,SYMBOL,&argPtr) == FALSE)
     { return((SYMBOL_HN *) EnvAddSymbol(theEnv,GetStrategyName(EnvGetStrategy(theEnv)))); }

   argument = DOToString(argPtr);

   /*=============================================*/
   /* Set the strategy to the specified strategy. */
   /*=============================================*/

   if (strcmp(argument,"depth") == 0)
     { EnvSetStrategy(theEnv,DEPTH_STRATEGY); }
   else if (strcmp(argument,"breadth") == 0)
     { EnvSetStrategy(theEnv,BREADTH_STRATEGY); }
   else if (strcmp(argument,"lex") == 0)
     { EnvSetStrategy(theEnv,LEX_STRATEGY); }
   else if (strcmp(argument,"mea") == 0)
     { EnvSetStrategy(theEnv,MEA_STRATEGY); }
   else if (strcmp(argument,"complexity") == 0)
     { EnvSetStrategy(theEnv,COMPLEXITY_STRATEGY); }
   else if (strcmp(argument,"simplicity") == 0)
     { EnvSetStrategy(theEnv,SIMPLICITY_STRATEGY); }
   else if (strcmp(argument,"random") == 0)
     { EnvSetStrategy(theEnv,RANDOM_STRATEGY); }
   else
     {
      ExpectedTypeError1(theEnv,"set-strategy",1,
      "symbol with value depth, breadth, lex, mea, complexity, simplicity, or random");
      return((SYMBOL_HN *) EnvAddSymbol(theEnv,GetStrategyName(EnvGetStrategy(theEnv))));
     }

   /*=======================================*/
   /* Return the old value of the strategy. */
   /*=======================================*/

   return((SYMBOL_HN *) EnvAddSymbol(theEnv,GetStrategyName(oldStrategy)));
  }

/**********************************************************/
/* GetStrategyName: Given the integer value corresponding */
/*   to a specified strategy, return a character string   */
/*   of the strategy's name.                              */
/**********************************************************/
static char *GetStrategyName(
  int strategy)
  {
   char *sname;

   switch (strategy)
     {
      case DEPTH_STRATEGY:
        sname = "depth";
        break;
      case BREADTH_STRATEGY:
        sname = "breadth";
        break;
      case LEX_STRATEGY:
        sname = "lex";
        break;
      case MEA_STRATEGY:
        sname = "mea";
        break;
      case COMPLEXITY_STRATEGY:
        sname = "complexity";
        break;
      case SIMPLICITY_STRATEGY:
        sname = "simplicity";
        break;
      case RANDOM_STRATEGY:
        sname = "random";
        break;
      default:
        sname = "unknown";
        break;
     }

   return(sname);
  }
#endif /* CONFLICT_RESOLUTION_STRATEGIES */

#endif /* DEFRULE_CONSTRUCT */

