src/engine/Engine.js
function actionsSelector(goalTrees) {
    const recursiveActionsSelector = (actionsSoFar, programSoFar, l) => {
      if (l >= goalTrees.length) {
        let actions = new LiteralTreeMap();
        actionsSoFar.forEach((map) => {
          map.forEach((literal) => {
            actions.add(literal);
          });
        });
        return actions;
      }
      let goalTree = goalTrees[l];
      let resultSet = null;
      goalTree.forEachCandidateActions(_currentTime, (candidateActions) => {
        let cloneProgram = programSoFar.clone();

        let cloneExecutedActions = cloneProgram.getExecutedActions();
        candidateActions.forEach((a) => {
          cloneExecutedActions.add(a);
        });

        // pre-condition check
        if (!checkConstraintSatisfaction.call(this, cloneProgram)) {
          return false;
        }

        // post condition checks
        let clonePostProgram = programSoFar.clone();
        clonePostProgram.setExecutedActions(new LiteralTreeMap());
        let postState = clonePostProgram.getState();
        updateStateWithFluentActors(
          this,
          candidateActions,
          postState
        );
        clonePostProgram.setState(postState);

        if (!checkConstraintSatisfaction.call(this, clonePostProgram)) {
          return false;
        }

        resultSet = recursiveActionsSelector(
          actionsSoFar.concat([candidateActions]),
          cloneProgram,
          l + 1
        );
        return true;
      });

      if (resultSet !== null) {
        return resultSet;
      }

      return recursiveActionsSelector(
        actionsSoFar,
        programSoFar,
        l + 1
      );
    };

    return recursiveActionsSelector([], _program, 0);
  }
function actionsSelector(goalTrees) {
    const recursiveActionsSelector = (actionsSoFar, programSoFar, l) => {
      if (l >= goalTrees.length) {
        let actions = new LiteralTreeMap();
        actionsSoFar.forEach((map) => {
          map.forEach((literal) => {
            actions.add(literal);
          });
        });
        return actions;
      }
      let goalTree = goalTrees[l];
      let resultSet = null;
      goalTree.forEachCandidateActions(_currentTime, (candidateActions) => {
        let cloneProgram = programSoFar.clone();

        let cloneExecutedActions = cloneProgram.getExecutedActions();
        candidateActions.forEach((a) => {
          cloneExecutedActions.add(a);
        });

        // pre-condition check
        if (!checkConstraintSatisfaction.call(this, cloneProgram)) {
          return false;
        }

        // post condition checks
        let clonePostProgram = programSoFar.clone();
        clonePostProgram.setExecutedActions(new LiteralTreeMap());
        let postState = clonePostProgram.getState();
        updateStateWithFluentActors(
          this,
          candidateActions,
          postState
        );
        clonePostProgram.setState(postState);

        if (!checkConstraintSatisfaction.call(this, clonePostProgram)) {
          return false;
        }

        resultSet = recursiveActionsSelector(
          actionsSoFar.concat([candidateActions]),
          cloneProgram,
          l + 1
        );
        return true;
      });

      if (resultSet !== null) {
        return resultSet;
      }

      return recursiveActionsSelector(
        actionsSoFar,
        programSoFar,
        l + 1
      );
    };

    return recursiveActionsSelector([], _program, 0);
  }
Select the appropriate set of actions from the given goal trees such that
constraints are not violated for the current cycle.
@param  {Array<GoalTree>} goalTrees The goal trees to choose actions from
@return {LiteralTreeMap}            The set of actions chosen to execute