001    package aima.basic.vaccum;
002    
003    import java.util.Set;
004    
005    import aima.basic.Agent;
006    import aima.basic.AgentProgram;
007    import aima.basic.ObjectWithDynamicAttributes;
008    import aima.basic.Percept;
009    import aima.basic.simplerule.Rule;
010    
011    /**
012     * Artificial Intelligence A Modern Approach (2nd Edition): Figure 2.12, page 49.
013     * <code>
014     * function REFLEX-AGENT-WITH-STATE(percept) returns an action
015     *   static state, a description of the current world state
016     *          rules, a set of condition-action rules
017     *          action, the most recent action, initially none
018     *   
019     *   state  <- UPDATE-STATE(state, action, percept)
020     *   rule   <- RULE-MATCH(state, rules)
021     *   action <- RULE-ACTION(rule)
022     *   return action
023     * </code>
024     * Figure 2.12 A model-based reflex agent. It keeps track of the current state of the world
025     * using an internal model. It then chooses an action in the same way as the reflex agent.
026     */
027    
028    /**
029     * @author Ciaran O'Reilly
030     * 
031     */
032    public abstract class ReflexAgentWithStateProgram extends AgentProgram {
033            //
034            // static state, a description of the current world state
035            private ObjectWithDynamicAttributes state = null;
036    
037            // rules, a set of condition-action rules
038            private Set<Rule> rules = null;
039    
040            // action, the most recent action, initially none
041            private String action = null;
042    
043            public ReflexAgentWithStateProgram() {
044                    init();
045                    // Implementors of the init() method should have ensured the state and
046                    // rules are setup
047                    assert (null != state);
048                    assert (null != rules);
049            }
050    
051            public void setState(ObjectWithDynamicAttributes aState) {
052                    state = aState;
053            }
054    
055            public void setRules(Set<Rule> aRuleSet) {
056                    rules = aRuleSet;
057            }
058    
059            // function REFLEX-AGENT-WITH-STATE(percept) returns an action
060            @Override
061            public String execute(Percept percept) {
062                    // state <- UPDATE-STATE(state, action, percept)
063                    state = updateState(state, action, percept);
064                    // rule <- RULE-MATCH(state, rules)
065                    Rule rule = ruleMatch(state, rules);
066                    // action <- RULE-ACTION(rule)
067                    action = ruleAction(rule);
068                    // return action
069                    return action;
070            }
071    
072            //
073            // PROTECTED METHODS
074            //
075    
076            /**
077             * Realizations of this class should implement the init() method so that it
078             * calls the setState() and setRules() method.
079             */
080            protected abstract void init();
081    
082            protected abstract ObjectWithDynamicAttributes updateState(
083                            ObjectWithDynamicAttributes envState, String anAction,
084                            Percept percept);
085    
086            protected Rule ruleMatch(ObjectWithDynamicAttributes envState,
087                            Set<Rule> rulesSet) {
088                    for (Rule r : rulesSet) {
089                            if (r.evaluate(envState)) {
090                                    return r;
091                            }
092                    }
093                    return null;
094            }
095    
096            protected String ruleAction(Rule r) {
097                    return null == r ? Agent.NO_OP : r.getAction();
098            }
099    }