;;;  -*- mode: LISP; Package: CL-USER; Syntax: COMMON-LISP;  Base: 10 -*-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; 
;;; Author      : Mike Byrne
;;; Copyright   : (c)1998-2001 Rice U./CMU/Mike Byrne, All Rights Reserved
;;; Availability: public domain
;;; Address     : Rice University
;;;             : Psychology Department
;;;             : Houston, TX 77251-1892
;;;             : byrne@acm.org
;;; 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; 
;;; Filename    : test-suite.actr
;;; Version     : 2.1b5
;;; 
;;; Description : This is the ACT-R source file containing the productions which
;;;             : will drive the test-suite example.  The task is a fairly 
;;;             : complex one with multiple steps:
;;;             : [1] A "Start" button appears on the screen.  ACT-R/PM finds
;;;             :     that button and clicks on it.
;;;             : [2] After a short random interval, a tone is generated
;;;             :     (this will be heard as a regular beep), and ACT-R/PM
;;;             :     responds "high" if it is a high tone and "low" if it
;;;             :     is a low tone.
;;;             : [3] A random letter will appear at a random location on the
;;;             :     screen.  ACT-R/PM will respond by typing that letter.
;;;             : [4] Either the word "up" or the word "down" will appear at
;;;             :     a random location on the screen.  If the word is "up,"
;;;             :     ACT-R/PM will respond by pressing the "u" key.  If it is
;;;             :     "down," the "m" key is pressed.
;;;             : [5] The phrase "key left" or "key right" will appear on the
;;;             :     screen.  Again, a key response of "s" or "l" is 
;;;             :     generated.
;;;             : [6] Two objects appear on the screen, a star and a circle.
;;;             :     These objects will move.  ACT-R/PM will start to track
;;;             :     the one on the left, and when it reaches the top third
;;;             :     of the window, tracking ends with a mouse click.
;;;             : Note also that there are two right-hand moves here, from
;;;             : the mouse to the keyboard and back.
;;;             : 
;;;             : ACT-R/PM does this task very quickly--this is intended to
;;;             : be a demonstration more than a model, though I suspect
;;;             : that an expert on this task would be about as fast.
;;;             : 
;;;             : To run the simulation, first load the "test-suite.lisp"
;;;             : file.  Then LOAD (don't just evaluate) this file.  Call
;;;             : the (startup) function and then call (sim) or (pm-step).
;;; 
;;; To do       : [] Finish up 5.0 recoding
;;;             : [] New comments on 5.0 mechanisms.
;;; 
;;; ----- History -----
;;; 01.08.06 mdb
;;;             : Started working on 5.0 version.
;;; 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


;;;; ---------------------------------------------------------------------- ;;;;
;;;; Lisp functions

;;; STARTUP      [Function]
;;; Description : Several things have to be done to run an ACT-R/PM model.
;;;             : First, the ACT-R part of the model is reloaded.
;;;             : Then RPM is reset and the window is created and installed.
;;;             : RPM global parameters are set.  Note the setting of the 
;;;             : SPEECH-HOOK-FCT, which is necessary for the environment to
;;;             : "hear" ACT-R/PM's speech.  Note also the setting of 
;;;             : VISUAL-MOVEMENT-TOLERANCE--this should be set to some value
;;;             : greater than 0 if objects are going to be moving around.
;;;             : Also, gotta start the hands at the mouse and process the
;;;             : screen.

(defun startup ()
  "Setup the test-suite simulation."
  (when *experiment* (window-close *experiment*))
  (setf *experiment* (make-instance 'test-window))
  (reload)
  (pm-install-window *experiment*)
  ;  (pm-set-cursor-position 0 0)
  (pm-proc-screen :with-cursor t)
  (window-select (find-window "Listener"))
  )


(defun sim (&optional (time 25.))
  "Run the test-suite simulation."
  (window-select *experiment*)
  (pm-run time)
  (window-select (find-window "Listener")))


;;;; ---------------------------------------------------------------------- ;;;;
;;;; Chunk definitions and set-up

(clear-all)
(pm-reset)
(sgp :era t)

(chunk-type test-suite state)
(chunk-type task-state)
(chunk-type (star (:include visual-object)))
;; don't need an OVAL chunk-type because that's already in RPM

(add-dm 
 (start isa task-state) (sound isa task-state)
 (key1 isa task-state) (key2 isa task-state)
 (key3 isa task-state) (find-track isa task-state)
 (tracking isa task-state) (done isa task-state)
 (goal1 isa test-suite state init)
 (cursor isa chunk) (star isa chunk)
 )
(goal-focus goal1)

(pm-set-params :randomize-time t
               :output-speech t
               :visual-movement-tolerance 2.0
               :conservative-update-visual nil
               :process-cursor t
               :optimize-visual t
               )
(pm-set-params :trace-modules t)
(pm-start-hand-at-mouse)
(pm-attend-location 0 0)
(pm-set-cursor-position 200 20)
(pm-prepare-motor punch :hand right :finger index)
(pm-set-params :show-focus t)


;;;; ---------------------------------------------------------------------- ;;;;
;;;; Productions and production parameters


(p pre-start
   =goal>
     isa	test-suite
     state	init
==>
   +visual-location>
     isa	visual-location
     kind	text
  =goal>
    state	start
)



;;; START
;;; Description : First thing to do is find the button that's on the screen,
;;;             : and move the mouse over to it.

(p start
   =goal>
     isa 	test-suite
     state 	start
   =visual-location>
     isa 	visual-location
   =manual-state>
     isa 	module-state
     modality 	free
   =visual-state>
     isa 	module-state
     modality 	free
==>
   +visual>
     isa	visual-object
     screen-pos =visual-location
   +manual>
     isa	move-cursor
     loc	=visual-location
)


;;; CLICK
;;; Description : One the mouse move is complete (which is the MODULE-STATE
;;;             : test), then we can click the mouse.  Then we can start
;;;             : waiting for the sound.  Run a clear on Vision as well, 
;;;             : since we no longer care about attending the current location.

(p click
   =goal>
     isa 	test-suite
     state 	start
   =visual>
     isa 		text
   =manual-state>
     isa 		module-state
     preparation 	free
==>
   +manual>
     isa		click-mouse
   -visual>
   =goal>
     state sound1)


;;; HOME-HANDS
;;; Description : While we're waiting for the sound, move the right hand 
;;;             : to the keyboard, since we'll need that later.  This is
;;;             : a good time to do this since it won't interfere with
;;;             : hearing or speech production.

(p home-hands
   =goal>
     isa 		test-suite
     state 		sound1
   =manual-state>
     isa 		module-state
     last-command	click-mouse
     modality 		free
==>
   +manual>
     isa		hand-to-home
)


;;; DETECTED-SOUND
;;; Description : When we've detected that there is a sound, attend it
;;;             : so we can tell what it is.

(p detected-sound
   =goal>
     isa 	test-suite
     state 	sound1
   =aural-location>
     isa 	audio-event
     attended 	nil
   =aural-state>
     isa	module-state
     modality	free
==>
   +aural> 
     isa 	sound
     event 	=aural-location
   =goal>
     state	sound2
   -visual-location>
)



;;; SOUND-RESPOND-LOW
;;; Description : When the sound we have is a low tone, respond by
;;;             : speaking "low" and note the change in task state.

(p sound-respond-low
   =goal>
     isa 	test-suite
     state 	sound2
   =aural>
     isa 	sound
     content 	800
==>
   +vocal>
      isa 	speak 
      string	"low"
   =goal>
     state key1
)


;;; SOUND-RESPOND-HIGH
;;; Description : Same as the previous but for a high tone.

(p sound-respond-high
   =goal>
     isa 	test-suite
     state 	sound2
   =aural>
     isa 	sound
     content 	2000
==>
   +vocal>
      isa 	speak 
      string	"high"
   =goal>
     state key1
)



;;; LOOK-FOR-LETTER
;;; Description : When the letter appears, this production will fire to
;;;             : have the Vision Module go and attend it.

(p look-for-letter
   =goal>
     isa 	test-suite
     state 	key1
   =visual-location>
     isa 	visual-location
     kind 	text
   =visual-state>
     isa 	module-state
     modality 	free
==>
   +visual>
     isa	visual-object
     screen-pos	=visual-location
   =goal>
     state	key1p
)

;;; DO-KEY1
;;; Description : Once we've seen the letter, press the key for that 
;;;             : letter and note the change in state.

(p do-key1
   =goal>
     isa 	test-suite
     state 	key1p
   =visual>
     isa 	text
     value 	=key
   =manual-state>
     isa 	module-state
     modality 	free
==>
   +manual>
     isa	press-key
     key	=key
   =goal>
     state	find-key2
   -visual-location>
)



;;; LOOK-FOR-WORD
;;; Description : This will fire when the word appears, and sends Vision
;;;             : off to attend that word.

(p look-for-word
   =goal>
     isa 	test-suite
     state 	find-key2
   =visual-location>
     isa 	visual-location
     kind 	text
   =visual-state>
     isa 	module-state
     modality 	free
==>
   +visual>
     isa	visual-object
     screen-pos	=visual-location
   =goal>
     state	key2
)

;;; DO-KEY2-UP and DO-KEY2-DOWN
;;; Description : When the word has been attended, press the appropriate
;;;             : key and note the change in task state.

(p do-key2-up
   =goal>
     isa 		test-suite
     state 		key2
   =visual>
     isa 		visual-object
     value 		"up"
   =manual-state>
     isa 		module-state
     preparation	free
==>
   +manual> 
     isa 	press-key 
     key	"u"
   =goal>
     state 	key3-look
   -visual-location>
)


(p do-key2-down
   =goal>
     isa 		test-suite
     state 		key2
   =visual>
     isa 		visual-object
     value 		"down"
   =manual-state>
     isa 		module-state
     preparation	free
==>
   +manual> 
     isa 	press-key 
     key	"m"
   =goal>
     state 	key3-look
   -visual-location>
)


;;; LOOK-FOR-PHRASE
;;; Description : Pretty much the same as LOOK-FOR-WORD.

(p look-for-phrase
   =goal>
     isa 	test-suite
     state 	key3-look
   =visual-location>
     isa 	visual-location
     kind 	text
   =visual-state>
     isa 	module-state
     modality 	free
==>
   +visual>
     isa	visual-object
     screen-pos	=visual-location
     scale	phrase
   =goal>
     state  	key3
)

;;; DO-KEY3-LEFT and DO-KEY3-RIGHT
;;; Description : Again, about the same as the DO-KEY2 productions, though
;;;             : we want to run a CLEAR here so that there is no current
;;;             : visual object and the tracking productions won't start
;;;             : firing.

(p do-key3-left
   =goal>
     isa 	test-suite
     state 	key3
   =visual>
     isa 	phrase!
     value 	"key left"
   =manual-state>
     isa 		module-state
     preparation 	free
==>
   +manual>
     isa	press-key 
     key	"s"
   =goal>
     state 	wait-for-track
   -visual>
   -visual-location>
)


(p do-key3-right
   =goal>
     isa 	test-suite
     state 	key3
   =visual>
     isa 	phrase!
     value 	"key right"
   =manual-state>
     isa 		module-state
     preparation 	free
==>
   +manual>
     isa	press-key 
     key	"l"
   =goal>
     state 	wait-for-track
   -visual>
   -visual-location>
)



;;; FIND-TRACK-STAR and FIND-TRACK-OVAL
;;; Description : OK, first thing to do when you want to track an object is
;;;             : to find it and attend it (you can't track an object that 
;;;             : isn't the current focus of attention).  
;;;             : There are two productions for a reason:  there is a third
;;;             : object on the screen, the cursor, and you don't want to
;;;             : start trying to track the cursor.

(p wait-for-track
   =goal>
     isa	test-suite
     state	wait-for-track
   =visual-location>
     isa	visual-location
==>
   =goal>
     state	find-track
)

#|
(p find-track-star
   =goal>
     isa 	test-suite
     state 	find-track
   !bind! =x 150
   =visual-state>
     isa 	module-state
     modality 	free
==>
   +visual-location>
     isa	visual-location
     attended	nil
     value	star
     screen-x	(less-than =x)
   =goal>
     state	attn-track
)

(p find-track-oval
   =goal>
     isa 	test-suite
     state 	find-track
   !bind! =x 150
   =visual-state>
     isa 	module-state
     modality 	free
==>
   +visual-location>
     isa	visual-location
     attended	nil
     value	oval
     screen-x	(less-than =x)
   =goal>
     state	attn-track
)
|#


(p attend-track
   =goal>
     isa 	test-suite
     state 	find-track
   =visual-location>
     isa	visual-location
   =visual-state>
     isa	module-state
     modality	free
==>
   +visual>
     isa	visual-object
     screen-pos	=visual-location
   =goal>
     state	track
)

;;; BEGIN-TRACKING
;;; Description : Once we have an object in the focus of visual attention,
;;;             : start tracking it and note that we're tracking.

(p begin-tracking
   =goal>
     isa 	test-suite
     state 	track
   =visual>
     isa 	visual-object
     value 	=val
   =visual-state>
     isa 	module-state
     execution free
==>
   +visual>
      isa	start-tracking
      object	=visual
   !output! ("ее Tracking the ~S" =val)
   =goal>
     state tracking
)


;;; RETURN-HAND-TO-MOUSE
;;; Description : When the tracked object is responded to, it's with a click.
;;;             : So move the hands back to the mouse.  Note the test of the
;;;             : previous motor command--without it, this production will get
;;;             : called over and over.

(p return-hand-to-mouse
   =goal>
     isa 	test-suite
     state 	tracking
   =visual-state>
     isa 	module-state
     execution 	busy
   =manual-state>
     isa 		module-state
     modality 		free
     last-command 	press-key
==>
   +manual>
     isa	hand-to-mouse
)




;;; RESPOND-TO-TRACK
;;; Description : The last action, click in response to the position of the
;;;             : tracked object.  (This is an illustration of how you get
;;;             : the current position of a tracked object.)

(p respond-to-track
   =goal>
     isa 	test-suite
     state 	tracking
   =visual-state>
     isa 	module-state
     execution 	busy
   =visual>
     isa 	visual-object
     screen-pos =loc
   =loc>
     isa 	visual-location
     screen-y 	=y
   =manual-state>
     isa 	module-state
     modality 	free
   !eval! (< =y 100)
==>
   +manual>
     isa	click-mouse
   -visual>
   =goal>
     state done)


;;; FINISHED
;;; Description : When everything is done, pop the top goal.  Note that this
;;;             : production checks the state of the Motor Module.  Why? 
;;;             : If not, this production will fire immediately after the 
;;;             : last command is issued, not after it is completed.

(p finished
   =goal>
     isa 	test-suite
     state 	done
   =manual-state>
     isa 	module-state
     modality 	free
==>
   !pop!)