;; The first three lines of this file were inserted by DrRacket. They record metadata ;; about the language level of this file in a form that our tools can easily process. #reader(lib "htdp-advanced-reader.ss" "lang")((modname adventure) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #t #t none #f ()))) ; A place is ; (make-place string list-of-link) (define-struct place (name links)) ; A link is ; (make-link string place) (define-struct link (dir dest)) (define home (shared ([home (make-place "Home" (list (make-link "west" school) (make-link "south" zoo) (make-link "in" garage)))] [garage (make-place "Garage" (list (make-link "out" home) (make-link "drive" zoo)))] [school (make-place "School" (list (make-link "east" home)))] [zoo (make-place "Zoo" (list (make-link "north" home) (make-link "drive" garage)))]) home)) (define school (link-dest (first (place-links home)))) (define zoo (link-dest (second (place-links home)))) (define current-place home) ;; go! : string -> string ;; To move in the direction `dir', if possible. ;; Returns a description of the new place, if any, ;; or a string saying that you can't go that direction. ;; Effect: changes current-place (define (go! dir) (local [(define next-place (find-next-place current-place dir))] (cond [(place? next-place) (begin (set! current-place next-place) (string-append "You are at " (place-name next-place)))] [else "You can't go that direction"]))) ;; find-next-place : place string -> place-or-false (define (find-next-place here dir) (find-step (place-links here) dir)) ;; find-step : list-of-link string -> place-or-false (define (find-step links dir) (cond [(empty? links) false] [else (if (is-dir? (first links) dir) (link-dest (first links)) (find-step (rest links) dir))])) ;; is-dir? : link str -> boolean (define (is-dir? link dir) (string=? (link-dir link) dir)) (check-expect (find-step empty "east") false) (check-expect (find-step (place-links home) "east") false) (check-expect (find-step (place-links home) "west") school) (check-expect (find-next-place home "east") false) (check-expect (find-next-place home "west") school) (check-expect (begin (set! current-place home) (local [(define r (go! "east"))] (list r current-place))) (list "You can't go that direction" home)) (check-expect (begin (set! current-place home) (local [(define r (go! "west")) (define new-place-name (place-name current-place))] (begin (set! current-place home) (list r new-place-name)))) (list "You are at School" "School")) ;; can-reach? : string place list-of-place -> boolean ;; Determines whether you can reach a place named dest ;; from here, not using ignoring (define (can-reach? dest here ignoring) (if (member here ignoring) false (or (string=? dest (place-name here)) (can-reach-via-links? dest (place-links here) (cons here ignoring))))) ;; can-reach-via-links? : string list-of-link list-of-place -> boolean (define (can-reach-via-links? dest links ignoring) (cond [(empty? links) false] [else (or (can-reach? dest (link-dest (first links)) ignoring) (can-reach-via-links? dest (rest links) ignoring))])) (check-expect (can-reach-via-links? "School" empty empty) false) (check-expect (can-reach-via-links? "School" (place-links home) empty) true) (check-expect (can-reach-via-links? "School" (place-links zoo) empty) true) (check-expect (can-reach? "School" home empty) true) (check-expect (can-reach? "School" (make-place "Downtown" empty) empty) false) (check-expect (can-reach? "Zoo" school empty) true) (check-expect (can-reach? "Home" home empty) true)