;;; -*- Mode: Lisp; Syntax: Common-Lisp; -*- ;;;; The basic environment simulator code ;;; A "world" or environment has fields for its current state and ;;; for the list of agents that inhabit it. Most of the additional ;;; functionality will be defined by "subclass" worlds. In this ;;; file we also provide a few functions for running a simulation of ;;; and environment and its contained agents. (defstruct (environment (:print-function print-environment)) "The world in which agents exist." (agents '()) ;; A list of the agents in the environment (step 0) ;; The number of time steps simulated so far (max-steps 1000) ;; Stop the simulation after this number (stream t) ;; Stream to display output on (initialized nil) ;; Have we run initialize on this environment yet? (state nil)) ;; Current state of the environment; other subtypes ;; add new slots to hold various state information (defun print-environment (env stream depth) (declare (ignore depth)) (format stream "#<~A; Step: ~D, Agents:~{ ~A~}>" (type-of env) (environment-step env) (environment-agents env))) ;;;*********************************************************************** ;;;; Generic Functions that must be defined for each environment ;;; For each new type of environment you want to define, you will need a ;;; defstruct that includes the ENVIRONMENT data type, and you will need ;;; to write new methods (or inherit existing methods) for each of the ;;; following eight functions. ;;; There are four that will change for each new environment (and must be ;;; overridden in the subclass: ;;; GET-PERCEPT UPDATE-FUN ;;; PERFORMANCE-MEASURE LEGAL-ACTIONS ;;; Others can usually be inherited down without change: ;;; INITIALIZE TERMINATION? ;;; DISPLAY-ENVIRONMENT (defmethod get-percept ((env environment) agent) "Return the percept for this agent." (declare-ignore env agent) nil) ;;; The more specialized worlds will often want to do something ;;; in addition to executing an action for each agent, so they ;;; will probably over-ride UPDATE-FUN but call EXECUTE-AGENT-ACTIONS ;;; directly. (defmethod update-fn ((env environment)) "Modify the environment, based on agents actions, etc. Each agent (if the agent is alive and has specified a legal action) takes its action." (execute-agent-actions env)) (defun execute-agent-actions (env) (dolist (agent (environment-agents env)) (let ((act (agent-action agent))) (when (member (op act) (legal-actions env)) (apply (op act) env (agent-body agent) (args act)))))) ;;;************* (defmethod legal-actions ((env environment)) "A list of the action operators that an agent can do." nil) (defmethod performance-measure ((env environment) agent) "Return a number saying how well this agent is doing." ;; The default is to subtract one point for each time step. (declare-ignore agent) (- (environment-step env))) ;;; Here are the ones that can usually be inherited: (defmethod initialize ((env environment)) "Called once to do whatever is necessary to set up the environment for running the simulation." (initialize-agent-names env) (setf (environment-initialized env) t) env) (defun initialize-agent-names (env) "Name the agents 1, 2, ... if they don't yet have a name." (dolist (agent (environment-agents env)) (when (null (agent-name agent)) (let ((i (+ 1 (position agent (environment-agents env)))) (body (agent-body agent))) (setf (agent-name agent) i) (when (and body (null (sim-object-name body))) (setf (sim-object-name body) i)))))) (defmethod termination? ((env environment)) "Return true if the simulation should end now." nil) (defmethod display-environment ((env environment)) "Display the current state of the environment." ;; You probably won't need to specialize this, unless you want to do ;; a fancy graphical user interface (let ((stream (environment-stream env))) (when stream (format stream "~&At Time step ~D:~%" (environment-step env)) (when (> (environment-step env) 0) (dolist (agent (environment-agents env)) (format stream "~&Agent ~A perceives ~A~%~6Tand does ~A~%" agent (agent-percept agent) (agent-action agent)))) (display-environment-snapshot env)))) (defmethod display-environment-snapshot ((env environment)) "Display a 'picture' of the current state of the environment." ;; This is what you will specialize (print env (environment-stream env))) ;;;******************************************************************* ;;;; Top level function to run an environment (defun run-environment (env) "Basic environment simulator. It gives each agent its percept, gets an action from each agent, and updates the environment. It also keeps score for each agent, and optionally displays intermediate results. [p 48]" (initialize env) (display-environment env) (dotimes (i (environment-max-steps env)) (incf (environment-step env)) ;; Deliver percept and get action from each agent (dolist (agent (environment-agents env)) (setf (agent-percept agent) (get-percept env agent)) (setf (agent-action agent) (funcall (agent-program agent) agent (agent-percept agent)))) ;; Execute the actions and otherwise update the world (update-fn env) ;; Update the agent scores, then optionally display the current state (dolist (agent (environment-agents env)) (setf (agent-score agent) (performance-measure env agent))) (display-environment env) (when (termination? env) (RETURN))) env)