Find the exit to the labyrinth - prolog

I have to find the exit path to this labyrinth.
The labyrinth must be represented with connect events eg connect(1,7), connect(2,8) etc.
The output path must be a list with start on the left edge and finish on the right edge.
I have written the following code:
connect(start,2).
connect(1, 7).
connect(7, 13).
connect(13, 14).
connect(14,15).
connect(15,21).
connect(14,20).
connect(20,26).
connect(26,27).
connect(27,28).
connect(28,29).
connect(23,29).
connect(17,23).
connect(11,17).
connect(5,11).
connect(5,6).
connect(19,25).
connect(25,31).
connect(31,32).
connect(32,33).
connect(33,34).
connect(34,35).
connect(35,36).
connect(12, 18).
connect(18, 24).
connect(24,30).
connect(30,36).
connect(2, 8).
connect(2,3).
connect(3,4).
connect(8,9).
connect(3, 9).
connect(4,10).
connect(10,16).
connect(16, 22).
connect(21, 22).
connect(32,finish).
I have stuck to the commands needed for finding the path.

Let's start from a smaller one.
We represent it as
connect(2,8).
connect(3,2).
connect(3,exit).
connect(3,9).
connect(8,9).
cango(A,B) :- connect(A,B).
cango(A,B) :- connect(B,A).
And program it as simply as possible,
path( Start, [Start | Path]) :-
Start = exit, Path = [].
path( Start, [Start | Path]) :-
cango( Start, Next),
path( Next, Path).
and that's it. And it even works,
3 ?- path(2,P).
P = [2, 3, exit] ;
P = [2, 3, exit, 3, exit] ;
P = [2, 3, exit, 3, exit, 3, exit] ;
P = [2, 3, exit, 3, exit, 3, exit, 3, exit] .
Wait, no, it doesn't. It gets stuck, with the above facts as shown, and doesn't even produce the first possible path, let alone avoiding this unwelcome repetitiveness.
But it did, when I tried it with a different set of connect facts -- and then I made a change, but a very small one, that broke this program. Yet the above set of connect facts does correctly describe the labyrinth...
All you need to do to make it work again is swap the arguments to one connect fact above. Try it. Does it produce any results now? Does it produce the same Path result as the one shown above, when we call it as path(2,Path)?
Then try swapping the order of the connect facts to get the same Path as shown above.
Then change the program so that it is impervious to such small differences in representation, and works for any set of facts that correctly describe the situation, not just such that was made specifically so the above simple program doesn't get stuck.
Then / or, change it so it produces all possible paths in order of their length.
Then change it so it produces the shortest path.
There, a whole learning program / path ahead of you.

Related

Replace every instance of a list by another ONE by ONE in Prolog

So I have a program that is supposed to replace every instance of an element in a list with another one but ONE BY ONE.
E.g.
change_element(5,[1,5,9,12,5,6],3,X). should give
X = [1,3,9,12,5,6] and
X = [1,5,9,12,3,6]
So it's replacing first 5 with 3, then in the second output, the first 5 remains 5 and the second changes to 3.
I was able to implement the code to change the first element but the code terminates after that. Doesn't goes to the second element.
change_element(A,[A|As],B,[B|As]).
change_element(A,[E|As],B,[E|Bs]):-
dif(A, E),
change_element(A,As,B,Bs).
Any idea, what should I do differently to get the desired result?
just go on after a match, preserving the old element:
change_element(A,[A|As],B,[B|As]).
change_element(A,[A|As],B,[A|Bs]):-
change_element(A,As,B,Bs).
change_element(A,[E|As],B,[E|Bs]):-
dif(A, E),
change_element(A,As,B,Bs).

Creating list of all elements fullfilling relation in prolog

I have a relation grandpa(X,Y) and I'm trying to get list of all grandpa's in the known world without using forall, findall and similar methods
My attempt so far is:
find_grandpas(Tmp,List):-
grandpa(New,_),
not(member(New,Tmp)),
find_grandpas([New|Tmp],List).
list_grandpas(List) :- find_grandpas([], List), print_list(List).
while checking stepswith trace I can see, that correct list is evaluated, but later it is lost. How can I construct some "cut" condition?
The problem here is that you build the right list but you need to tell where to stop. For example if we have as facts:
grandpa(a,_).
grandpa(b,_).
grandpa(c,_).
Eventually you will build list [a, b, c] and recursively try to find another solution there calling in the next iteration:
grandpa(New,_) will produce a but due to not(member(New,Tmp))this will fail, via backtracking it will try again with b... and c wher also fails. Then no choice points left and it completely fails. Soyou need to change to:
find_grandpas(Tmp,List):-
(
grandpa(New,_),
not(member(New,Tmp)) ->
find_grandpas([New|Tmp],List); List = Tmp
).
This simply says try grandpa(New,_),not(member(New,Tmp)) if succeed I have something to add, add it and go on in recursion. If not then no more solutions so set List = Tmp and this succeeds returning the right list.
Example:
?- find_grandpas([],L).
L = [c, b, a].

