I'm stuck with some grammar exercise in Prolog. This is my first time with grammar (in any language). I need to create a parser that will be counting robot's destination coordinates as well as the direction (makred as one of: n,s,w,e) it is currently pointed to.
Possible moves are: [go,10]
(or any number), [turn, left]
, [turn, right]
.
It was easy (I think..) to write parser that recognizes the correct sentence, like:[go,10,turn,right,go,10]
:
robot_p-->pol.
pol-->[go],num.
pol-->[go],num,pol.
pol-->[turn],[left].
pol-->[turn],[left],pol.
pol-->[turn],[right].
pol-->[turn],[right],pol.
num-->[D],{number(D)}.
robot(L):-robot_p(L,[]).
Yet now, I have no idea, how could I accumulate every single step, so for the sentence I've given as an example, the result would be [10,10,e]
. I think I should write something like:
robot_p(result)-->pol(result).
But if so, how would it look then? I could change num
to:
num(D)-->[D],{number(D)}.
Next, this would start:
pol([X,Y,N])-->[go],num(D),{N==n;//here I don't know what next}.
Yet, I'm not sure if it's good approach and if so, what to do now.
EDIT:
I've forgotten to say, that I need to pass starting coordinates.
So for [0,0,n]
and moves [go,10,turn,right,go,10]
the result is [10,10,e]
.
EDIT2:
Big thanks to @BretC for help. I've followed your tips and created the version that was satisfying by me. Maybe it will help someone:)
pol([X])-->[go],num(X).
pol([X| T])-->[go],num(X),pol(T).
pol([left])-->[turn],[left].
pol([left | T])-->[turn],[left],pol(T).
pol([right])-->[turn],[right].
pol([right | T])-->[turn],[right],pol(T).
commands(L,V):-pol(V,L,[]).
move([X,Y,D],V,[X1,Y,D]):-D==n,X1 is X+V.
move([X,Y,D],V,[X1,Y,D]):-D==s,X1 is X-V.
move([X,Y,D],V,[X,Y1,D]):-D==w,Y1 is Y-V.
move([X,Y,D],V,[X,Y1,D]):-D==e,Y1 is Y+V.
rotate(D,P,D1):-P==left,D==n,D1=w.
rotate(D,P,D1):-P==left,D==s,D1=e.
rotate(D,P,D1):-P==left,D==w,D1=s.
rotate(D,P,D1):-P==left,D==e,D1=n.
rotate(D,P,D1):-P==right,D==n,D1=e.
rotate(D,P,D1):-P==right,D==s,D1=w.
rotate(D,P,D1):-P==right,D==w,D1=n.
rotate(D,P,D1):-P==right,D==e,D1=s.
robot_H(D,[],D).
robot_H([X,Y,D],[H|T],K):-number(H),move([X,Y,D],H,ND),robot_H(ND,T,K).
robot_H([X,Y,D],[H|T],K):- \+number(H),rotate(D,H,D1),robot_H([X,Y,D1],T,K).
robot(S,P,K):-commands(P,P1),robot_H(S,P1,K).
num(X)-->[X],{number(X)}.
So, for instance:
?- robot([0,0,n],[go, 10, turn, left,turn,left, go, 20],K).
K = [-10, 0, s]
Not sure if this helps, but I would use the DGC to build a list of clauses representing the natural language and then process those clauses.
For example, if you add the following arguments to your grammar...
pol([move(X)])-->[go],num(X).
pol([move(X) | T])-->[go],num(X),pol(T).
pol([turn(left)])-->[turn],[left].
pol([turn(left) | T])-->[turn],[left],pol(T).
pol([turn(right)])-->[turn],[right].
pol([turn(right) | T])-->[turn],[right],pol(T).
num(D)-->[D],{number(D)}.
...now you can get a list of 'commands', for example...
4 ?- pol(X, [go,10,turn,left,go,10], []).
X = [move(10), turn(left), move(10)] .
So that's the parsing bit, now you need to write clauses to process the simulation, for example...
% Parses grammar and processes commands
robot(SENTANCE, XOut, YOut) :-
% Parse the sentance
pol(COMMANDS, SENTANCE, []),
% Process the commands
process(COMMANDS, north, 0, 0, XOut, YOut).
% process(COMMAND_LIST, HEADING, XSTART, YSTART, XOUT, YOUT)
% Case 1: No commands to process, return current position
process([], _, X, Y, X, Y).
% Case 2: Process a single command then process the rest of the commands
process([COMMAND | T], Heading, XIn, YIn, XOut, YOut) :-
do_command(COMMAND, Heading, XIn, YIn, HeadingTmp, XTmp, YTmp),
process(T, HeadingTmp, XTmp, YTmp, XOut, YOut).
% do_command(COMMAND, HEADING_START, XSTART, YSTART, HEADING_OUT, XOUT, YOUT).
% Move in current direction command
do_command(move(N), Heading, X, Y, Heading, XOut, YOut) :-
x_delta(Heading, N, XDelta),
y_delta(Heading, N, YDelta),
XOut is X + XDelta,
YOut is Y + YDelta.
% Turn command
do_command(turn(Dir), HeadingIn, X, Y, HeadingOut, X, Y) :-
turn(HeadingIn, Dir, HeadingOut).
% Utility clauses to help with deltas + turns
x_delta(north, _, 0).
x_delta(south, _, 0).
x_delta(east, X, X).
x_delta(west, X, Y) :- Y is -X.
y_delta(north, X, X).
y_delta(south, X, Y) :- Y is -X.
y_delta(east, _, 0).
y_delta(west, _, 0).
turn(north, right, east).
turn(east, right, south).
turn(south, right, west).
turn(west, right, north).
turn(north, left, west).
turn(east, left, north).
turn(south, left, east).
turn(west, left, south).
Example output...
2 ?- robot([go, 10, turn, left, go, 11], X, Y).
X = -11,
Y = 10