;;; Geography Program: ;;; ------------------ ;;; INIT: Initializes the data base ;;; ----- (define INIT (lambda [] (begin (set *Road-Descriptors* (new-environment)) (set *Location-Index* (new-environment)) (set *Highway-Synonyms* (new-environment))))) ;;; DRIVER: Runs a read-process-print loop. ;;; ------- (define DRIVER (lambda [] (begin (print ps cr) (string-out ps " Geo> ") (let [[input (read-structure ps)]] (if (= input 'quit) 'ok (begin (string-out ps " Geo= ") (let [[answer (process-input input)]] (if (string answer) (string-out ps answer) (print-structure ps answer))) (driver))))))) ;;; PROCESS-INPUT: Processes an input structure, assumed to be ;;; -------------- written in the simple data language. (define PROCESS-INPUT (lambda [input] (dispatch (pproc input) [Road (if (bound (arg 1 input) *Road-Descriptors*) "Thanks, already known" (begin (rebind (arg 1 input) '[] *Road-Descriptors*) 'ok))] [Highway (if (bound (arg 2 input) *Highway-Synonyms*) "Thanks, already known" (begin (rebind (arg 2 input) (arg 1 input) *Highway-Synonyms*) 'ok))] [Intersection (let [[pn1 (canonical-position-name (arg 1 input))] [pn2 (canonical-position-name (arg 2 input))]] (begin (store-intersection-info pn1 pn2) (store-intersection-info pn2 pn1) 'ok))] [Location (begin (rebind (arg 1 input) (canonical-position-name (arg 2 input)) *Location-Index*) 'ok)] [Routes (map prettify (Routes-Descs (arg 1 input) (arg 2 input)))] [Route (prettify (shortest-route-desc (arg 1 input) (arg 2 input)))] [$T (error "Unrecognized input" input)]))) (define ROUTES-DESCS (lambda [pn-1 pn-2] (map (lambda [route-name] (cons (canonical-position-name pn-1) route-name)) (find-routes-descs (canonical-position-name pn-1) (canonical-position-name pn-2) [])))) (define FIND-ROUTES-DESCS (lambda [current-point destination used-names] (if (= (road-name destination) (road-name current-point)) [[destination]] (let [[inters (except (binding (road-name current-point) *Road-Descriptors*) current-point used-names)]] (mappend (lambda [intersection] (map (lambda [route] (cons (cons (first intersection) (rest current-point)) route)) (find-routes-descs (second intersection) destination (cons (road-name current-point) used-names)))) inters))))) (define EXCEPT (lambda [news this used-names] (cond [(null news) []] [(or (member (road-name (second (first news))) used-names) (and (same-road-name (second (first news)) this) (= (milepost-name (second (first news))) (milepost-name this)))) (except (rest news) this used-names)] [$T (cons (first news) (except (rest news) this used-names))]))) (define SHORTEST-ROUTE-DESC (lambda [pn-1 pn-2] (letseq [[routes-descs (routes-descs pn-1 pn-2)] [lengths (map route-length routes-descs)] [shortest (min . lengths)] [position (index shortest lengths)] [route-desc (nth position routes-descs)]] [shortest route-desc]))) (define ROUTE-LENGTH (lambda [route] (if (= (length route) 1) 0 (+ (distance (milepost-name (second route)) (if (same-road-name (first route) (second route)) (milepost-name (first route)) (position-of-road (first route) (binding (road-name (second route)) *Road-Descriptors*)))) (route-length (rest route)))))) (define DISTANCE (lambda [m-name-1 m-name-2] (abs (- \m-name-1 \m-name-2)))) (define POSITION-OF-ROAD (lambda [rd tuples] (cond [(null tuples) (error "No intersection?" tuples)] [(same-road-name rd (second (first tuples))) (first (first tuples))] [$T (position-of-road rd (rest tuples))]))) ;;; ROAD-NAMES Acceptable road names are either atoms or pairs ;;; ========== of the form (HIGHWAY