Smarty, the Autonomous Detective

(define (make-autonomous-detective name birthplace murder-details characteristics)
  (let ((person (make-person name birthplace characteristics))
	(crime-details murder-details)
	(alibi-room 'nowhere)
	(alibi-possessions 'nothing)
	(alibi-witnesses 'nobody)
	(solved #f)
	(nice-try #f)
	(room nil)
	(missing-people '(colonel-mustard  miki miss-scarlet mrs-peacock professor-plum mr-green mrs-white))
	(suspects nil)
	(count 0))
    (lambda (message)
      (case message
	((autonomous-person?) (lambda (self) #t))
	((install)
	 (lambda (self)
	   (add-to-clock-list self)
	   (delegate person self 'install)))
	((guess)
	 (lambda (self room weapon murderer)
	    (if ( (crime-details 'check) room weapon murderer)
		(begin
		  (display-message (list "You got it right!! (This was your guess # "
				       (+ 1 count) ")"))
		  (set! solved #t))
		(begin
		  (set! count (+ 1 count))
		  (display-message (list "Hm.. not quite.."))
		  #f))))
	((SAVE-STATE)  ;; remember information for an alibi
	 (lambda (self)
	   (set! alibi-room (ask  (ask self 'LOCATION) 'NAME))
	   (let ((holdings (map (lambda (x) (ask x 'NAME)) (ask self 'POSSESSIONS)))
		 (other-people (map (lambda (x) (ask x 'NAME)) 
				    (other-people-at-place self (ask self 'LOCATION)))))
	     (if (not (null? holdings))
		 (set! alibi-possessions holdings))
	     (if (not (null? other-people))
		 (set! alibi-witnesses  other-people)))
	   'ok))
	((ALIBI)
	 (lambda (self)
	   (if  (eq? alibi-room 'nowhere)
		(ask self 'SAY '("Has a murder been committed?"))
		(begin
		  (ask self 'SAY (list "Me?  I was in the" alibi-room))
		  (ask self 'SAY (list "I had in my possession:" alibi-possessions))
		  (ask self 'SAY (list "Oh, and" alibi-witnesses 
				       "was in the room with me"))))
	   (list alibi-room alibi-possessions alibi-witnesses)))
	 ((clock-tick)
	  (lambda (self)

	    (define next-place
	      (let ((loc (ask (ask self 'location) 'name)))
		(define (help loc)
		  (cond ((eq? loc 'dining-room) 'north)
			((eq? loc 'hall) 'west)
			((eq? loc 'foyer) 'north)
			((eq? loc 'study) 'south)
			((eq? loc 'library) 'south)
			((eq? 'billiard-room loc) 'south)
			((eq? loc 'conservatory) 'east)
			((eq? loc 'ballroom) 'east)
			((eq? loc 'kitchen) 'north)
			(else (display-message (list "We've got a problem")))))
		(if (eq? loc 'lounge)
		    (begin
		      (ask self 'go 'south)
		      (ask self 'go 'west))
		    (ask self 'go (help loc)))))

	    (define (helper room)    
      (cond ((and (filter (lambda (x) (eq? x 'magnifying-glass))
				    (ask self 'look-around))
			    (not (filter (lambda (x) (eq? x 'magnifying-glass))
					 (ask self 'list-possessions))))
		       (begin
			 (display-message (list "I've got the glass"))
			 (ask self 'take (car (filter (lambda (x) (eq? (ask x 'name)
								  'magnifying-glass))
						 (ask (ask self 'location) 'things))))))
       ((null? (cdr missing-people))
	     (display-message (list "no missing people"))
	     (let* ((weaps (filter (lambda (x) (filter (lambda (y) (eq? x (ask y 'name)))
						       *weapons*))
				   (ask self 'look-around)))
		    (weps (filter (lambda (x)
				    (filter (lambda (y)
					      (filter (lambda (a)
							(eq? a y))
						      (ask self 'look-at-weapon
							   (car (filter (lambda (c)
									  (eq? (ask c 'name)
									       x))
									(ask (ask self
										  'location)
									     'things))))))
										   
					      suspects))
				    weaps)))
	       (begin
		 (display-message (list weps))
		 (map (lambda (x)
			(map (lambda (y)
			       (begin
				 (display (list (ask room 'name) x y))
				 
				 (ask self 'guess
				      (ask room 'name)
				      x
				      y)))
			     (filter (lambda (a)
				       (filter (lambda (b) (eq? a b))
					       (ask self 'look-at-weapon
						    (car (filter (lambda (c)
								   (eq? (ask c 'name)
									x))
								 (ask (ask self
									   'location)
								      'things))))))
				       suspects)))
			weps)		    
		 (display-message (list "Smarty says: I'm going away from" (ask (ask self 'location) 'name)))
		    next-place)))


	    (else (display-message (list "second part"))
	     (let* ((souls (filter (lambda (x) (filter (lambda (y) (eq? x (ask y 'NAME)))
							     *the-cast*))
					(ask self 'look-around)))
		    (new-souls (filter (lambda (x) (filter (lambda (y)
							     (not (eq? y x)))
							   missing-people))
				       souls))
		    (new-suspects (filter (lambda (x)
					    (eq? (car (ask x 'alibi)) (ask room 'name)))
					     (filter (lambda (y)
						       (memq (ask y 'name) souls))
						     (ask (ask self 'location) 'things)))))

		    (begin
		    (if (not (null? new-suspects))
			(set! new-suspects (map (lambda (x) (ask x 'name)) new-suspects))
			#f)
		    (display-message (list souls "a" new-souls "a" new-suspects "a" missing-people))
		    (set! missing-people (filter (lambda (x) (not (memq x new-souls)))
						 missing-people))
		    (display-message (list missing-people))
		    (if (not (null? new-suspects))
			(set! suspects (append new-suspects suspects)))
		    (display-message (list suspects))
		    
		    (display-message (list "Smarty says: I'm going away from" (ask (ask self 'location) 'name)))
		    next-place)))))



	    (if (ask heaven 'things)
		(if (not nice-try)
		(cond ((and (filter (lambda (x) (eq? x 'magnifying-glass))
				    (ask self 'look-around))
			    (not (filter (lambda (x) (eq? x 'magnifying-glass))
					 (ask self 'list-possessions))))
		       (begin
			 (display-message (list "I've got the glass"))
			 (ask self 'take (car (filter (lambda (x) (eq? (ask x 'name)
								  'magnifying-glass))
						 (ask (ask self 'location) 'things))))))

		      ((not (memq 'bloodstain
				    (ask self 'look-around)))
		       (begin (display-message (list "Smarty says: I'm going away from" (ask (ask self 'location) 'name)))
		       next-place))
		      ((filter (lambda (x) (filter (lambda (y)
						     (eq? x (ask y 'name))) *weapons*))
				    (ask self 'look-around))
		       (set! room (ask self 'location))
		       (if (not (memq 'magnifying-glass
					(ask self 'list-possessions)))
			   (begin
			     (display-message (list "Smarty says: I'm going away from" (ask (ask self 'location) 'name)))
			   next-place)
			   (begin 
			     (map (lambda (x)
				    (map (lambda (y)
					   (begin
					     (display-message (list
							       (ask (ask self 'location) 'name)
							       x y))
					     (ask self 'guess
						  (ask (ask self 'location) 'name)
						  x
						  y)))
					 (ask self 'look-at-weapon (car (filter (lambda (c)
								   (eq? (ask c 'name)
									x))
								 (ask (ask self
									   'location)
								      'things))))))
				  (filter (lambda (a) (filter (lambda (b) (eq? a (ask b 'name))) *weapons*))
					  (ask self 'look-around)))
			     (if (not solved) (begin (set! nice-try #t) (display-message (list "nice try is true now"))))
			     (display-message (list "Smarty says: I'm going away from" (ask (ask self 'location) 'name)))
			     next-place)))
		      (else (begin (set! nice-try #t)
				   (set! room (ask self 'location))
				   (display-message (list "no weapons, nice try = true")))))
		(if (not solved)
		    (begin (display-message (list "starting helper"))
			   (helper room))))
		(begin (display-message (list "Smarty says: What a boring world!"))
		       #f))))
	 (else (get-method message person))))))