Traversal through Room - prolog

I keep getting false for path_to_phone(1, 16, Path). and cannot figure out where the error is in the code.
door(1,2).
door(1,7).
door(2,1).
door(2,8).
door(3,8).
door(4,8).
door(4,9).
door(5,9).
door(5,6).
door(6,9).
door(7,1).
door(7,8).
door(7,9).
door(7,10).
door(7,11).
door(7,12).
door(7,13).
door(7,14).
door(8,2).
door(8,3).
door(8,4).
door(8,7).
door(9,4).
door(9,5).
door(9,6).
door(9,7).
door(10,7).
door(11,7).
door(12,7).
door(13,7).
door(14,7).
door(14,15).
door(15,16).
door(16,15).
phone(5).
phone(9).
phone(16).
rooms_connected(X, Y) :- door(X, Y), door(Y, X).
path_to_phone(Start, End, Path) :-
move(Start, End,[Start], Room),
reverse(Room,Path).
move(Start, End, Path, [End|Path]) :-
rooms_connected(Start, End),
phone(End).
move(Start, Middle, Visit, Path) :-
rooms_connected(Start, End),
End \== Middle,
\+member(End, Visit),
move(End, Middle, [End|Visit], Path).

From an aesthetical point of view, it would look better like this:
move(Start, End, Visit, Path) :- rooms_connected(Start, Middle),
End \== Middle,
\+member(Middle, Visit),
move(Middle, End, [Middle|Visit], Path).
The problem is your definition of rooms_connected because it forces to have the connection both ways. If thats what you intended you have to put in the file doors(15,14) and others, because as it is now, it cannot find a path.
If not you can change it to:
rooms_connected(X, Y) :- door(X, Y); door(Y, X).
This means either door(X,Y) or door(Y,X).

I think should be simpler, no need to pass around the confusing Middle:
path_to_phone(Start, End, Path) :-
move(Start, [Start], [End|RPath]),
reverse([End|RPath], Path).
move(From, Visit, [Phone|Visit]) :-
door(From, Phone),
phone(Phone).
move(From, Visit, Path) :-
door(From, Next),
\+memberchk(Next, Visit),
move(Next, [Next|Visit], Path).

Related

Prolog get list from different relations

i´d like to get a list from a graph. The variables with two letters are the points and the one letter is a line. Each line can contain multiple points.
conn(bs, oc, c).
conn(oc, tc, c).
conn(bs, gp, j).
conn(gp, cc, j).
conn(gp, pc, p).
conn(pc, ls, p).
conn(gp, oc, v).
conn(oc, pc, b).
conn(pc, cc, b).
conn(tc, ls, n).
conn(ls, cc, n).
link(X, Y, Z) :- conn(X, Y, Z), !.
link(X, Y, Z) :- conn(Y, X, Z).
Now i want to get a list with all points belonging to a line. By typing:
getpoints(c, X).
i would expect
X = [bs, oc, tc]
This is how i tried to get my result:
getpoints(Line, [First|[]]) :- not(link(First, _Second, Line)).
getpoints(Line, [First|Rest]) :- link(First, _Second, Line), getpoints(Line, Rest).
Does anybody has an idea?
If you aren't interested in a particular order of points, you could use setof/3
By example
getpoints(Line, Points) :-
setof(X, Y^(conn(X, Y, Line) ; conn(Y, X, Line)), Points).
--- EDIT ---
Is it very complicadet to get the order of the points?
If you're point are really a line (not a more general graph), you can write something like
nextLine(Line, EndLine, []) :-
\+ conn(EndLine, _, Line).
nextLine(Line, Start, [NextPoint | NextLine]) :-
conn(Start, NextPoint, Line),
nextLine(Line, NextPoint, NextLine).
getpoints(Line, [Start, NextPoint | NextLine]) :-
conn(Start, NextPoint, Line),
\+ conn(_, Start, Line),
nextLine(Line, NextPoint, NextLine).
The idea is find, in getpoints/2, the Start point of the line, that is the point that is on the left of a conn/3 (conn(Start, NextPoint, Line)) but isn't on the right of a conn/3 (\+ conn(_, Start, Line)).
In this way you have the first two point of the line and, calling nextLine/3 recursively, you detect the following points in the correct order.

Breadth First Search in Prolog

