0
votes

I am a beginner at prolog and required to write a predicate path(Start, Dest, Path) for metro stations application using backtracking. Given some facts: connected(x,y) describing the connected stations, I managed to do the following

%% Some facts (for illustration):
connected(a,b).
connected(b,c).
connected(c,d).
connected(d,e).
connected(e,f).

%% Direction A (e.g from b to e)
path1(Start, End, [[Start,End]]):- (connected(Start,End) ; connected(End,Start)),!.
path1(Start, End, [[Start,X]|Path]):-
    connected(Start, X),
    path1(X, End, Path).

%% Direction B (e.g from f to A)
path2(Start, End, [[Start,End]]):- (connected(Start,End) ; connected(End,Start)),!.
path2(Start, End, [[Start,X]|Path]):-
    connected(X, Start),
    path2(X, End, Path). 

%% And for the required predicate:
path(Start, End, Path):-
    path1(Start, End, Path)
    ;
    path2(Start, End, Path).

The above predicates works properly and as required, but what I want to do is to merge these two predicates into a single one in a better way and I don't know exactly how to do so. Anyone can help?

Thanks in advance.

EDIT:

I modified it to the following:

path(Start, End, [[Start,End]], _):- (connected(Start,End) ; connected(End,Start)),!.
path(Start, End, [[Start,X]|Path], Direction):-
    (Direction == 0,
    connected(Start, X),
    path(X, End, Path,0))
    ;
    (Direction == 1,
    connected(X, Start),
    path(X, End, Path,1))

%% And for the required predicate:
path(Start, End, Path):-
    path(Start, End, Path, 0)
    ;
    path(Start, End, Path, 1).

but still need to remove more of the repetitive code lines.

1
"these two predicates"? I count four. "in a better way" in what way? - Will Ness
I mean path1 and path2 predicates. I merged them using path, but you can see that they are the same predict with only changing the order of arguments in connected. I'm seeking to find a wat that makes me write only one predicate to act the same as the above code. @WillNess - Khalid
"Yes I've tried it before asking my question here and also traced it, so it doesn't work as needed. Explanation: If I queried path(a,c,Path), it would get the path correctly for the first backtrack, but then I need to cut. But if I queried the opposite direction path(c,a,Path), this would cause the stack to be filled with no need to as it keeps "swinging" between the facts. – Khalid 20 mins ago" so you actually had an actual code with an actual problem but did not include any of the specifics in your question? - Will Ness
I tried to do what you've suggested in so many ways and it didn't work for me so I didn't include it as it seemed wrong. I only included the working version of code to explain its idea and ask for working modifications. - Khalid

1 Answers

2
votes

A possible solution is:

path(Start, End, Path) :-
   path(_, Start, End, Path).

path(_, Start, Start, []).
path(Direction, Start, End, [[Start,X]|Path]) :-
   link(Direction, Start, X),
   path(Direction, X, End, Path).

link(forward,  X, Y) :- connected(X, Y).
link(backward, X, Y) :- connected(Y, X).

connected(a,b).
connected(b,c).
connected(c,d).
connected(d,e).
connected(e,f).

Examples:

?- path(c, a, P).
P = [[c, b], [b, a]] ;
false.

?- path(a, c, P).
P = [[a, b], [b, c]] ;
false.

?- path(D, a,c,P).
D = forward,
P = [[a, b], [b, c]] ;
false.

?- path(D, c, a, P).
D = backward,
P = [[c, b], [b, a]] ;
false.