for-loop in prolog doesn't work - prolog

I'm trying to do a for loop in Prolog which doesn't work. The program should do following:
generate(N,[S,E],FinalSegments):-
segments([S,E],Initialsegments),
iterate_level(N,Initialsegments,FinalSegments).
When I'm calling generate(5,[(10,0),(-10,0)]) the first step is, that generate(5,[(10,0),(-10,0)],FinalSegments) is being called and this predicate generates 4 coordinates between the Startpoint (10,0) and the Endpoint (-10,0), and store those four ccordinates in the listFinalSegments. This is actually done correctly. In the next step the predicate iterate_level(N,Initialsegments,FinalSegments) is being called.
The predicate iterate_level(), takes the four coordinates from the last step as a list called Initialsegments:
Initialsegments:([[ (10, 0), (3.333333333333333, 0)],
[ (3.3333, 0), (-3.5527e-15, -5.7735)],
[ (-3.5527e-15, -5.77350), (-3.3333, 0)],
[(-3.3333, 0), (-10, 0)]])
And now iterate_level(5,Initialsegments,FinalSegments) should be a for-loop which should generate 16 coordinates after the first iteration, then 64 coordinates after the second iteration...
But here is my problem that this is not really working and I don't know what I'm still doing wrong.
It seem to me, when I'm looking at the trace, that
iterate_level(N,Ls,F):-
seq(0,N,Index),
next_level_segments(Index,Ls,F).
when next_level_segments(Index,Ls,F) is called within the for-loop, the list
Ls which should contain four times more coordinates after each iteration is not refreshed.(Maybe this is the problem).
When I call generate(3,[[(60,0),(-60,0)]],X). I get four times always the same 16 coordinates as a result but I should get 1024 different coordinates.
Maybe someone may have some time to have a look at this problem an give me some help.
Thanks
This is my implementation until now:
generate(N,[S,E],FinalSegments):-
segments([S,E],Initialsegments),
iterate_level(N,Initialsegments,FinalSegments).
generate(N,[],[]).
seq(From,_,From).
seq(From,To,X) :-
From<To,
Next is From+1,
seq(Next,To,X).
iterate_level(N,Ls,F):-
seq(0,N,Index),
next_level_segments(Index,Ls,F).
%fail.
iterate_level(Ls,F).
iterate_level([],[]).
segments([(Sx,Sy),(Ex,Ey)],Ls):-
X2 is Sx+(Ex-Sx)/3,
Y2 is Sy+(Ey-Sy)/3,
R1 is sqrt((X2-Sx)*(X2-Sx)+(Y2-Ey)*(Y2-Ey)),
Phi1 is atan((Y2-Sy)/(X2-Sx)),
X3 is X2 +R1*cos((Phi1-240)*pi/180),
Y3 is Y2 +R1*sin((Phi1+240)*pi/180),
X4 is X2+(X2-Sx),
Y4 is Y2+(Y2-Sy),
Ls=[
[(Sx,Sy),(X2,Y2)],
[(X2,Y2),(X3,Y3)],
[(X3,Y3),(X4,Y4)],
[(X4,Y4),(Ex,Ey)]
].
next_level_segments(N,[[(Sx,Sy),(Ex,Ey)]|E],[X|RLs]):-
segments([(Sx,Sy),(Ex,Ey)],X),
next_level_segments(N,E,RLs).
next_level_segments(N,[],[]).

