;; This file contains excerpts from the textbook Concrete ;; Abstractions: An Introduction to Computer Science Using Scheme, by ;; Max Hailperin, Barbara Kaiser, and Karl Knight, Copyright (c) 1998 ;; by Brooks/Cole Publishing Company. This file may not be reproduced ;; or redistributed other than for use with that textbook. ;; Chapter 7: Lists ;; 7.6 An Application: A Movie Query System (define make-pattern/action (lambda (pattern action) (cons pattern action))) (define pattern car) (define action cdr) ;; Chapter 14: Object-Oriented Programming ;; 14.5 An Application: Adventures in the Imaginary Land of Gack (define difficulty 1) (define play (lambda () (define loop (lambda () (newline) (let ((user-input (read))) (if (equal? user-input '(quit)) 'done (begin (respond-to-using user-input gack-p/a-list) (loop)))))) (newline) (display "Enter your name, using one word only, please.") (newline) (person/change-name player (read)) (display-message (list "OK," (person/name player) "enter your commands one by one" "as scheme lists; to get help enter (help).")) (loop))) (define gack-p/a-list (list (make-pattern/action '(help) (lambda () (newline) (display "Possibilities:") (newline) (for-each (lambda (command) (display " ") (display command) (newline)) '((help) (quit) (drop thing) (lose thing) (take thing) (go direction) (read scroll) (inventory) (list possessions) (look) (look around) (say ...))) (newline))) (make-pattern/action (list '(drop lose) thing?) (lambda (verb thing) (person/lose player thing) (registry/trigger-times registry difficulty))) (make-pattern/action (list 'take thing?) (lambda (thing) (person/take player thing) (registry/trigger-times registry difficulty))) (make-pattern/action '(go _) (lambda (direction) (person/go player direction) (registry/trigger-times registry difficulty))) (make-pattern/action (list 'read scroll?) (lambda (scroll) (person/read player scroll) (registry/trigger-times registry difficulty))) (make-pattern/action '(inventory) (lambda () (person/list-possessions player) (registry/trigger-times registry difficulty))) (make-pattern/action '(list possessions) (lambda () (person/list-possessions player) (registry/trigger-times registry difficulty))) (make-pattern/action '(look) (lambda () (person/look-around player))) (make-pattern/action '(look around) (lambda () (person/look-around player))) (make-pattern/action '(say ...) (lambda (stuff) (person/say player stuff) (registry/trigger-times registry difficulty))))) (define respond-to-using (lambda (command p/a-list) (cond ((null? p/a-list) (display-message '("I don't understand."))) ((matches? (pattern (car p/a-list)) command) (apply (action (car p/a-list)) (substitutions-in-to-match (pattern (car p/a-list)) command))) (else (respond-to-using command (cdr p/a-list)))))) ;; The versions of matches? and substitutions-in-to-match ;; given below not only are after doing various chapter 7 ;; exercises, but moreover have an additional feature that a ;; predicate can be used as one of the components of a pattern, ;; in which case it means that at that position in the command, ;; a symbol is needed that is the name of an item in the player's ;; place that satisfies the predicate. (define matches? (lambda (pattern question) (cond ((null? pattern) (null? question)) ((not (pair? question)) #f) ((equal? (car pattern) '_) (matches? (cdr pattern) (cdr question))) ((list? (car pattern)) (if (member (car question) (car pattern)) (matches? (cdr pattern) (cdr question)) #f)) ((equal? (car pattern) '...) #t) ((equal? (car pattern) (car question)) (matches? (cdr pattern) (cdr question))) ((procedure? (car pattern)) (let ((object (object-with-name (car question)))) (if (and object ((car pattern) object)) (matches? (cdr pattern) (cdr question)) #f))) (else #f)))) (define substitutions-in-to-match (lambda (pattern question) (cond ((null? pattern) (if (null? question) '() (error "substitutions-in-to-match without a match"))) ((not (pair? question)) (error "substitutions-in-to-match without a match")) ((equal? (car pattern) '_) (cons (car question) (substitutions-in-to-match (cdr pattern) (cdr question)))) ((list? (car pattern)) (if (member (car question) (car pattern)) (cons (car question) (substitutions-in-to-match (cdr pattern) (cdr question))) (error "substitutions-in-to-match without a match"))) ((equal? (car pattern) '...) (list question)) ((equal? (car pattern) (car question)) (substitutions-in-to-match (cdr pattern) (cdr question))) ((procedure? (car pattern)) (let ((object (object-with-name (car question)))) (if (and object ((car pattern) object)) (cons object (substitutions-in-to-match (cdr pattern) (cdr question))) (error "substitutions-in-to-match without a match")))) (else (error "substitutions-in-to-match without a match"))))) (define object-with-name (lambda (name) (let ((objects (filter (lambda (obj) (equal? (named-object/name obj) name)) (place/contents (person/place player))))) (if (or (null? objects) (not (null? (cdr objects)))) #f (car objects)))))