I'm new to Prolog and currently implementing DFS (depth-first search) and BFS (breadth-first search) algorithms. My DFS works fine as the code below, but the BFS is terminated and aborted when it reaches the leaf node (it doesn't backtrack and continue searching).
I also read some sample code about this but there are some functions they don't define like s(Node, NewNode)... so it's hard to understand, or the version use Queue is too complicated.
Here is my code:
Some ground functions:
%connected(+Start, +Goal, -Weight)
connected(1,7,1).
connected(1,8,1).
connected(1,3,1).
connected(7,4,1).
connected(7,20,1).
connected(7,17,1).
connected(8,6,1).
connected(3,9,1).
connected(3,12,1).
connected(9,19,1).
connected(4,42,1).
connected(20,28,1).
connected(17,10,1).
connected2(X,Y,D) :- connected(X,Y,D).
connected2(X,Y,D) :- connected(Y,X,D).
next_node(Current, Next, Path) :-
connected2(Current, Next, _),
not(member(Next, Path)).
DFS implement:
depth_first(Goal, Goal, _, [Goal]).
depth_first(Start, Goal, Visited, [Start|Path]) :-
next_node(Start, Next_node, Visited),
write(Visited), nl,
depth_first(Next_node, Goal, [Next_node|Visited], Path).
BFS implement:
breadth_first(Goal, Goal, _,[Goal]).
breadth_first(Start, Goal, Visited, Path) :-
findall(X,
(connected2(X,Start,_),not(member(X,Visited))),
[T|Extend]),
write(Visited), nl,
append(Visited, [T|Extend], Visited2),
append(Path, [T|Extend], [Next|Path2]),
breadth_first(Next, Goal, Visited2, Path2).
The Path is something like the Queue list.
For example when call DFS:
?- depth_first(1, 28, [1], P).
BFS:
?- breadth_first(1, 28, [1], []).
First, the usual notion of s(A,B) is just like your connect2(A,B,_).
You should make your interface predicates explicit:
depth_first( Start, Goal, Path):-
depth_first( Start, Goal, [Start], Path).
Maintaining a queue in BFS is not complicated at all. Instead of Visited, have VisitedLists queue (pop from front; add at end; thus FIFO):
consed( A, B, [B|A]).
bfs( Goal, [Visited|Rest], Path) :- % take one from front
Visited = [Start|_],
Start \== Goal,
findall( X,
( connected2(X, Start, _), \+ member(X, Visited) ),
[T|Extend]),
maplist( consed(Visited), [T|Extend], VisitedExtended), % make many
append( Rest, VisitedExtended, UpdatedQueue), % put them at the end
bfs( Goal, UpdatedQueue, Path ).
When the goal is reached, Path is instantiated:
bfs(Goal, [[Goal|Visited]|_], Path):-
reverse([Goal|Visited], Path).
The interface call needs to be adjusted correspondingly. It should be
breadth_first( Start, Goal, Path):- bfs( Goal, [[Start]], Path).
later note: repeated appending of course causes quadratic slowdown, so for efficiency this should be re-written with difference lists (also a straightforward task).

Successful prolog query not showing true

Testing some Prolog code to see if I can show gameover when a white(w) has a connected path from one side of the board to the other.
My biggest problem so far is while gameover/2 does go through all the nodes on each side and checks if their connected it doesn't stop or show when they are. Thus when testing this query:
gameover([[e,e,b,e,e],[e,w,w,b,e],[b,w,b,w,w],[w,w,b,b,b],[e,e,b,w,e]], w).
Prolog returns no when it should be true. I've gone through everything I can but I am new to Prolog and I'm sure I must be missing something obvious.
gameover(State, w) :-
width(State, W), write(W), nl,
series(1, W, NewList), write(NewList), nl,
member(X1, NewList), write(X1), nl,
write(loc(X1,1)), nl, write('X1'), nl,
member(X2, NewList), write(X2), nl,
write(loc(X2,W)), nl, write('X2'), nl,
connected(State, loc(X1,1), loc(X2,W), w).
I've tested connected, member, series and width each very thoroughly and am sure they all work so I think it must be something I have done in the code above.
There is also a similar predicate for gameover(State,b) that uses the Y coordinate rather than the X. It's also having the same troubles.
Connected:
connected(State, Start, End, Colour) :- get_location(State, End, Colour),
get_location(State, Start, Colour),
connects(State, End, Colour, Start, [Start]).
connected(_State, _Next, _Colour, End, Close):- member(End, Close).
%checking to make sure every node is connected to the other using linked
%list of children from linked- check child is not member of closed list(meaning it has been checked before)
%get location of child to check for colour
%recursive call, include children in closed list to mark they have been checked and won't be checked again
connects(State, End, Colour, Next, Close) :- linked(Next, Child),
\+member(Child, Close),
get_location(State, Child, Colour),
connects(State, End, Colour, Child, [Child|Close]).
connects(_State, End, _Colour, End, _Close).
with appropriate simplification, and removing undue display of intermediate computation, here is a sketch that could help you
gameover(State, Colour) :-
width(State, W),
get_location(State, loc(X1,1), Colour),
connected(State, loc(X1,1), loc(_,W), w).
connected(State, L1, L2, Colour) :-
connected_(State, [L1], L2, Colour).
connected_(_State, [Target|_], Target, _Colour).
connected_(State, [Last|Visited], Target, Colour) :-
linked(Last,Link),
get_location(State, Link, Colour),
\+ memberchk(Link, Visited),
connected_(State, [Link,Last|Visited], Target, Colour).
the key it's the service predicate connected_, that holds a list of visited locs instead of the starting one, then enabling a simple depth first visit. A small test, with a silly topology
width(_State, 3).
linked(loc(X,Y),loc(U,V)) :- (U is X+1 ; U is X-1), Y=V.
linked(loc(X,Y),loc(U,V)) :- (V is Y+1 ; V is Y-1), X=U.
get_location(State, loc(X,Y), Colour) :-
nth(Y,State,Row), nth(X,Row,Colour).
?- S = [[e,w,e],[e,w,e],[e,w,e]], gameover(S,w).
S = [[e, w, e], [e, w, e], [e, w, e]]
.
?- S = [[w,e,e],[e,w,e],[e,w,e]], gameover(S,w).
false.