So, first of all, Prolog doesn't do for-loops in the traditional sense - what you actually want to do is recurse over the list with an accumulator. This can be achieved as follows.
Firstly, generate(0, [[X|Y]|Z], [[X|Y]|Z]) :- !., which says "if I am trying to generate the 0th iteration of a list of lists, I have achieved my goal and I should succeed". This also cuts, as there is only ever going to be a single solution here.
generate(N, [[P1, P2]|Tail], Final) does the main body of the (outer) recursion. As long as this is a positive iteration (ie exclude negatives), we do_generate an iteration of coordinates, and recurse for another iteration (with iteration 0 succeeding as above).
do_generate([],[]). states that if we're trying to generate coordinates between an empty list, we're done for this level.
do_generate([Current|Rest], Interim) takes the first pair of coordinates and generates the set of four pairs of coordinates (using segments([(Sx,Sy),(Ex,Ey)],Ls) as before), then recurses onto the rest of the list of coordinates. Once we reach the above base-case, we append all the lists together from last to first to get the new set of coordinates. This is then unified with Interim, to send back to generate(N, [[P1, P2]|Tail], Final) for further recursion or unification with Final using the outer base-case.
As a caveat, in order to get output looking like input for the final base-case, the input is now required to be a list of lists of coordinate-pairs, not just a list of coordinate-pairs.
All put together, you get the following:
generate(0, [[X|Y]|Z], [[X|Y]|Z]) :- !.
generate(N, [[P1, P2]|Tail], Final) :-
N > 0,
do_generate([[P1, P2]|Tail], Interim),
N1 is N-1,
generate(N1, Interim, Final).
do_generate([], []).
do_generate([Current|Rest], Interim) :-
segments(Current, Segs),
do_generate(Rest, RestSegs),
append(Segs, RestSegs, Interim).
segments([(Sx,Sy), (Ex,Ey)], Ls) :-
X2 is Sx+(Ex-Sx)/3,
Y2 is Sy+(Ey-Sy)/3,
R1 is sqrt((X2-Sx)*(X2-Sx)+(Y2-Ey)*(Y2-Ey)),
Phi1 is atan((Y2-Sy)/(X2-Sx)),
X3 is X2+R1*cos((Phi1-240)*pi/180),
Y3 is Y2+R1*sin((Phi1+240)*pi/180),
X4 is X2+(X2-Sx),
Y4 is Y2+(Y2-Sy),
Ls=[[(Sx,Sy),(X2,Y2)],
[(X2,Y2),(X3,Y3)],
[(X3,Y3),(X4,Y4)],
[(X4,Y4),(Ex,Ey)]].

Related

How to test a predicate on a range of numbers and return those that pass in Prolog