Filtering elements of a list in Prolog

In my project I need to build a list of possible moves. I've already done that, but I need to filter the possible moves from previous moves. How can I do that?
From:
PossibleMoves = [(up,1,2),(down,2,4),(left,1,3)],
PreviousMoves = [(up,1,2),(down,2,4)].
To:
PossibleMovesLeft = [(left,1,3)].
I tried delete, \+ memberchk, without success. Maybe I did something wrong.
This question is not really related to mazes, it's just about removing all elements in a list from another list. There's a predicate for that: subtract/3.
subtract(+Set, +Delete, -Result)
Delete all elements in Delete from Set. Deletion is based on unification using memberchk/2.
Example usage:
?- subtract([1,2,5,4,3,5,4], [6,2,4], X).
X = [1, 5, 3, 5]
But if needed, it's really easy to roll your own version.

gprolog: Getting a stacktrace after an exception

While using gprolog I often have exceptions without any kind of line numbers or context like this one:
uncaught exception: error(instantiation_error,(is)/2)
Without any kind of context. I know I can do a trace but it would take very long to debug it with trace since I need to execute a lot of things before getting to the place where the error occur.
Any idea on how to have this stacktrace ? Or a dynamic trace / notrace ?
EDIT: Or just automate the printing of the whole trace output.
#gusbro's answer (s(X)) shows you how you somewhat solve this with GNU's debugger. However, if you cannot afford to see all the printing going on, or it is much too slow, you might consider the following "debugger" available as library(debug) in Scryer.
I personally do not use debuggers offered by Prolog systems for the simple reason that most of them print much too much, are often buggy themselves, and have their own specific ever changing conventions, I can't afford to learn.
:- op(900, fx, [#,$,$-]).
$-(G_0) :-
catch(G_0, Ex, ( portray_clause(exception:Ex:G_0), throw(Ex) ) ).
$(G_0) :-
portray_clause(call:G_0),
$-G_0,
portray_clause(exit:G_0).
#(G_0) :-
( $-G_0
*-> true
; portray_clause(badfail:G_0),
throw(goal_failed(G_0))
).
:- op(950, fy, *).
*(_).
To use it, simply add $-, $, or # in front of a specific goal.
$- means: only signal exceptions going through this goal
$ additionally show call and exit
# assures that there is at least one answer, and if not, it is reported and an exception is thrown.
Use above annotations sparingly!
* removes the goal. This is for generalizing a program doing program modification/program-slicing in a pure monotonic program. You need this in case of unexpected failures. For examples how to use it, see the following answers/debugging sessions
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13.
More.
_/*term*/ replaces a term by an anonymous variable. This generalizes a program even further than * alone. Example sessions:
1,
2,
3,
4,
5,
6,
7,
8,
9,
10.
In this manner you can reduce the information you watch significantly.
In other systems supporting meta_predicate directives like SICStus, YAP and SWI, add in front the following directive:
:- meta_predicate(( $-(0), $(0), #(0) )).
You may trace/0 and leash/1 only the exception port, e.g:
?- trace.
?- leash([exception]).
Then you run your program and it will print a trace on screen but only stop when an exception occurs. There you can see the "stack trace" (ancestors) by pressing letter g.

prolog, copying lists

I am attempting to get my arms around some basic prolog but struggling a bit in the process. In specific - I am trying to get through a list of items and copy it, item by item into a new list. I can get it to reverse, but I am finding it trickier doing it without reversing.
Ive been trying the following -
copy(L,R) :- accCp(L,R).
accCp([],R).
accCp([H|T],R) :- accCp(T,H).
When i run a trace on this - i can see the individual items being copied across, but they get 'lost', and dont form a growing list (at R, as i was hoping). How could i achivie this?
Many thanks
Your base case needs to set the copy list to empty when the original list is empty. Then, the recursive case needs to take H from list L and add it to the head of list R:
copy(L,R) :- accCp(L,R).
accCp([],[]).
accCp([H|T1],[H|T2]) :- accCp(T1,T2).
When you call copy, it works its way down to the base case, where it sets R to an empty list. Then, as it works back up, it keeps appending the head H of known list [H|T1] to the beginning of variable list [H|T2]. It does that until the original case is reached, at which point R contains a full copy of L.
Very simple approach would be:
clone1(X,X).
?-clone1([1,2,3],Z).
Z=[1,2,3]
Here's an expressive approach for the list handling. You want to copy or clone a list. My approach is add every element from the list to want to copy to another list and return another list.
clone([],[]).
clone([H|T],[H|Z]):- clone(T,Z).
OUTPUT
?- clone([1,2,3,4,5],Z).
Z=[1,2,3,4,5]
?- clone([a,b,c,d],Z).
Z=[a,b,c,d]
?- clone([ [a,1,2] , [b,2,3] , [c,3,4] ],Z).
Z = [[a, 1, 2], [b, 2, 3], [c, 3, 4]]
This works for every kind of list.

Resources