Want to print the path,but getting errors

domains
list=symbol*
predicates
path(symbol,symbol)
solve(symbol,symbol,list)
insert(symbol,list,list)
clauses
path(a,b).
path(b,c).
path(c,d).
path(d,e).
path(a,d).
path(c,e).
solve(X, Z, P):-
path(X,Z),
insert(Z,Temp,P),
P=Temp.
solve(X,Z,P):-
path(X,Y),
insert(Y,Temp,P),
P=Temp,
solve(Y,Z,P).
insert(X,[X|Tail],Tail).
insert(X,[Y|Tail],[Y|Tail1]):-
insert(X,Tail,Tail1).
Want to print the path which i have followed in going from one point to another.But getting errors.For examples, i want:
goal
solve(a,c,P).
Answer:P=[a,b,c]
I don't get what your solve predicate does. Here is my guess about how it should be :
solve(Start, End, [Start|PathMinusStart]) :-
solve_(Start, End, PathMinusStart).
solve_(Start, End, [End]) :-
path(Start, End).
solve_(Start, End, [Waypoint|Path]) :-
path(Start, Waypoint),
solve_(Waypoint, End, Path).
solve will give you the paths one after another using the ; to browse them (well, I guess at least since I don't know anything about the prolog implementation you're using).
search_path(Node, End, Temp, Path) :- path(Node,End),reverse([End | [Node | Temp]], Path).
search_path(Node, End, Temp, Path) :-
path(Node, Next),
not(member(Node, Temp)),
search_path(Next, End, [Node | Temp], Path).
solve(Start, End, Path) :- search_path(Start, End, [], Path).

graph path in prolog

I've made the rules to obtain a path of a graph with the edges defined as follows:
graph(a,b).
graph(a,a).
graph(b,c).
but now I need to do it when the facts being, for example:
graph(a,[a,b,e]).
graph(b,[c,d]).
graph(d,[]).
I had this:
path(Origin, Dest, List) :- path(Origin, Dest, List, [Origin]).
path(X, X, List, Temp) :- reverse(Temp, List).
path(Origin, Dest, List, Temp) :- graph(Origin, Inter),
not(member(Inter, Temp)),
path(Inter, Dest, List, [Inter|Temp]).
and I know that problem is in graph(Origin, Inter), but I don't know how to tweak it so it can go inside the list, I've tried graph(Origin, [Inter|_]) but obviously it just checks the first one. Any help (even if it's not code) would be greatly appreciated.
Assuming directed graphs:
edge(X,Y) :- graph(X,Nodes), member(Y,Nodes).
I managed to solve it, in case someone else has the same problem:
node(X) :- graph(X,_).
allnodes(Nodes) :- setof(X, node(X), Nodes).
path(Origin,Dest,List) :- allnodes(X),
path(Origin, Dest, List1, X, X),
reverse(List1,List),!.
path(X,X,[X],_,_).
path(Origin,Dest,[Dest|List],[X|_],AN) :- graph(X, Inter),
member(Dest, Inter),
path(Origin,X,List,AN,AN).
path(Origin,Dest,List,[X|Y],AN) :- graph(X, Inter),
\+ member(Dest, Inter),
path(Origin,Dest,List,Y,AN).
Here's my solution that works on directed or undirected graphs, with or without cycles.
Using #larsmans suggestion you can make this work with adjacency-list like input.
edge(X,Y) :- graph(X,Nodes), member(Y,Nodes).
It also tries to find all paths, without revisiting.
c(1,2).
% ... c(X,Y) means X and Y are connected
d(X,Y):- c(X,Y).
d(X,Y):- c(Y,X).
% Use d instead of c to allow undirected graphs
findPathHelper(_, Begin, [], End):- d(Begin, End).
findPathHelper(Front, Begin, [Next|NMiddle], End):-
not(member(Begin,Front)),
d(Begin, Next),
append([Front,[Begin]], NFront),
findPathHelper(NFront, Next, NMiddle, End).
findPath(Start, End, Path):-
findPathHelper([], Start, Middle, End),
append([[Start],Middle,[End]], Path).

Resources