I am trying to write a predicate in Prolog that will use my predicate 'PAR', which tests whether a 4 digit number meets certain conditions, but return a list of all numbers which are PARs, i.e. all numbers which return true when passed into par.
pars(A, C)
:- A =< 9999,
par(A) -> append(C, A, C),
A1 is A+1,
pars(A1, C).
This is my current code, with A initially passed in as 1000 (the smallest 4 digit number), but it will only return false when the first number is tried, or timeout if the first number is a PAR.
I also want the predicate to take only one argument, e.g. pars(X) where X is then the list of PARs.
par(A)
:- number_chars(A, [W,X,Y,Z]),
unique([W,X,Y,Z]),
atom_number(W, W1),
atom_number(X, X1),
atom_number(Y, Y1),
atom_number(Z, Z1),
B1 is W1 * 10 + X1,
B2 is Y1 * 10 + Z1,
0 is mod(B1,B2).
Here is my par predicate for reference, I know this is also probably very inefficient.
Any help would be appreciated, thanks in advance.
The easy way is to use a "solution-collecting" metapredicate, i.e. findall/3, bagof/3 or setof/3:
findall(P,(between(1000,9999,P),par(P)),Bag).
In this case the subgoal is between(1000,9999,P),par(P):
Generate a number P between 1000 and 9999
Test is for "par-ity"
If there is success of the above, it will be in the list Bag when findall/3 succeeds.
If there is failure of the above, the Prolog processor backtracks to the start of the subgoal and tries again, generating and testing the next number.
This can also be written more extensively (i.e. not "inlined"):
subgoal(P) :- between(1000,9999,P),par(P).
findthem(Bag) :- findall(P,subgoal(P),Bag).
(Testing this fails because I dont't have the definition of unique/1 as used in par/1.)

How can I verify if a coordinate is in a list

I'm generating random coordinates and adding on my list, but first I need verify if that coordinate already exists. I'm trying to use member but when I was debugging I saw that isn't working:
My code is basically this:
% L is a list and Q is a count that define the number of coordinate
% X and Y are the coordinate members
% check if the coordniate already exists
% if exists, R is 0 and if not, R is 1
createCoordinates(L,Q) :-
random(1,10,X),
random(1,10,Y),
convertNumber(X,Z),
checkCoordinate([Z,Y],L,R),
(R is 0 -> print('member'), createCoordinates(L,Q); print('not member'),createCoordinates(L,Q-1).
checkCoordinate(C,L,R) :-
(member(C,L) -> R is 0; R is 1).
% transforms the number N in a letter L
convertNumber(N,L) :-
N is 1, L = 'A';
N is 2, L = 'B';
...
N is 10, L = 'J'.
%call createCoordinates
createCoordinates(L,20).
When I was debugging this was the output:
In this picture I'm in the firts interation and L is empty, so R should be 1 but always is 0, the coordinate always is part of the list.
I have the impression that the member clause is adding the coordinate at my list and does'nt make sense
First off, I would recommend breaking your problem down into smaller pieces. You should have a procedure for making a random coordinate:
random_coordinate([X,Y]) :-
random(1, 10, XN), convertNumber(XN, X),
random(1, 10, Y).
Second, your checkCoordinate/3 is converting Prolog's success/failure into an integer, which is just busy work for Prolog and not really improving life for you. memberchk/2 is completely sufficient to your task (member/2 would work too but is more powerful than necessary). The real problem here is not that member/2 didn't work, it's that you are trying to build up this list parameter on the way out, but you need it to exist on the way in to examine it.
We usually solve this kind of problem in Prolog by adding a third parameter and prepending values to the list on the way through. The base case then equates that list with the outbound list and we protect the whole thing with a lower-arity procedure. In other words, we do this:
random_coordinates(N, Coordinates) :- random_coordinates(N, [], Coordinates).
random_coordinates(0, Result, Result).
random_coordinates(N, CoordinatesSoFar, FinalResult) :- ...
Now that we have two things, memberchk/2 should work the way we need it to:
random_coordinates(N, CoordinatesSoFar, FinalResult) :-
N > 0, succ(N0, N), % count down, will need for recursive call
random_coordinate(Coord),
(memberchk(Coord, CoordinatesSoFar) ->
random_coordinates(N, CoordinatesSoFar, FinalResult)
;
random_coordinates(N0, [Coord|CoordinatesSoFar], FinalResult)
).
And this seems to do what we want:
?- random_coordinates(10, L), write(L), nl.
[[G,7],[G,3],[H,9],[H,8],[A,4],[G,1],[I,9],[H,6],[E,5],[G,8]]
?- random_coordinates(10, L), write(L), nl.
[[F,1],[I,8],[H,4],[I,1],[D,3],[I,6],[E,9],[D,1],[C,5],[F,8]]
Finally, I note you continue to use this syntax: N is 1, .... I caution you that this looks like an error to me because there is no distinction between this and N = 1, and your predicate could be stated somewhat tiresomely just with this:
convertNumber(1, 'A').
convertNumber(2, 'B').
...
My inclination would be to do it computationally with char_code/2 but this construction is actually probably better.
Another hint that you are doing something wrong is that the parameter L to createCoordinates/2 gets passed along in all cases and is not examined in any of them. In Prolog, we often have variables that appear to just be passed around meaninglessly, but they usually change positions or are used multiple times, as in random_coordinates(0, Result, Result); while nothing appears to be happening there, what's actually happening is plumbing: the built-up parameter becomes the result value. Nothing interesting is happening to the variable directly there, but it is being plumbed around. But nothing is happening at all to L in your code, except it is supposedly being checked for a new coordinate. But you're never actually appending anything to it, so there's no reason to expect that anything would wind up in L.
Edit Notice that #lambda.xy.x solves the problem in their answer by prepending the new coordinate in the head of the clause and examining the list only after the recursive call in the body, obviating the need for the second list parameter.
Edit 2 Also take a look at #lambda.xy.x's other solution as it has better time complexity as N approaches 100.
Since i had already written it, here is an alternative solution: The building block is gen_coord_notin/2 which guarantees a fresh solution C with regard to an exclusion list Excl.
gen_coord_notin(C, Excl) :-
random(1,10,X),
random(1,10,Y),
( memberchk(X-Y, Excl) ->
gen_coord_notin(C, Excl)
;
C = X-Y
).
The trick is that we only unify C with the new result, if it is fresh.
Then we only have to fold the generations into N iterations:
gen_coords([], 0).
gen_coords([X|Xs], N) :-
N > 0,
M is N - 1,
gen_coords(Xs, M),
gen_coord_notin(X, Xs).
Remark 1: since coordinates are always 2-tuples, a list representation invites unwanted errors (e.g. writing [X|Y] instead of [X,Y]). Traditionally, an infix operator like - is used to seperate tuples, but it's not any different than using coord(X,Y).
Remark 2: this predicate is inherently non-logical (i.e. calling gen_coords(X, 20) twice will result in different substitutions for X). You might use the meta-level predicates var/1, nonvar/1, ground/1, integer, etc. to guard against non-sensical calls like gen_coord(1-2, [1-1]).
Remark 3: it is also important that the conditional does not have multiple solutions (compare member(X,[A,B]) and memberchk(X,[A,B])). In general, this can be achieved by calling once/1 but there is a specialized predicate memberchk/2 which I used here.
I just realized that the performance of my other solutions is very bad for N close to 100. The reason is that with diminishing possible coordinates, the generate and test approach will take longer and longer. There's an alternative solution which generates all coordinates and picks N random ones:
all_pairs(Ls) :-
findall(X-Y, (between(1,10,X), between(1,10,Y)), Ls).
remove_index(X,[X|Xs],Xs,0).
remove_index(I,[X|Xs],[X|Rest],N) :-
N > 0,
M is N - 1,
remove_index(I,Xs,Rest,M).
n_from_pool(_Pool, [], 0).
n_from_pool(Pool, [C|Cs], N) :-
N > 0,
M is N - 1,
length(Pool, L),
random(0,L,R),
remove_index(C,Pool,NPool,R),
n_from_pool(NPool, Cs, M).
gen_coords2(Xs, N) :-
all_pairs(Pool),
n_from_pool(Pool, Xs, N).
Now the query
?- gen_coords2(Xs, 100).
Xs = [4-6, 5-6, 5-8, 9-6, 3-1, 1-3, 9-4, 6-1, ... - ...|...] ;
false.
succeeds as expected. The error message
?- gen_coords2(Xs, 101).
ERROR: random/1: Domain error: not_less_than_one' expected, found0'
when we try to generate more distinct elements than possible is not nice, but better than non-termination.

Iterating List in Prolog

I would like to iterate a list in Prolog an write a generated result into a new list.
With the predicate next_level_segments(List of Start-, Endcoordinates)
I would like to calculate four lists of four coordinates between each pair of Start-, and Endcoordinates and store this four lists in Ls.
This means when I call for example
next_level_segments([
[(10,0),(3.3,0)],
[(3.3,0),(0,-5.8)],
[(0,-5.8),(-3.3,0)],
[(-3.3,0),(-10,0)]
])
the predicate segments() should calculate the four next coordinates between
the pair of Start- and Endcoordinates for example [(10,0),(3.3,0)].
So next_level_segments should iterate through the list of Start and Endpoints, segments should do the calculation and the result of four list, with each four pairs of coordinates should be stored in the a resulting list.
When I call next_level_segments() with a list of four coordinates, the calculation is done and the coordinates are generated when i look at the trace, but aren't stored correctly.
As far as I can see it in the trace, the last list of four coordinates is missing.
Maybe somebody may have a look and have some advice what I'm doing wrong.
Thank you
segments([(Sx,Sy),(Ex,Ey)],Ls):-
X2 is Sx+(Ex-Sx)/3,
Y2 is Sy+(Ey-Sy)/3,
R1 is sqrt((X2-Sx)*(X2-Sx)+(Y2-Ey)*(Y2-Ey)),
Phi1 is atan((Y2-Sy)/(X2-Sx)),
X3 is X2 +R1*cos((Phi1-240)*pi/180),
Y3 is Y2 +R1*sin((Phi1+240)*pi/180),
X4 is X2+(X2-Sx),
Y4 is Y2+(Y2-Sy),
Ls=[
[(Sx,Sy),(X2,Y2)],
[(X2,Y2),(X3,Y3)],
[(X3,Y3),(X4,Y4)],
[(X4,Y4),(Ex,Ey)]].
next_level_segments([[(Sx,Sy),(Ex,Ey)]|E],[X|RLs]):-
segments([(Sx,Sy),(Ex,Ey)],X),
next_level_segments(E,RLs).
next_level_segments([],[]).
Your next_level_segments/2 needs only two clauses (instead of the three you are using). The first one should be:
next_level_segments([], []).
Both the first and the third clause you have at the moment should go because they don't do anything useful.
The recursive clause seems fine as it is at the moment.
Corrected like this, I get:
?- next_level_segments(
[[(10,0),(3.3,0)],
[(3.3,0),(0,-5.8)],
[(0,-5.8),(-3.3,0)],
[(-3.3,0),(-10,0)]
],
X).
X = [[[(10, 0), (7.766666666666667, 0)], [(7.766666666666667, 0), (6.649999999999999, -1.9341234017852458)], [(6.649999999999999, -1.9341234017852458), (5.533333333333333, 0)], [(5.533333333333333, 0), (3.3, 0)]],
[[(3.3, 0), (2.2, -1.9333333333333333)], [(2.2, -1.9333333333333333), (0.1262841490828066, -5.451200543142186)], [(0.1262841490828066, -5.451200543142186), (1.1000000000000005, -3.8666666666666667)], [(1.1000000000000005, -3.8666666666666667), (0, -5.8)]],
[[(0, -5.8), (-1.0999999999999999, -3.8666666666666663)], [(-1.0999999999999999, -3.8666666666666663), (-3.0456930398351094, -7.310619872034865)], [(-3.0456930398351094, -7.310619872034865), (-2.1999999999999997, -1.9333333333333327)], [(-2.1999999999999997, -1.9333333333333327), (-3.3, 0)]],
[[(-3.3, 0), (-5.533333333333333, 0)], [(-5.533333333333333, 0), (-6.65, -1.9341234017852458)], [(-6.65, -1.9341234017852458), (-7.766666666666667, 0)], [(-7.766666666666667, 0), (-10, 0)]]
].
Keep in mind that a trivial list iteration like this can also be written simply as:
maplist(segments, Input, Output)
In other words, apply segments/2 to each corresponding element in the two lists. You would have to redefine your segments/3 however to have two arguments instead of three, for example by re-writing the head to:
segments([(Sx,Sy),(Ex,Ey)], Ls)
(put the two first arguments in a list, as they are in your input list)
A small comment: a pair in Prolog is usually written as X-Y, not as (X, Y). Many standard library predicates represent "pairs" as X-Y, for example keysort/2, library(pairs) and so on. If you want to, you could also give your pair a descriptive name like pair(X,Y) or coordinates(X,Y). It doesn't really matter of only two elements, but a "tuple" with three elements like this: (X,Y,Z) is actually a nested term:
?- write_canonical((X,Y,Z)).
','(_,','(_,_))
true.
You get the same problem with X-Y-Z:
?- write_canonical(X-Y-Z).
-(-(_,_),_)
true.
At that point you could again use a term with a descriptive name, for example triple(X, Y, Z) or coordinates(X, Y, Z).

Prolog project. Labyrinth. Checking if next move is possible

Noob at prolog.
I need to do a school project related to a labyrinth.
My question is:
In the project I need to make a function "possible moves".
It gets a labyrinth, a current position and previous moves
Lab is represented by (these are the walls positions):
[[[down,left,up],[left,down,up],[right,up],[up],[,up],[right,left,up]],
[[left,down],[down,up],[down,up],[],[down],[right,down]],
[[left,up],[down,up],[down,up],[down],[down,up],[right,down,up]],
[[right,left],[left,up],[up],[up],[up],[right,up]],
[[left,down],[right,down],[left,down],[down],[down],[right,down]]]
And Poss_moves like:
Poss_moves(Lab, current_poss, previous_moves, possible_moves)
which is called as follows.
?- ..., poss_moves(Lab1, (2,5),
[(beginning, 1, 6), (down, 2, 6), (left, 2, 5)], possible_moves).
Lab1 = ...,
Poss = [ (up, 1, 5), (left, 2, 4)].
Important:
--- You can only move up, down, left or right.
PS: Sorry for my bad english.
PS: Edited.
PS: Can I do in prolog:
distance((Line1, Column1), (Line2, Column2), Dist) :-
Dist is abs(Line1 - Line2) + abs(Column1 - Column2).
PS: The lab that matches the picture.
[[[right,left,up],[left,down,up],[down,up],[up],[right,up],[right,left,up]],
[[left,down],[down,up],[b,up],[],[down],[right,down]],
[[left,up],[down,up],[down,up],[down],[down,up],[right,down,up]],
[[right,left],[left,up],[up],[up],[up],[right,up]],
[[left,down],[right,down],[left,down],[down],[down],[right,down]]]
By the way, the lab can change.
Thanks
EDIT 2:
I made this changes:
% predicates
lookup(Lab,(X,Y),Walls)
calc(Direction,(X1,Y1),(X2,Y2)
map_calc((X,Y),L,R)
poss_moves(Lab, (X,Y), PreviousMoves, PossibleMoves)
% clauses
nth(1, [H|T], H).
nth(N,[_|T],R) :-
M is N-1,
nth(M,T,R).
lookup(Lab, (X, Y), Walls) :-
nth(N,Lab,R),
Y == R,
X == Walls.
calc(up,(X,Y1),(X,Y2)) :-
Y2 is Y1-1.
calc(down,(X,Y1),(X,Y2)) :-
Y2 is Y1+1.
calc(left,(X,Y1),(X,Y2)) :-
X2 is X1-1.
calc(right,(X,Y1),(X,Y2)) :-
X2 is X1+1.
map_calc(_,[],[]).
map_calc((X,Y),[H|T],[(H,X1,Y1)|S]) :-
calc(H,(X,Y),(X1,Y1)),
map_calc((X,Y),T,S).
% main predicates
poss_moves(Lab, (X,Y), PreviousMoves, PossibleMoves) :-
lookup(Lab, (X,Y), Walls),
map_calc((X,Y), Lab, PossibleMoves).
I'm almost 100% sure that the lookup is incorrect.
Thanks
The first thing you need to do is define a way of looking up a cell in the Labryinth datastructure. You need something like:
lookup(Lab,(X,Y),Walls)
which is true if Walls is the list of walls present at cell (X,Y) in Lab. To do this you'll need an 'nth' predicate which finds the nth element of the list.
nth(1,[H|T],H).
nth(N,[_|T],R) :- M is N-1, nth(M,T,R).
Normally one would use 0 to return the first element of a list but your maze co-ordinates start at (1,1) so I've made nth do the same.
Now you can build lookup(Lab,(X,Y),Walls) which is true if the Yth element of Lab is Row and the Xth element of Row is Walls.
Next you need a way of turning the list of Walls in to a list of possible moves. A move consists of a direction and the co-ordinates of the new position so first write some helpers to calculate the new co-ordinates:
calc(Direction,(X1,Y1),(X2,Y2)
should be true if (X2,Y2) is the co-ordinate you get to if you move in Direction from (X1,Y1). Here is an example clause of calc, the others are similar:
calc(up,(X,Y1),(X,Y2)) :- Y2 is Y1-1.
But we need to apply calc to every element of the list of Walls to get the list of moves (this is called 'map' in functional programming)
map_calc((X,Y),L,R)
should be true if R is the result of applying calc to every direction in L starting from co-ordinate (X,Y).
map_calc(_,[],[]).
map_calc((X,Y),[H|T],[(H,X1,Y1)|S]) :- calc(H,(X,Y),(X1,Y1)),
map_calc((X,Y),T,S).
Now you can write poss_moves:
poss_moves(Lab, (X,Y), PreviousMoves, PossibleMoves)
i.e. PossibleMoves is the list of moves you can make from (X,Y) given that lookup(Lab,(X,Y),Walls) is true, and that map_calc on Walls gives you PossibleMoves.

using arithmetic operations in Prolog

I have the following code:
position(0,0).
move(f):-
position(X,Y),
number(X),
number(Y),
Y is Y+1,
X is X+1.
but when i call move(f) it returns false. number(X) and number(Y) returns true but whem i add the other two lines the function doesn't work. what's the problem?
Elaborating on some of the comments your question has received, variables in Prolog stand for a possible instantiation of a single value, just like variables in mathematics and mathematical logic, and once they are instantiated within a context they must remain consistent. If we're dealing with a formula 0 = (a + b) - (a + b), we know that it can only express its intended sense if any value assigned to the first a is also assigned to the second. That is, we can substitute any value for a, but it must be the same value throughout. Prolog works with variables in this same way. If x = x + 1, then 2 = 3; but then math would be broken.
Addressing mat's caution against using dynamic predicates, here is a possible way of handling moves, but accomplished by passing around a list of previous moves. With this method, the most recent move will always be the first element of List in the compound term moves(List).
Supposing the current history of moves is as follows:
moves([position(0,0), position(0,1), position(1,1)]).
move/3 takes a direction, a complex term representing the previous moves, and tells us what the updated list of moves is.
move(Direction, moves([From|Ms]), moves([To,From|Ms])) :-
move_in_direction(Direction,From,To).
move_in_direction/3 takes a direction, and a position, and tells us what the next position in that direction is:
move_in_direction(left, position(X1,Y1), position(X2,Y1)) :- X2 is X1 - 1.
move_in_direction(right, position(X1,Y1), position(X2,Y1)) :- X2 is X1 + 1.
move_in_direction(up, position(X1,Y1), position(X1,Y2)) :- Y2 is Y1 + 1.
move_in_direction(down, position(X1,Y1), position(X1,Y2)) :- Y2 is Y1 - 1.
Notice that, using this method, you get a back-trackable history of moves for free. I'd imagine you could use this in interesting ways -- e.g. having the player explore possible series of moves until a certain condition is met, at which point it commits or backtracks. I'd be interested to know what kind of solution you end up going with.

Resources