/* prolog tutorial 7_3.pl */ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Command idiom c: % {Please} place {block} X on {block} Y, W on Z, ... % I want X on Y, W on Z, ... % I want you to put ... % Can you {please} put X on Y, ... c(L) --> lead_in,arrange(L),end. end --> ['.'] | ['?']. lead_in --> please, place. lead_in --> [i], [want] | [i], [would], [like], you_to_put. lead_in --> ([can] | [could] | [would]), [you], please, place. you_to_put --> [] | [you], [to], place. %%% partially optional please --> [] | [please]. %%% optional word place --> [put] | [place]. %%% alternate words arrange([ON]) --> on(ON). arrange([ON|R]) --> on(ON), comma, arrange(R). comma --> [','] | ['and'] | [','],[and]. %%% alternate words on(on(X,Y)) --> block, [X], ([on] | [onto] | [on],[top],[of]), block, [Y]. on(on(X,table)) --> [X],([on] | [onto]), [the], [table]. block --> [] | [block]. %%% optional word :- [read_line]. place_blocks :- repeat, write('?? '), read_line(X), ( c(F,X,[]), assert_list(F), write('ok.'), nl | q(F,X,[]) ), answer(F), nl, fail. % Assert each item in the list. assert_list([]). assert_list([H|T]) :- assert_item(H), assert_list(T). % Add a new table spot. assert_table_spot([X,0]) :- assert(free_spot_on_table([X,0])). assert_table_spot([X,Y]) :- Y \= 0. % Move block A on the table. assert_item(on(A,table)) :- location(A,[X,Y]), not(Y is 0), free_spot_on_table(P), YN is Y + 1, not(location(_,[X,YN])), retract(free_spot_on_table(P)), retract(location(A,[X,Y])), assert(location(A,P)),!. % Move block A on block B. assert_item(on(A,B)) :- B \== table, location(A, [XA,YA]), YAN is YA + 1, not(location(_, [XA,YAN])), location(B, [XB,YB]), YBN is YB + 1, not(location(_, [XB,YBN])), retract(location(A, [XA,YA])), assert_table_spot([XA,YA]), % Possibly free up spot on table. assert(location(A, [XB,YBN])),!. % Handle errors. assert_item(on(A,table)) :- location(A,[_,Y]), Y is 0, write('Already on the table!'), nl, !, fail. assert_item(on(_,table)) :- not(free_spot_on_table(_)), write('No free spots on the table!'), nl, !, fail. assert_item(on(A,table)) :- location(A,[X,Y]), YN is Y + 1, location(_,[X,YN]), write('Cannot move from, something is on top!'), nl, !, fail. assert_item(on(A,_)) :- not(location(A, _)), write('Block to move does not exist!'), nl, !, fail. assert_item(on(_,B)) :- B \== table, not(location(B, _)), write('Block to place on does not exist!'), nl, !, fail. assert_item(on(A,B)) :- B \== table, location(A, [XA,YA]), YAN is YA + 1, location(_, [XA,YAN]), write('Cannot move from, something is on top!'), nl, !, fail. assert_item(on(_,B)) :- B \== table, location(B, [XB,YB]), YBN is YB + 1, location(_, [XB,YBN]), write('Cannot move to, something is on top!'), nl, !, fail. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Question idiom q: % Which block is on top of X? % What is on top of? % :- op(500, xfx, 'is_on_top_of'). % the question q q(_ is_on_top_of A) --> [which],[block],[is],[on],[top],[of],[A],end. q(_ is_on_top_of A) --> [what],[is],[on],[top],[of],[A],end. % How to answer q B is_on_top_of A :- location(A,[X,Y]), Y1 is Y+1, location(B,[X,Y1]), !. 'Nothing' is_on_top_of _ . answer(X is_on_top_of A) :- call(X is_on_top_of A), say([X,is,on,top,of,A]). say([X|R]) :- write(X), write(' '), say(R). say([]). % % positioning information % % [0,3] [1,3] [2,3] % [0,2] [1,2] [2,2] % [0,1] [1,1] [2,1] % [0,0] [1,0] [2,0] % -=================- table % % initially % % c % b % a d % -=================- :- dynamic free_spot_on_table/1. :- dynamic location/2. :- dynamic on/2. free_spot_on_table([2,0]). location(c,[0,2]). location(b,[0,1]). location(a,[0,0]). location(d,[1,0]). on(A,table) :- location(A,[_,0]). on(A,B) :- B \== table, location(A,[X,YA]), location(B,[X,YB]), YB is YA - 1.