%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%  read_line
%%%  Similar to read_sent in Pereira and Shieber, Prolog and
%%%        Natural Language Analysis, CSLI, 1987.
%%%
%%%  Examples:
%%%           % read_line(L).
%%%           The sky was blue, after the rain.
%%%           L = [the,sky,was,blue,',',after,the,rain,'.']
%%%           % read_line(L).
%%%           Which way to the beach?
%%%           L = [which,way,to,the, beach,'?']
%%%

read_line(Words) :- get0(C),
                    read_rest(C,Words).

/* A period or question mark ends the input. */
read_rest(46,['.']) :- !.
read_rest(63,['?']) :- !.

/* Spaces and newlines between words are ignored. */
read_rest(C,Words) :- ( C=32 ; C=10 ) , !,
                     get0(C1),
                     read_rest(C1,Words).

/* Commas between words are absorbed. */
read_rest(44,[','|Words]) :- !,
                             get0(C1),
                             read_rest(C1,Words).

/* Otherwise get all of the next word. */
read_rest(C,[Word|Words]) :- lower_case(C,LC),
                             read_word(LC,Chars,Next),
                             name(Word,Chars),
                             read_rest(Next,Words).

/* Space, comma, newline, period or question mark separate words. */
read_word(C,[],C) :- ( C=32 ; C=44 ; C=10 ;
                         C=46 ; C=63 ) , !.

/* Otherwise, get characters, convert alpha to lower case. */
read_word(C,[LC|Chars],Last) :- lower_case(C,LC),
                                get0(Next),
                                read_word(Next,Chars,Last).

/* Convert to lower case if necessary. */
lower_case(C,C) :- ( C <  65 ; C > 90 ) , !.
lower_case(C,LC) :- LC is C + 32.

/* for reference ... 
newline(10).
comma(44).
space(32).
period(46).
question_mark(63).
*/

% initial state
tilebox([[1,2,3],[4,5,6],[7,8,' ']]).

% Call the parser.
move_tiles :- 
    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).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Command idiom c:
%  {Please} move <push> {tile} X <up/down/left/right>
%  I want <would like> you to move <push> {tile} X {up/down/left/right}
%  Can <could> <would> you {please} move <push> X {up/down/left/right}, ...

c(L) --> lead_in,arrange(L),end.

end --> ['.'] | ['?'].

lead_in --> please, move.
lead_in --> [i], [want] | [i], [would], [like], you_to_put.
lead_in --> ([can] | [could] | [would]), [you], please, move.

you_to_move --> [] | [you], [to], move.   %%% partially optional

please --> [] | [please].    %%% optional word

move --> [move] | [push].   %%% alternate words

arrange([ON]) --> slide(ON).
arrange([ON|R]) --> slide(ON), comma, arrange(R).

comma --> [','] | ['and'] | [','],[and].   %%% alternate words

slide(slide(X,Direction)) --> tile, [X], [Direction].

tile --> [] | [tile].   %%% optional word

% Move tile A.
assert_item(slide(X,Direction)) :- 
write('I am not Implemented: '), 
write(slide(X,Direction)),
fail .

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Question idiom q:
%   Which tile is at X,Y ?
%

% the question q
q(check(X,Y)) --> [which],[tile],[is],[at],[X],[,],[Y],end.
   
% How to answer q
answer(check(X,Y)) :- tilebox(L), grabA(Res,X,Y,L), write('Tile '), write(Res), write('.'), nl.






%%%%%%%%%%%%%%
% Utilities


%Pretty Prints a list of lists to the console

prettyprint([]).
prettyprint([H|L]) :- printhelp(H), prettyprint(L).
printhelp([]) :- nl.
printhelp([H|T]) :-
	write(H),write(' '),
	printhelp(T).


% Replace and replacegrid have as their first argument a copy of their fourth argument, with 
% instances of the second argument replaced with instances of the first argument.  Replace
% Takes in lists and replacegrid takes in lists of lists.
% replacegrid(Res, 2, 7, [[1,2,3,4]]) would set Res to [[1,7,3,4]].
% Take note that the tilebox assertion is a list of lists.

replace([],_,_,[]).
replace(Res,In,Out,[H|L]) :- In = H, replace(FRes,In,Out,L), Res=[Out|FRes] .
replace(Res,In,Out,[H|L]) :- not(In = H), replace(FRes,In,Out,L), Res=[H|FRes] .
replacegrid([],_,_,[]).
replacegrid(Res,In,Out,[H|T]) :- replace(HRes,In,Out,H), replacegrid(TRes,In,Out,T), Res=[HRes|TRes].

% grabA find an element at coordinate Xpos,Ypos within a list of lists.  grabB is finds an 
% element at coordinate Xpos within a list (i.e. the Xpos element).
grabA(Res,Xpos,1,[H|_]) :- !,grabB(Res,Xpos,H).
grabA(Res, Xpos,Ypos,[_|T]) :- Yposnew is Ypos - 1, grabA(Res, Xpos, Yposnew, T) .
grabB(Res, 1 ,[H|_]) :- !,Res = H.
grabB(Res, Xpos ,[_|T]) :- Xposnew is Xpos - 1, grabB(Res, Xposnew, T).

% This function is not implemented.  If it was, Res would be equal to L, excepting that all
% instances of A would be replaced by B and visa versa.
switch(Res,A,B,L) :- write('Not implemented'), nl, fail.

% Move utility function
% Move from C,D into A,B, so long as A,B is empty.
% Makes the valid assumption that tile names are unique.
move(Res,L,A,B,C,D) :- 
	grabA(' ',A,B,L),
	grabA(E,C,D,L),
	switch(Res,' ',E,L).