Some minor comments first: You do not need that cut at all. If you really want to restrict the predicate to exactly one answer, do it at the top using once/1
. That is not only conceptually cleaner, it is even more efficient.
The other problem you had is related to Prolog's unsafe negation. If you, accidentally as you did, hand over a goal that is too general, the negation will always fail. In other words: negation is next-to-broken in Prolog. There are two ways out: Either produce an error for such cases or simply use a better definition like non_member/2
.
Let's see what would have happened with non_member/2
in place:
link(b,brown,j).
route(X,X,[X],_).
route(X,Z,[X|Path],Positions):-
link(X,Colour,Y),
% \+member([Y,Colour],Positions),
non_member([Y,Colour],Positions),
route(Y,Z,Path,[[Y,Colour]|Positions]).
non_member(E, Es) :-
maplist(dif(E), Es).
?- route(X,Y,Path,Rs).
Y = X, Path = [X]
; X = b, Y = j, Path = "bj", Rs = []
; X = b, Y = j, Path = "bj", Rs = [_A],
dif([j,brown],_A)
; X = b, Y = j, Path = "bj", Rs = [_A,_B],
dif([j,brown],_A), dif([j,brown],_B)
; X = b, Y = j, Path = "bj", Rs = [_A,_B,_C],
dif([j,brown],_A), dif([j,brown],_B), dif([j,brown],_C)
; X = b, Y = j, Path = "bj", Rs = [_A,_B,_C,_D],
dif([j,brown],_A), dif([j,brown],_B), dif([j,brown],_C),
dif([j,brown],_D)
; X = b, Y = j, Path = "bj", Rs = [_A,_B,_C,_D,_E],
dif([j,brown],_A), dif([j,brown],_B), dif([j,brown],_C),
dif([j,brown],_D), dif([j,brown],_E)
; ... .
So all answers describe the same Path = "bj"
(short form for [b,j]
). But the last argument now is a list of elements that all must be different to [j,brown]
. So the best would have been:
route(X, Y, Path) :-
route(X, Y, Path, []).
And here is an alternate definition reusing path/4
. I am not really sure what you mean by these colors. Nevertheless:
clink(X-_, Y-Color) :-
link(X, Color, Y).
route(X, Y, Path) :-
path(clink, Path, X-none, Y-_).
or even shorter using library(lambda)
:
route(X, Y, Path) :-
path(\ (Xl,_)^(Yl^C)^clink(Xl,C,Yl), Path, X-none, Y-_).