



THE AUTOMATED TOURIST GUIDE - from "Computers & Thought" THE AUTOMATED TOURIST GUIDE - from "Computers & Thought"
/*
THE AUTOMATED TOURIST GUIDE - from "Computers & Thought"
http://www.informatics.sussex.ac.uk/local/books/computers-and-thought/index.html
This appendix gives a listing in POP-11 of a complete Tourist Guide based on
one programmed by a student. It makes use of the `prodsys' and `semnet'
POP-11 libraries. The program can be called by the command
converse();
*/
lib prodsys;
lib semnet;
/*****************************************************
Rule-Based System for Advising on Entertainment
- see Chapter 7
******************************************************/
;;; following rules deal with entertainment in London
[] -> rulebase;
false -> chatty;
false -> repeating;
rule find_type [entertainment medium unknown];
vars enttype;
[what type of entertainment would you like: cinema or theatre?] ==>
readline() -> enttype;
remove([entertainment medium unknown]);
add([entertainment medium ^^enttype]);
endrule;
rule find_style [entertainment style unknown];
vars styletype;
[would you like western, drama or horror]==>
readline() -> styletype;
remove([entertainment style unknown]);
add([entertainment style ^^styletype]);
endrule;
rule cinema_western [entertainment style western]
[entertainment medium cinema];
[soldier blue is on this week at the eros.] ==>
endrule;
rule cinema_horror [entertainment style horror]
[entertainment medium cinema];
[[the amazing doctor vulture is on this week at the classic and abc1.]
[i was an american vulture in london is on this week at abc2.]] ==>
endrule;
rule cinema_drama [entertainment style drama]
[entertainment medium cinema];
[[twenty tiny ants is on this week at the carlton.]
[dog on a shed roof is on until thursday at the rialto.]
[sharp shooter the prequel is on for two weeks at dominion.]]==>
endrule;
rule theatre_western [entertainment style western]
[entertainment medium theatre];
[home on the range is on at the criterion.]==>
endrule;
rule theatre_horror [entertainment style horror]
[entertainment medium theatre];
[[cant slay wont slay is on at the adelphi.]
[sweaters is on at the piccadilly.]]==>
endrule;
rule theatre_drama [entertainment style drama]
[entertainment medium theatre];
[[world go away is on at the phoenix.]
[slaving over a hot keyboard is on at the lyric.]]==>
endrule;
/*****************************************************
Syntactic and Semantic Analysis of Noun-Phrases
- see Chapter 5
******************************************************/
define DET(word) -> found;
member(word, [a the]) -> found;
enddefine;
define PREP(word) -> found;
if member(word, [near by]) then
"near" -> found;
elseif member(word, [in containing]) then
word -> found;
else
false -> found;
endif;
enddefine;
define NOUN(list) -> found;
if member(list, [[avenue] [street] [road]]) then
[road] -> found;
elseif member(list, [[gallery] [square] [museum]
[theatre] [cinema] [monument]
[lake] [park]] ) then
list -> found;
else
false -> found;
endif
enddefine;
define PROPN(list) -> found;
member(list,
[[the abc1] [the abc2] [the carlton]
[the odeon] [the rialto] [the dominion]
[the classic] [the eros] [the haymarket]
[the criterion] [the phoenix] [the adelphi]
[the savoy] [the piccadilly] [the lyric]
[the royal albert hall]
[the royal opara house]
[the british museum]
[the natural history museum]
[the victoria and albert museum]
[the science museum] [the tower of london]
[hms belfast] [the houses of parliament]
[st pauls cathedral] [westminster abbey]
[london zoo] [the serpentine]
[st katherines dock] [the national gallery]
[nelsons column] [hyde park] [the serpentine]
[the tate gallery] [shaftesbury avenue]
[leicester square] [haymarket]
[piccadilly circus] [coventry street]
[tottenham court road] [trafalgar square]
[jermyn street] [the strand] [denman street]
[kensington gore] [floral street]
[great russel street] [cromwell road]
[exhibition road] [millbank] [tower hill]
[st catherines way]
] ) -> found;
enddefine;
define NP(list) -> meaning;
vars pn, d, n, p, np, sym1, sym2;
if list matches [??pn:PROPN] then
pn -> meaning
elseif list matches [?d:DET ??n:NOUN] then
gensym("v") -> sym1;
[ [ ? ^sym1 isa ^n] ] -> meaning
elseif list matches [?d:DET ??n:NOUN ?p:PREP ??np:NP]
then
gensym("v") -> sym1;
if np matches [[= ?sym2 isa =] ==] then
;;; meaning of noun phrase is
;;; a list of patterns
[ [? ^sym1 isa ^n] [? ^sym1 ^p ? ^sym2] ^^np]
-> meaning
else
;;; meaning of noun phrase is proper name
[ [? ^sym1 isa ^n] [? ^sym1 ^p ^np] ]
-> meaning
endif;
else
;;; unknown noun phrase form
false -> meaning
endif;
enddefine;
define referent(meaning) -> thing;
;;;
;;; find the thing referred by meaning structure
;;;
vars sym, vals, x;
if meaning matches [[= ?sym isa =] ==] then
;;; meaning is a list of patterns
which(sym, meaning) -> vals;
if vals matches [?x ==] then
;;; at least one thing referred to
x -> thing
else
;;; nothing referred to
false -> thing
endif;
else
;;; meaning is a proper name
meaning -> thing;
endif
enddefine;
/*********************************************
Finding a Route on the Underground
- see Chapter 4
**********************************************/
vars verychatty;
false -> verychatty;
/* first set travel and change times */
vars travtime, changetime;
2 -> travtime;
3 -> changetime;
define addonefuture(newplace,newtime,comefrom);
;;; This records in the database a single pending
;;; arrival at a place (where place means
;;; a line-station combination as in the database),
;;; unless there has already been an
;;; arrival at that place.
;;; Also protects against inserting the same future event
;;; twice, as could happen when looking at
;;; line changes due to the fact that the
;;; information that a station is on a given line can
;;; appear twice in the database.
;;; Can also say what it's doing.
vars futureevent;
[will arrive ^newplace at ^newtime mins from ^comefrom]
-> futureevent;
if not(present([arrived ^newplace at = mins from =]))
and not(present(futureevent))
then
add(futureevent);
if verychatty then
[ . . will arrive ^newplace at ^newtime mins] ==>
endif;
endif;
enddefine;
define addfuture(event);
;;; Given an event, adds the pending events that
;;; follow it into the database
vars place, newplace, time, station, line, newln;
;;; Get breakdown of event
;;; Note that the matcher arrow --> could be
;;; replaced by MATCHES except that it
;;; does not return a TRUE/FALSE value.
;;; We know that the event passed to
;;; ADDFUTURE will have the right format.
event --> [arrived ?place at ?time mins from =];
place --> [?line ??station];
;;; First get all the connections on the same line
foreach [^place connects ?newplace] do
addonefuture(newplace,time+travtime,place);
endforeach;
;;; This repeats the last bit for patterns
;;; the other way round
foreach [?newplace connects ^place] do
addonefuture(newplace,time+travtime,place);
endforeach;
;;; Then all the changes to other lines
foreach [[?newln ^^station] connects =] do
addonefuture([^newln ^^station], time+changetime,place);
endforeach;
;;; And again for patterns the other way round
foreach [= connects [?newln ^^station]] do
addonefuture([^newln ^^station], time+changetime,place);
endforeach;
enddefine;
define next();
;;; This looks at all the future events in the database
;;; and finds the one that will happen next - that is,
;;; the one with the smallest value of time, and returns
;;; a list giving the corresponding actual event.
vars leasttime, place, time, lastplace, event;
;;; leasttime has to start bigger than any likely time
100000 -> leasttime;
foreach [will arrive ?place at ?time mins
from ?lastplace] do
if time < leasttime then
[arrived ^place at ^time mins from ^lastplace]
-> event;
time -> leasttime;
endif;
endforeach;
return(event);
enddefine;
define insertnext(event);
;;; Takes an event returned by NEXT and inserts it
;;; into the database, then removes all pending events
;;; which would cause later arrivals at the same station.
;;; Can also print out the event.
vars place;
;;; addition
add(event);
;;; removal
event --> [arrived ?place at = mins from =];
foreach ([will arrive ^place at = mins from =]) do
remove(it);
endforeach;
if chatty or verychatty then
event ==>
endif;
enddefine;
define start(station);
;;; This sets up the database ready to start by inserting
;;; pending arrivals at the starting station
vars line;
foreach [[?line ^^station] connects =] do
addonefuture([^line ^^station],0,[start]);
endforeach;
;;; This is the same as the first half but
;;; for the other sort of patterns
foreach [= connects [?line ^^station]] do
addonefuture([^line ^^station],0,[start]);
endforeach;
enddefine;
define search(startstat,deststat);
;;; Inserts information into the database till the "tree"
;;; as far as the destination station has grown
vars nextevent, destline;
start(startstat);
repeat
next() -> nextevent;
insertnext(nextevent);
quitif (nextevent matches
[arrived [?destline ^^deststat]
at = mins from =]);
addfuture(nextevent);
endrepeat;
add([finished at [^destline ^^deststat]]);
enddefine;
define traceroute();
;;; Assuming the tree has been grown in the database,
;;; and event is the arrival at the destination station,
;;; return a list of the stations through which the
;;; quickest route passes
vars place, lastplace, time, ok, routelist;
;;; ok will always be true
present([finished at ?place]) -> ok;
present([arrived ^place at ?time mins from ?lastplace])
-> ok;
[[^place at ^time mins]] -> routelist;
until lastplace = [start] do
lastplace -> place;
;;; the next line is there for its side effects.
;;; ok will always be true
present([arrived ^place at ?time mins from
?lastplace]) -> ok;
[[^place at ^time mins] ^^routelist] -> routelist;
enduntil;
return(routelist);
enddefine;
define checkstat(station);
;;; simply checks that a station is present
;;; in the database
return(present([[= ^^station] connects =])
or present([= connects [= ^^station]]));
enddefine;
define tidyup();
;;; this removes any previous route-finding information
;;;from the database, in order to clear the way
;;; for a new route
foreach [will arrive = at = mins from =] do
remove(it);
endforeach;
foreach [arrived = at = mins from =] do
remove(it);
endforeach;
foreach [finished at =] do
remove(it);
endforeach;
enddefine;
define route(startstat,deststat);
;;; this is the overall calling program for route finding
;;; this sets up the database for the other routines.
;;; checking
if not(checkstat(startstat)) then
[start station ^^startstat not found] ==>
return(false);
endif;
if not(checkstat(deststat)) then
[destination station ^^deststat not found] ==>
return(false);
endif;
;;; tidy the database in preparation
tidyup();
;;; do the search
search(startstat,deststat);
;;; return the result. Note that the database is left
;;; with all the search stuff still in it
return(traceroute());
enddefine;
define reply(list) -> response;
;;;
;;; Convert a route list into
;;; an English description of the form:
;;;
;;; travelling by underground, take the ... line to ...
;;; then change and take the ... line to ...
;;; then change and take the ... line to ...
;;; ...
vars line, station, line1, response;
list --> [[[?line ??station] ==] ??list];
[travelling by underground, take the
^line line to] -> response;
while list matches [[[?line1 ??station] ==] ??list] do
if line1 /= line then
[^^response ^^station then change and
take the ^line1 line to] -> response;
line1 -> line;
endif;
endwhile;
[^^response ^^station] -> response;
enddefine;
/***************************************************
Top-Level Procedures of the
Automated Tourist Guide
****************************************************/
define setup();
;;;
;;; Setup the database of facts about London
;;;
[
;;; cinemas
[[the abc1] in [shaftesbury avenue]]
[[the abc1] underground [leicester square]]
[[the abc1] isa [cinema]]
[[the abc2] in [shaftesbury avenue]]
[[the abc2] underground [leicester square]]
[[the abc2] isa [cinema]]
[[the carlton] in [haymarket]]
[[the carlton] underground [piccadilly circus]]
[[the carlton] isa [cinema]]
[[the odeon] in [haymarket]]
[[the odeon] underground [piccadilly circus]]
[[the odeon] isa [cinema]]
[[the rialto] in [coventry street]]
[[the rialto] underground [piccadilly circus]]
[[the rialto] isa [cinema]]
[[the dominion] in [tottenham court road]]
[[the dominion] underground [piccadilly circus]]
[[the dominion] isa [cinema]]
[[the classic] in [piccadilly circus]]
[[the classic] underground [piccadilly circus]]
[[the classic] isa [cinema]]
[[the eros] in [piccadilly circus ]]
[[the eros] underground [piccadilly circus]]
[[the eros] isa [cinema]]
;;; theatres
[[the haymarket] in [haymarket]]
[[the haymarket] underground [piccadilly circus]]
[[the haymarket] isa [theatre]]
[[the criterion] in [jermyn street]]
[[the criterion] underground [piccadilly circus]]
[[the criterion] isa [theatre]]
[[the phoenix] in [charing cross road]]
[[the phoenix] underground [tottenham court road]]
[[the phoenix] isa [theatre]]
[[the adelphi] in [the strand]]
[[the adelphi] underground [charing cross]]
[[the adelphi] isa [theatre]]
[[the savoy] in [the strand]]
[[the savoy] underground [charing cross]]
[[the savoy] isa [theatre]]
[[the piccadilly] in [denman street]]
[[the piccadilly] underground [piccadilly circus]]
[[the picadilly] isa [theatre]]
[[the lyric] in [shaftesbury avenue]]
[[the lyric] underground [piccadilly circus]]
[[the lyric] isa [theatre]]
[[the royal albert hall] in [kensington gore]]
[[the royal albert hall] underground
[south kensington]]
[[the royal albert hall] isa [theatre]]
[[the royal opera house] in [floral street]]
[[the royal opera house] underground [covent garden]]
[[the royal opera house] isa [theatre]]
;;; museums
[[the british museum] in [great russel street]]
[[the british museum] underground
[tottenham court road]]
[[the british museum] isa [museum]]
[[the natural history museum] in [cromwell road]]
[[the natural history museum] underground
[south kensington]]
[[the natural history museum] isa [museum]]
[[the victoria and albert museum] in [cromwell road]]
[[the victoria and albert museum] underground
[south kensington]]
[[the victoria and albert museum] isa [museum]]
[[the science museum] in [exhibition road]]
[[the science museum] underground [south kensington]]
[[the science museum] isa [museum]]
;;; galleries
[[the national gallery] in [trafalgar square]]
[[the national gallery] underground [charing cross]]
[[the national gallery] isa [gallery]]
[[the tate gallery] in [millbank]]
[[the tate gallery] underground [pimlico]]
[[the tate gallery] isa [gallery]]
;;; places of interest
[[the tower of london] near [tower hill]]
[[the tower of london] underground [tower hill]]
[[the tower of london] isa [place of interest]]
[[hms belfast] near [the tower of london]]
[[hms belfast] underground [london bridge]]
[[hms belfast] isa [place of interest]]
[[the houses of parliament] near [parliament square]]
[[the houses of parliament] underground [westminster]]
[[the houses of parliament] isa [place of interest]]
[[st pauls cathedral] in [newgate street]]
[[st pauls cathedral] underground [st pauls]]
[[the houses of parliament] isa [place of interest]]
[[westminster abbey] in [millbank]]
[[westminster abbey] underground [westminster]]
[[westminster abbey] isa [place of interest]]
[[st katharines dock] near [st katharines way]]
[[st katharines dock] underground [tower hill]]
[[st katharines dock] isa [place of interest]]
[[nelsons column] in [trafalgar square]]
[[nelsons column] underground [charing cross]]
[[nelsons column] isa [place of interest]]
[[nelsons column] isa [monument]]
[[london zoo] in [regents park]]
[[london zoo] underground [camden town]]
[[london zoo] isa [place of interest]]
[[the serpentine] in [hyde park]]
[[the serpentine] underground [hyde park corner]]
[[the serpentine] isa [lake]]
;;; roads
[[shaftesbury avenue] isa [road]]
[[haymarket] isa [road]]
[[coventry street] isa [road]]
[[tottenham court road] isa [road]]
[[jermyn street] isa [road]]
[[the strand] isa [road]]
[[denman street] isa [road]]
[[kensington gore] isa [road]]
[[floral street] isa [road]]
[[great russell street] isa [road]]
[[cromwell road] isa [road]]
[[exhibition road] isa [road]]
[[millbank] isa [road]]
[[tower hill] isa [road]]
[[st catherines way] isa [road]]
;;; squares
[[leicester square] isa [square]]
[[piccadilly circus] isa [square]]
[[parliament square] isa [square]]
[[trafalgar square] isa [square]]
;;; parks
[[hyde park] isa [park]]
[[regents park] isa [park]]
;;; underground topology for route finder
[[JUBILEE charing cross] connects [JUBILEE green park]]
[[JUBILEE green park] connects [JUBILEE bond street]]
[[JUBILEE bond street] connects [JUBILEE baker street]]
[[BAKERLOO embankment] connects [BAKERLOO charing cross]]
[[BAKERLOO charing cross] connects
[BAKERLOO piccadilly circus]]
[[BAKERLOO piccadilly circus] connects
[BAKERLOO oxford circus]]
[[CIRCLE embankment] connects [CIRCLE westminster]]
[[CIRCLE westminster] connects [CIRCLE st jamess park]]
[[CIRCLE st jamess park] connects [CIRCLE victoria]]
[[CIRCLE victoria] connects [CIRCLE sloane square]]
[[CIRCLE sloane square] connects
[CIRCLE south kensington]]
[[PICCADILLY south kensington] connects
[PICCADILLY knightsbridge]]
[[PICCADILLY knightsbridge] connects
[PICCADILLY hyde park corner]]
[[PICCADILLY hyde park corner] connects
[PICCADILLY green park]]
[[PICCADILLY green park] connects
[PICCADILLY piccadilly circus]]
[[CENTRAL lancaster gate] connects [CENTRAL marble arch]]
[[CENTRAL marble arch] connects [CENTRAL bond street]]
[[CENTRAL bond street] connects [CENTRAL oxford circus]]
[[CENTRAL oxford circus] connects
[CENTRAL tottenham court road]]
[[VICTORIA warren street] connects
[VICTORIA oxford circus]]
[[VICTORIA oxford circus] connects [VICTORIA green park]]
[[VICTORIA green park] connects [VICTORIA victoria]]
[[VICTORIA victoria] connects [VICTORIA pimlico]]
[[VICTORIA pimlico] connects [VICTORIA vauxhall]]
[[NORTHERN charing cross] connects
[NORTHERN leicester square]]
[[NORTHERN leicester square] connects
[NORTHERN convent garden]]
;;; fare and zones for fare finder
[[zone1 station] fare [40 pence]]
[[zone2 station] fare [60 pence]]
[[green park] isa [zone1 station]]
[[picadilly circus] isa [zone1 station]]
[[shepherds bush] isa [zone2 station]]
[[goodge street] isa [zone2 station]]
[[brixton] isa [zone2 station]]
] -> database;
enddefine;
define introduction();
;;;
;;; output welcome and instructions to user
;;;
[Hello, this is the automated London tourist guide]==>
[I can offer information on the following]==>
[cinema]==>
[theatre]==>
[museums]==>
[galleries]==>
[places of interest]==>
[routes and fares on the underground]==>
[Please ask about any of the above
and I will try to help you]==>
[Type in your question using lowercase letters only]==>
[and then press RETURN]==>
[If you want to exit please type "bye"
and press RETURN]==>
enddefine;
define answer(query) -> response;
;;;
;;; produce a response to query
;;;
vars list, museums, response, x, y, place, routelist;
if query matches [== places of interest ==] then
;;; this is a query about places of interest
[] -> list;
foreach [?place isa [place of interest]] do
[^^list , ^place] -> list;
endforeach;
;;; strip off leading comma from reply
list --> [, ??list];
[I know about the following places of interest:
^^list] -> response;
elseif query matches [== where is ??np:NP] or
query matches [== where ??np:NP is] then
;;; a query about where somewhere is
;;; find the place referred to by noun-phrase
referent(np) -> place;
if place and present([^place in ?y]) then
[^^place is in ^^y] -> response;
elseif place and present([^place near ?y]) then
[^^place is near ^^y] -> response;
elseif place and present([^place underground ?y])
then
[^^place is near ^^y underground station]
-> response;
else
[I do not know where that place is]
-> response;
endif;
elseif query matches [== get to ??np:NP] then
;;; route finding query
;;; find place referred to by noun-phrase
referent(np) -> place;
if place and present([^place underground ?y]) then
route([victoria], y) -> routelist;
if not(routelist) then
[route not found] -> response
else
reply(routelist) -> response
endif
else
[I do not know where that place is]
-> response;
endif
elseif query matches [== fare to ??x] then
;;; query about fare to a given underground station
if spresent([^x fare ?y]) then
[The fare to ^^x is ^^y] -> response
else
[I do not know about the underground station ^^x]
-> response
endif
elseif query matches [== entertainment ==] or
query matches [== cinema==] or
query matches [== theatre==] or
query matches [== theatres ==] or
query matches [== cinemas ==] then
;;; answer query about entertainment in London
;;; using LIB PRODSYS
;;; add initial entertainment facts to database
add([entertainment medium unknown]);
add([entertainment style unknown]);
;;; run production system
run();
;;; remove database entries created by
;;; production system
flush([entertainment ==]);
[I hope you enjoy the show] -> response;
elseif query matches [] then
;;; blank line input
[please type in your question and press RETURN]
-> response
elseif query matches [bye] then
;;; produce response to terminate session
[bye] -> response
else
;;; cannot handle this query
[Sorry I do not understand. Try rewording
your question] -> response
endif;
enddefine;
define converse();
;;;
;;; main calling procedure
;;;
vars query, response;
;;; setup the database of facts about London
setup();
;;; output welcome and instructions to tourist user
introduction();
;;; read and answer queries until done
repeat
;;; read in query from keyboard
readline() -> query;
;;; produce an answer to query
answer(query) -> response;
;;; output answer to user
response ==>
;;; quit if answer indicates end of session
quitif(response = [bye]);
endrepeat;
enddefine;
