Lab 2: Comparing Agent Programs

In this lab session we will finish lab 1 and write a new kind of agent program mantaining a state.

  1. Getting Started:
    Start by getting the file agents2.zip and unzipping it into your working directory. This is largely the same file as we had for the last lab session, except some fixes to accommodate agents having a state, and code to run experiments.
    1. In order to run the experiments later, you can use both functions: random-agent-program and random-agent-measure from lab 1 (that means you can copy them in the new file agents2.lisp =));
    2. You only have to change the random-agent-program declaration in order to accommodate a small change in the way the function is called during experiments.
      ;; OLD declaration
      (defun random-agent-program (percept)
      ;; NEW declaration
      (defun random-agent-program (agent percept)
  2. Creating an Agent Program with a State:
    Fill in the function RANDOM-AGENT-WITH-STATE-PROGRAM, found in agents2.lisp. This should be the program of an agent that:
    • Uses the STATE field of the agent struct to remember what squares has already visited (and eventually cleaned). Remember you can use this field in this way:
      ;; HINT: getting the value of the state field in the agent structure
      (agent-state agent)
      ;; HINT: setting a new value for the state field
      (setf (agent-state agent) <new value>)
    • The agent should walk randomly, but it should avoid revisiting squares that has already visited (and then already cleaned up).
    • The agent's objective is to clean the whole environment.
    • The agent should return the 'suck action when visiting a dirty square otherwise one of the following actions: 'right, 'left, 'up or 'down.
    • If the agent is sure everything is clean, it should return the action 'idle (i.e. forever).
    • Be careful to not being too much strict, e.g. if it is absolutely impossible for the agent to travel through clean squares. Can it get in troubles so that it is unable to meet its objective? If so, find a solution.
    • NOTE 1: when you are ready to fill in the agent program code you'll see that the agent stores the state as a list of squares id that it has seen (and clean) already. It would be useful for you to remember the following regarding lists:
      ;; HINT: getting the first item in a list
      CL-USER> (first '(a b c))
      A
      ;; HINT: adding an element to a list.
      ;; cons takes an item and a list, and returns a new list consisting of 
      ;; the old list with the item tacked on the front.
      CL-USER> (setf my-list '(a b c))
      (A B C)
      CL-USER> (setf my-list (cons 'item my-list))
      (ITEM A B C)
      ;; HINT: checking for a list argument.
      ;; consp is a predicate which is true if its argument is a list...
      CL-USER> (consp '(4 3 8))
      T
      ;; ...but is not nil
      CL-USER> (consp nil)
      NIL
    • NOTE 2: in order to keep track of the squares already seen, you can use two helper functions (see agents2.lisp for more details): SQUARE-ID and GET-NEIGHBOURS. The following picture show an example of possible 3×3 environment (w x h, width and height = 3) and how unique id are assigned to each square:
  3. Running Experiments:
    Deal with the lines at the bottom of agents2.lisp to run experiments and evaluate your agent. The following lines, for example, allow you to try the EXAMPLE-AGENT-PROGRAM on all the possible 3×3 environments with 2 dirty squares (that is all the permutations of 2 dirty squares out of 3×3 = 9 squares in total). For each 3×3 generated environment, the agent program is executed for 1000 steps and then automatically turned-off. Check this out entering these few lines in the REPL:
    ;; HINT: remember to load the definitions in "agent2.lisp" as shown in step 7 of Lab 1.
    (run-experiment (generate-environments 3 3 2)
    	        (lambda () (make-agent :program #'example-agent-program))
                    #'example-measure
                    1000)

    This will return the number of experiments performed, and the average performance value.

  4. Comparing Different Agents:
    Try different agents (e.g. random-agent-program) and different performance measures. Does the agent with state behave better than the others with any particular performance measure? You can add print commands to the experiment functions to get more information about the agents behaviour if you like.
  5. Building an Orderly Agent (EXTRA):
    Try to create an agent called orderly-moving-agent-program that moves through the environment with some orderly pattern (i.e. from left to right, then down, right to left, down and so on…). Make sure it visits all the squares and cleans the dirty ones. Is the orderly agent more efficient than the random one?