package aima.core.environment.vacuum; import java.util.LinkedList; import aima.core.agent.Action; import aima.core.agent.Percept; import aima.core.agent.impl.AbstractAgent; import aima.core.agent.impl.NoOpAction; import aima.core.search.framework.PerceptToStateFunction; import aima.core.search.nondeterministic.AndOrSearch; import aima.core.search.nondeterministic.IfStateThenPlan; import aima.core.search.nondeterministic.NondeterministicProblem; import aima.core.search.nondeterministic.Plan; /** * This agent traverses the NondeterministicVacuumEnvironment using a * contingency plan. See page 135, AIMA3e. * * @author Andrew Brown */ public class NondeterministicVacuumAgent extends AbstractAgent { private NondeterministicProblem problem; private PerceptToStateFunction ptsFunction; private Plan contingencyPlan; private LinkedList<Object> stack = new LinkedList<Object>(); public NondeterministicVacuumAgent(PerceptToStateFunction ptsFunction) { setPerceptToStateFunction(ptsFunction); } /** * Returns the search problem for this agent. * * @return the search problem for this agent. */ public NondeterministicProblem getProblem() { return problem; } /** * Sets the search problem for this agent to solve. * * @param problem * the search problem for this agent to solve. */ public void setProblem(NondeterministicProblem problem) { this.problem = problem; init(); } /** * Returns the percept to state function of this agent. * * @return the percept to state function of this agent. */ public PerceptToStateFunction getPerceptToStateFunction() { return ptsFunction; } /** * Sets the percept to state functino of this agent. * * @param ptsFunction * a function which returns the problem state associated with a * given Percept. */ public void setPerceptToStateFunction(PerceptToStateFunction ptsFunction) { this.ptsFunction = ptsFunction; } /** * Return the agent contingency plan * * @return the plan the agent uses to clean the vacuum world */ public Plan getContingencyPlan() { if (this.contingencyPlan == null) { throw new RuntimeException("Contingency plan not set."); } return this.contingencyPlan; } /** * Execute an action from the contingency plan * * @param percept * @return an action from the contingency plan. */ @Override public Action execute(Percept percept) { // check if goal state VacuumEnvironmentState state = (VacuumEnvironmentState) this .getPerceptToStateFunction().getState(percept); if (state.getLocationState(VacuumEnvironment.LOCATION_A) == VacuumEnvironment.LocationState.Clean && state.getLocationState(VacuumEnvironment.LOCATION_B) == VacuumEnvironment.LocationState.Clean) { return NoOpAction.NO_OP; } // check stack size if (this.stack.size() < 1) { if (this.contingencyPlan.size() < 1) { return NoOpAction.NO_OP; } else { this.stack.push(this.getContingencyPlan().removeFirst()); } } // pop... Object currentStep = this.stack.peek(); // push... if (currentStep instanceof Action) { return (Action) this.stack.pop(); } // case: next step is a plan else if (currentStep instanceof Plan) { Plan newPlan = (Plan) currentStep; if (newPlan.size() > 0) { this.stack.push(newPlan.removeFirst()); } else { this.stack.pop(); } return this.execute(percept); } // case: next step is an if-then else if (currentStep instanceof IfStateThenPlan) { IfStateThenPlan conditional = (IfStateThenPlan) this.stack.pop(); this.stack.push(conditional.ifStateMatches(percept)); return this.execute(percept); } // case: ignore next step if null else if (currentStep == null) { this.stack.pop(); return this.execute(percept); } else { throw new RuntimeException("Unrecognized contingency plan step."); } } // // PRIVATE METHODS // private void init() { setAlive(true); stack.clear(); AndOrSearch andOrSearch = new AndOrSearch(); this.contingencyPlan = andOrSearch.search(this.problem); } }