001    package aima.search.framework;
002    
003    import java.util.ArrayList;
004    import java.util.List;
005    import aima.basic.Agent;
006    import aima.basic.Percept;
007    import aima.util.Util;
008    
009    /**
010     * Artificial Intelligence A Modern Approach (2nd Edition): Figure 3.1, page 61.
011     * <code>
012     * function SIMPLE-PROBLEM-SOLVING-AGENT(percept) returns an action
013     *   inputs: percept, a percept
014     *   static: seq, an action sequence, initially empty
015     *           state, some description of the current world state
016     *           goal, a goal, initially null
017     *           problem, a problem formulation
018     *           
019     *   state <- UPDATE-STATE(state, percept)
020     *   if seq is empty then do
021     *     goal    <- FORMULATE-GOAL(state)
022     *     problem <- FORMULATE-PROBLEM(state, goal)
023     *     seq     <- SEARCH(problem)
024     *   action <- FIRST(seq)
025     *   seq <- REST(seq)
026     * </code>
027     * Figure 3.1 A simple problem-solving agent. It first formulates a goal and a problem,
028     * searches for a sequence of actions that would solve the problem, and then executes the actions
029     * one at a time. When this is complete, it formulates another goal and starts over. Note that
030     * when it is executing the sequence it ignores its percepts: it assumes that the solution it has
031     * found will always work.
032     */
033    
034    /**
035     * @author Ciaran O'Reilly
036     * 
037     */
038    public abstract class SimpleProblemSolvingAgent extends Agent {
039    
040            // seq, an action sequence, initially empty
041            private List<String> seq = new ArrayList<String>();
042    
043            //
044            private boolean formulateGoalsIndefinitely = true;
045    
046            private int maxGoalsToFormulate = 1;
047    
048            private int goalsFormulated = 0;
049    
050            public SimpleProblemSolvingAgent() {
051                    formulateGoalsIndefinitely = true;
052            }
053    
054            public SimpleProblemSolvingAgent(int maxGoalsToFormulate) {
055                    formulateGoalsIndefinitely = false;
056                    this.maxGoalsToFormulate = maxGoalsToFormulate;
057            }
058    
059            // function SIMPLE-PROBLEM-SOLVING-AGENT(percept) returns an action
060            @Override
061            public String execute(Percept p) {
062                    String action = NO_OP;
063    
064                    // state <- UPDATE-STATE(state, percept)
065                    Object state = updateState(p);
066                    // if seq is empty then do
067                    if (0 == seq.size()) {
068                            if (formulateGoalsIndefinitely
069                                            || goalsFormulated < maxGoalsToFormulate) {
070                                    if (goalsFormulated > 0) {
071                                            notifyViewOfMetrics();
072                                    }
073                                    // goal <- FORMULATE-GOAL(state)
074                                    Object goal = formulateGoal();
075                                    goalsFormulated++;
076                                    // problem <- FORMULATE-PROBLEM(state, goal)
077                                    Problem problem = formulateProblem(goal);
078                                    // seq <- SEARCH(problem)
079                                    seq.addAll(search(problem));
080                                    if (0 == seq.size()) {
081                                            // Unable to identify a path
082                                            seq.add(NO_OP);
083                                    }
084                            } else {
085                                    // Agent no longer wishes to
086                                    // achieve any more goals
087                                    die();
088                                    notifyViewOfMetrics();
089                            }
090                    }
091    
092                    if (seq.size() > 0) {
093                            // action <- FIRST(seq)
094                            action = Util.first(seq);
095                            // seq <- REST(seq)
096                            seq = Util.rest(seq);
097                    }
098    
099                    return action;
100            }
101    
102            //
103            // PROTECTED METHODS
104            //
105            protected abstract Object updateState(Percept p);
106    
107            protected abstract Object formulateGoal();
108    
109            protected abstract Problem formulateProblem(Object goal);
110    
111            protected abstract List<String> search(Problem problem);
112    
113            protected abstract void notifyViewOfMetrics();
114    }