Beginner Prolog issue - prolog

We have a box that contains red & yellow balls.
A man comes daily and gets 2 balls from the box, if he couldn't get 2 balls the game finishes.
There is a heap of red balls next to the box.
If the 2 balls which the man has withdrawn from the box were similar, he puts red ball into the box,
while if they were different, he puts yellow ball in the box.
We suppose that the box is represented like this
initialCan([y, r, y, r, y, r, y, r, y, r]).
y represents yellow ball, r represents red ball.
The man withdraws the 2 balls from the beginning of the list,
then he puts back 1 ball also to the beginning of the list.
So what is the procedure in Prolog which gives the color of the last ball in the box whatever
was the box containing at the beginning?

You might abstract your problem as a search in the space of possible states.
search(FinalState, FinalState):-
is_final(FinalState).
search(CurrentState, FinalState):-
transition(CurrentState, NextState),
search(NextState, FinalState).
solution(FinalState):-
initial_state(State0),
search(State0, FinalState).
So you jump from state to state until you reach the final one which becomes your solution. You need to do some things:
design a representation for a state (for example, a state might be a list like [r,y,r,...])
write a predicate initial_state(S0) which is satisfied if S0 is the initial state of the game
write a predicate transition(S1, S2) which is true if you can get from S1 to S2
write a predicate is_final(S) which is true if S is a final state

It is even easier to design the state as just box(Yellow_count, Red_count) and not bother with any particular list (after all, the balls are all identical, like electrons). Here is my try. I'm probably writing someone's homework here, but this is actually interesting.
Also consider checking out "Why correctness must be a mathematical concern" by Edsger W. Dijkstra, wherein this problem is described.
% last_ball(box(Yellow_initial_count, Red_initial_count), Last_ball_color, Time_at_end)
% ---------- TRIVIAL CASES ---------
% if there is only 1 yellow ball, the color is 'yellow' and we needed zero steps to reach this state
last_ball(box(1,0), yellow, 0).
% if there is only 1 red ball, the color is 'red' and we needed zero steps to reach this state
last_ball(box(0,1), red, 0).
% ---------- CASES DEFINING INDUCTION OVER Yellow+Red BALLS -----------
% take two yellow: check that this is possible for the given box,
% then find out what the last color is from the reduced counts, then define the number of steps to be higher by 1
last_ball(box(YI, RI), LBC, TAE) :- YI>=2, YIp is (YI-2), RIp is (RI+1), last_ball(box(YIp,RIp),LBC,TAEp), TAE is (TAEp+1).
% take two red: check that this is possible for the given box,
% then find out what the last color is from the reduced counts, then define the number of steps to be higher by 1
last_ball(box(YI, RI), LBC, TAE) :- RI>=2, YIp is YI, RIp is (RI-2+1), last_ball(box(YIp,RIp),LBC,TAEp), TAE is (TAEp+1).
% take a red and a yellow: check that this is possible for the given box,
% then find out what the last color is from the reduced counts, then define the number of steps to be higher by 1
last_ball(box(YI, RI), LBC, TAE) :- RI>=1, YI>=1, YIp is (YI-1+1), RIp is (RI-1), last_ball(box(YIp,RIp),LBC,TAEp), TAE is (TAEp+1).
% Now ask for example:
% ?- last_ball(box(2,1), C, T).
% ===================================
% This problem is of course Edsger W. Dijkstra's "balls in the urn" problem, and
% there is a very easy way to deduce the color without exhautsive check of the move tree, as Prolog does in the above.
% See: https://www.cs.utexas.edu/users/EWD/transcriptions/EWD07xx/EWD720.html
last_ball_ewd(box(YI, _), red) :- 0 is (YI mod 2).
last_ball_ewd(box(YI, _), yellow) :- 1 is (YI mod 2).
% We can test this by trying to find a counterexample of the result of last_ball_ewsd for the other color via '\+'
othercolor(red,yellow).
othercolor(yellow,red).
verify(box(YI, RI)) :- last_ball_ewd(box(YI, RI), LBC), othercolor(LBC,LBCO), \+last_ball(box(YI, RI), LBCO, _).
% Now ask for example:
% ?- verify(box(2, 1))

Related

knowledgment unification in prolog

What I have to do is to unify the possible options and solve the problem with these sentences
The Spaniard lives next to the red house.
The Norwegian lives in the blue house.
An Italian lives in the second house.
This is my attempt but I am getting an error, could someone please help me.
neighborhood(N):-
length(V,3),
next(house(_,spaniard), house(red,_), V),
member(house(blue,norway), V),
V = [_|house(_,italian)].
You may write a procedure that enforces each of your rules, and then let prolog find the possible ordering of houses that fulfill all those rules:
neiborhood(Houses):-
Houses=[House1, Italy, House3], % these are the houses, after rule 3
Italy=house(_ItalyColor, italy),
Spain=house(_SpainColor, spain),
% rule 2:
Norway=house(blue, norway),
member(House1-House3, [Spain-Norway, Norway-Spain]),
% rule 1:
append(_, [HouseA, HouseB|_], Houses),
(HouseA-HouseB=Spain-house(red, _) ; HouseB-HouseA=Spain-house(red, _)).
In this code I assumed when you said that the Spaniard lives next to the red house that it may live "to the left" or "to the right" of that house.
Also note that you only mention 2 house colors, so the third one gets unassigned color. Maybe you are missing another rule, possible which is the missing color.
Sample run:
?- neiborhood(Houses).
Houses = [house(_163550, spain), house(red, italy), house(blue, norway)] ;
Houses = [house(blue, norway), house(red, italy), house(_163550, spain)] ;
false.
In both solutions, the Spain house does not have any color assigned.

Sliding tile puzzle with varying tile size using logic programming

So I am trying to solve this Booth arrangement problem given here. It is basically a sliding tile puzzle where one (booth)tile has to reach a target spot and in the end all other (booths)tiles should be in their original location. Each tile/booth has a dimension and following are the input fact and relation descriptions:
One fact of the form room(W,H), which specifies the width W and
height H of the room (3 ≤ W, H ≤ 20).
One fact booths(B), which
specifies the number of booths (1 ≤ B ≤ 20).
A relation that consists
of facts of the form dimension(B, W, H), which specifies the width W
and height H of booth B.
A relation consisting of facts of the form
position(B, W, H), specifying the initial position (W, H) of booth B.
One fact target(B, W, H), specifying the destination (W, H) of the
target booth B.
An additional fact horizon(H) gives an upper bound on
the number of moves to be performed.
The program is supposed to read input facts from a file but I am just trying to do the solving so I have just copy pasted one possible input for now, and I have written some basic clauses:
room(3, 3).
booths(3).
dimension(1, 2, 1).
dimension(2, 2, 1).
dimension(3, 1, 1).
position(1, 0, 1).
position(2, 1, 2).
position(3, 0, 0).
target(3, 0, 2).
horizon(10).
xlim(X) :- room(X,_).
ylim(X) :- room(_,X).
sum(X,Y,Z) :- Z is X+Y .
do(position(B,X,Y),movedown,position(B,X,Z)) :- Y > 0 , sum(Y,-1,Z) .
do(position(B,X,Y),moveup,position(B,X,Z)) :- ylim(L), Y < L , sum(Y,1,Z) .
do(position(B,X,Y),moveleft,position(B,Z,Y)) :- X > 0 , sum(X,-1,Z) .
do(position(B,X,Y),moveright,position(B,Z,Y)) :- xlim(L), X < L, sum(X,1,Z) .
noverlap(B1,B2) :-
position(B1,X1,Y1),
position(B2,X2,Y2),
ends(Xe1,Ye1,B1),
ends(Xe2,Ye2,B2),
( Xe1 < X2 ;
Xe2 < X1 ;
Ye1 < Y2 ;
Ye2 < Y1 ).
ends(Xe,Ye,B) :-
dimension(B,W,H),
position(B,X,Y),
Xe is X+W-1,
Ye is Y+H-1.
between(X,Y,Z) :-
X > Y ,
X < Z .
validMove(M,B) :- do(position(B,X,Y),M,position(B,Xn,Yn)) .
I am new to Prolog and I am stuck on how to go from here, I have the no_overlap rule so I can test if a move is valid or not but I am not sure how with the current clauses that I have. My current clauses for moves do/3 probably needs some modification. Any pointers?.
You need to express the task in terms of relations between states of the puzzle. Your current clauses determine the validity of a single move, and can also generate possible moves.
However, that is not sufficient: You need to express more than just a single move and its effect on a single tile. You need to encode, in some way, the state of the whole puzzle, and also encode how a single move changes the state of the whole task.
For a start, I recommend you think about a relation like:
world0_move_world(W0, M, W) :- ...
and express the relation between a given "world" W0, a possible move M, and the resulting world W. This relation should be so general as to generate, on backtracking, each move M that is possible in W0. Ideally, it should even work if W0 is a free variable, and for this you may find clpfd useful: Constraints allow you to express arithmetic relations in a much more general way than you are currently using.
Once you have such a relation, the whole task is to find a sequence Ms of moves such that any initial world W0 is transformed to a desired state W.
Assuming you have implemented world0_move_world/3 as a building block, you can easily lift this to lists of moves as follows (using dcg):
moves(W0) --> { desired_world(W0) }.
moves(W0) --> [M], { world0_move_world(W0, M, W) }, moves(W).
You can then use iterative deepening to find a shortest sequence of moves that solves the puzzle:
?- length(Ms, _), initial_world(W0), phrase(moves(W0), Ms).

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.

Some explanation about 8 queen solution that use permutation

I am studyin Prolog for an universitary exam on SWI Prolog implementation.
I have some doubt about how work this version of 8 Queen problem that solve the problem using the permutations:
solution(Queens) :-
permutation([1,2,3,4,5,6,7,8], Queens),
safe(Queens).
permutation([],[]).
permutation([Head|Tail],PermList) :-
permutation(Tail,PermTail),
del(Head,PermList,PermTail).
del(Item,[Item|List],List).
del(Item,[First|List],[First|List1]) :-
del(Item,List,List1).
safe([]).
safe([Queen|Others]) :-
safe(Others),
noattack(Queen,Others,1).
noattack(_,[],_).
noattack(Y,[Y1|Ylist],Xdist) :-
Y1-Y=\=Xdist,
Y-Y1=\=Xdist,
Dist1 is Xdist + 1,
noattack(Y,Ylist,Dist1).
In a previous resolution I used this solution template: [1\Y1, 2\Y2, 3\Y3, 4\Y4, 5\Y5, 6\Y6, 7\Y7, 8\Y8] that simply say that every queen have to be on different rows the X calue could be constrained.
This version of the program it's pretty difference because we can observe that to prevent vertical attack all the queens have to be on different rows, so I have a queen for each row.
So without losing information so I can say that the solution will be a permutation of the list: [1,2,3,4,5,6,7,8] in wich every element rappresent the Y coordinate of a queen.
so in this case I am rappresenting a queen position only by its Y coordinate (its row index)
So I have the solution relation than say that a list Queens is a solution if Queens is a premutation of [1,2,3,4,5,6,7,8] original list and if this permutation is safe (every queen in this permutation list don't attack the others queen).
Ok, this is clear...now it is defined the safe relation.
There is a base case that say that if the list is empty then this is safe because there is no attack.
And there is a general case in wich the list is not empty. If the list is not empty I can divide it in [Queen|Others] where Queen is the first queen in the list and Others is the remaining sublist...so the original list [Queen|Others] is safe if the sublist Others it is itself a solution (if it is safe, if there is no attack in Others) and if the first item Queen do not attack the other queen in others sublist...
Ok...until now I think that it is clear for me...
Now I have some problems with the definition of noattack relation !!!
The problem is that I rappresent a queen position only by its Y coordinate and the X coordinate it is
not explicity present.
I have understand that for circumvent this limitation of the rappresentation there is the folowing generalizzation (I hope to have understood well...I am not so sure...): ** I know also that there must be a queen on each column of the board, so the X distance from the first queen in the list (Queen) and the sublist Others must be 1**
Where the distance from the first item Queen and the sublist Others is the X distance from the first item Queen and the queen nearest to it, is it righ my reasoning?
So the noattack relation is TRUE if the queen are on different columns (always true for construction) and I can express that have to be on different row sayng that the X distance from Queen and the nearest queen in the Others sublist is 1.
But, if my reasoning is truem I am finding many trouble trying to understand how rappresent this thing in this part of code:
noattack(Y,[Y1|Ylist],Xdist) :-
Y1-Y=\=Xdist,
Y-Y1=\=Xdist,
Dist1 is Xdist + 1,
noattack(Y,Ylist,Dist1).
i think your problem is only these 2 lines:
Y-Y1=/=Xdist,
Y1-Y=/=Xdist,
it checks whether the queen which has Y, attacks the queen in the row with a distance of Xdist in a diagonal way or not. (|Y - Y1| = Xdist --> diagonal attack ).
the other way to attack other queens is to qttack them in the same row, that doesn't happen simply because the solution is a permutation of [1,2,3,4,5,6,7,8]. so something like [1,1,3,4,5,6,7,8] never happens and thats enough to check diagonals.
I hope it solved the problem.
p.s. note that Y1 is the Y coordinate of the head of the Others from the rule Safe/1. so it is a queen with a Xdist of 1 at first, then it backtracks to other rows.
clarification
we are talking about noattack/3. you give it three arguments:
first: Y coordinate of current queen,
second: a right-most list [Y1| Ylist] the begins somewhere after where Y is in the list, and continues to the end of the primary list.(yes this is a sublist of the solution), and
third: Xdist is the index-distance between current queen (which has Y) and the queen which is gonna be checked with the current queen (which has Y1 and is the head of second argument).
third argument is necessary because without it we can not check diagonal interaction between the current queen and and the queen which has Y1. it is really basic mathematics, you have 2 points in the coordinate system with only natural numbers. lets say these 2 points attack each other in a diagonal way if and only-if abs(x1 - x2) = abs(y1 - y2).
Example #1 . and if you understood my explanations well, check it as Accepted.
P1 = (3, 4) and P2 = (1, 2) --> these points have a diagonal attack because abs(3-1) = abs(4-2) = 2
Example #2
P1 = (3, 4) and P2 = (7, 0) --> these points have a diagonal attack because abs(3-7) = abs(4-0) = 4
this is why we check both Y1-Y =\= Xdist and Y-Y1 =\= Xdist . because whenever there is a diagonal attack at least one of them is gonna be true. when non of them was true, it means that there is no diagonal attack between the queen with Y and the queen with Y1. so we can proceed to checking the next queen which is the head of Ylist.
I hope that's enough. this is a very easy problem, Just read it carefully and if you couldn't understand again try to trace the algorithm on a piece of paper yourself. that's a way always works.
I have the same confusion when solving the same problem in recursion using C. There are two possible directions for diagonal attacks. Number each square with x,y coordinates with top-left being 0,0. You will then see that these two attacking diagonal detection or calculation satisfies the conditions:
x1 - y1 == x2 - y2
x1 + y1 == x2 + y2
I annotated the comparison above in C equality notation and not Prolog notation. Between two points (x1,y1) and (x2,y2), there is queen diagonal attack if one of conditions above is meet.

Solve Cannibals/Missionaries using breadth-first search (BFS) in Prolog?

I am working on solving the classic Missionaries(M) and Cannibals(C) problem, the start state is 3 M and 3 C on the left bank and the goal state is 3M, 3C on the right bank. I have complete the basic function in my program and I need to implemet the search-strategy such as BFS and DFS.
Basically my code is learn from the Internet. So far I can successfuly run the program with DFS method, but I try to run with BFS it always return false. This is my very first SWI-Prolog program, I can not find where is the problem of my code.
Here is part of my code, hope you can help me find the problem of it
solve2 :-
bfs([[[3,3,left]]],[0,0,right],[[3,3,left]],Solution),
printSolution(Solution).
bfs([[[A,B,C]]],[A,B,C],_,[]).
bfs([[[A,B,C]|Visisted]|RestPaths],[D,E,F],Visisted,Moves) :-
findall([[I,J,K],[A,B,C]|Visited]),
(
move([A,B,C],[I,J,K],Description),
safe([I,J,K]),
not(member([I,J,K],Visited)
),
NewPaths
),
append(RestPaths,NewPaths,CurrentPaths),
bfs(CurrentPaths,[D,E,F],[[I,J,K]|Visisted],MoreMoves),
Moves = [ [[A,B,C],[I,J,K],Description] | MoreMoves ].
move([A,B,left],[A1,B,right],'One missionary cross river') :-
A > 0, A1 is A - 1.
% Go this state if left M > 0. New left M is M-1
.
.
.
.
.
safe([A,B,_]) :-
(B =< A ; A = 0),
A1 is 3-A, B1 is 3-B,
(B1 =< A1; A1 =0).
I use findall to find all possible path before go to next level. Only the one pass the safe() will be consider as possible next state. The state will not use if it already exist. Since my program can run with DFS so I think there is nothing wrong with move() and safe() predicate. My BFS predicate is changing base on my DFS code, but its not work.
There is a very simple way to turn a depth-first search program into a breadth-first one, provided the depth-first search is directly mapped to Prolog's search. This technique is called iterative deepening.
Simply add an additional argument to ensure that the search will only go N steps deep.
So a dfs-version:
dfs(State) :-
final(State).
dfs(State1) :-
state_transition(State1, State2),
dfs(State2).
Is transformed into a bfs by adding an argument for the depth. E.g. by using successor-arithmetics:
bfs(State, _) :-
final(State).
bfs(State1, s(X)) :-
state_transition(State1, State2),
bfs(State2, X).
A goal bfs(State,s(s(s(0)))) will now find all derivations requiring 3 or less steps. You still can perform dfs! Simply use bfs(State,X).
To find all derivations use natural_number(X), bfs(State,X).
Often it is useful to use a list instead of the s(X)-number. This list might contain all intermediary states or the particular transitions performed.
You might hesitate to use this technique, because it seems to recompute a lot of intermediary states ("repeatedly expanded states"). After all, first it searches all paths with one step, then, at most two steps, then, at most three steps... However, if your problem is a search problem, the branching factor here hidden within state_transition/2 will mitigate that overhead. To see this, consider a branching factor of 2: We only will have an overhead of a factor of two! Often, there are easy ways to regain that factor of two: E.g., by speeding up state_transition/2 or final/1.
But the biggest advantage is that it does not consume a lot of space - in contrast to naive dfs.
The Logtalk distribution includes an example, "searching", which implements a framework for state space searching:
https://github.com/LogtalkDotOrg/logtalk3/tree/master/examples/searching
The "classical" problems are included (farmer, missionaries and cannibals, puzzle 8, bridge, water jugs, etc). Some of the search algorithms are adapted (with permission) from Ivan Bratko's book "Prolog programming for artificial intelligence". The example also includes a performance monitor that can give you some basic stats on the performance of a search method (e.g. branching factors and number of state transitions). The framework is easy to extend, both for new problems and new search methods.
If anyone still interested in this for a python solution please find the following.
For the simplification, count of Missionaries and Cannibals on left is only taken to the consideration.
This is the solution tree.
#M #missionaries in left
#C #cannibals in left
# B=1left
# B=0right
def is_valid(state):
if(state[0]>3 or state[1]>3 or state[2]>1 or state[0]<0 or state[1]<0 or state[2]<0 or (0<state[0]<state[1]) or (0<(3-state[0])<(3-state[1]))):
return False
else:
return True
def generate_next_states(M,C,B):
moves = [[1, 0, 1], [0, 1, 1], [2, 0, 1], [0, 2, 1], [1, 1, 1]]
valid_states = []
for each in moves:
if(B==1):next_state = [x1 - x2 for (x1, x2) in zip([M, C, B], each)]
else:next_state = [x1 + x2 for (x1, x2) in zip([M, C, B], each)]
if (is_valid(next_state)):
# print(next_state)
valid_states.append(next_state)
return valid_states
solutions = []
def find_sol(M,C,B,visited):
if([M,C,B]==[0,0,0]):#everyne crossed successfully
# print("Solution reached, steps: ",visited+[[0,0,0]])
solutions.append(visited+[[0,0,0]])
return True
elif([M,C,B] in visited):#prevent looping
return False
else:
visited.append([M,C,B])
if(B==1):#boat is in left
for each_s in generate_next_states(M,C,B):
find_sol(each_s[0],each_s[1],each_s[2],visited[:])
else:#boat in in right
for each_s in generate_next_states(M,C,B):
find_sol(each_s[0],each_s[1],each_s[2],visited[:])
find_sol(3,3,1,[])
solutions.sort()
for each_sol in solutions:
print(each_sol)
Please refer to this gist to see a possible solution, maybe helpful to your problem.
Gist: solve Missionaries and cannibals in Prolog
I've solved with depth-first and then with breadth-first, attempting to clearly separate the reusable part from the state search algorithm:
miss_cann_dfs :-
initial(I),
solve_dfs(I, [I], Path),
maplist(writeln, Path), nl.
solve_dfs(S, RPath, Path) :-
final(S),
reverse(RPath, Path).
solve_dfs(S, SoFar, Path) :-
move(S, T),
\+ memberchk(T, SoFar),
solve_dfs(T, [T|SoFar], Path).
miss_cann_bfs :-
initial(I),
solve_bfs([[I]], Path),
maplist(writeln, Path), nl.
solve_bfs(Paths, Path) :-
extend(Paths, Extended),
( member(RPath, Extended),
RPath = [H|_],
final(H),
reverse(RPath, Path)
; solve_bfs(Extended, Path)
).
extend(Paths, Extended) :-
findall([Q,H|R],
( member([H|R], Paths),
move(H, Q),
\+ member(Q, R)
), Extended),
Extended \= [].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% problem representation
% independent from search method
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
initial((3,3, >, 0,0)).
final((0,0, <, 3,3)).
% apply a *valid* move
move((M1i,C1i, Bi, M2i,C2i), (M1f,C1f, Bf, M2f,C2f)) :-
direction(Bi, F1, F2, Bf),
who_move(MM, CM),
M1f is M1i + MM * F1, M1f >= 0,
C1f is C1i + CM * F1, C1f >= 0,
( M1f >= C1f ; M1f == 0 ),
M2f is M2i + MM * F2, M2f >= 0,
C2f is C2i + CM * F2, C2f >= 0,
( M2f >= C2f ; M2f == 0 ).
direction(>, -1, +1, <).
direction(<, +1, -1, >).
% valid placements on boat
who_move(M, C) :-
M = 2, C = 0 ;
M = 1, C = 0 ;
M = 1, C = 1 ;
M = 0, C = 2 ;
M = 0, C = 1 .
I suggest you to structure your code in a similar way, with a predicate similar to extend/2, that make clear when to stop the search.
If your Prolog system has a forward chainer you can also solve
the problem by modelling it via forward chaining rules. Here
is an example how to solve a water jug problem in Jekejeke Minlog.
The state is represented by a predicate state/2.
You first give a rule that filters duplicates as follows. The
rule says that an incoming state/2 fact should be removed,
if it is already in the forward store:
% avoid duplicate state
unit &:- &- state(X,Y) && state(X,Y), !.
Then you give rules that state that search need not be continued
when a final state is reached. In the present example we check
that one of the vessels contains 1 liter of water:
% halt for final states
unit &:- state(_,1), !.
unit &:- state(1,_), !.
As a next step one models the state transitions as forward chaining
rules. This is straight forward. We model emptying, filling and pouring
of vessels:
% emptying a vessel
state(0,X) &:- state(_,X).
state(X,0) &:- state(X,_).
% filling a vessel
state(5,X) &:- state(_,X).
state(X,7) &:- state(X,_).
% pouring water from one vessel to the other vessel
state(Z,T) &:- state(X,Y), Z is min(5,X+Y), T is max(0,X+Y-5).
state(T,Z) &:- state(X,Y), Z is min(7,X+Y), T is max(0,X+Y-7).
We can now use the forward chaining engine to do the job for us. It
will not do iterative deeping and it will also not do breadth first.
It will just do unit resolution by a strategy that is greedy for the
given fact and the process only completes, since the state space
is finite. Here is the result:
?- post(state(0,0)), posted.
state(0, 0).
state(5, 0).
state(5, 7).
state(0, 7).
Etc..
The approach will tell you whether there is a solution, but not explain
the solution. One approach to make it explainable is to use a fact
state/4 instead of a fact state/2. The last two arguments are used for
a list of actions and for the length of the list.
The rule that avoids duplicates is then changed for a rule that picks
the smallest solution. It reads as follows:
% choose shorter path
unit &:- &- state(X,Y,_,N) && state(X,Y,_,M), M<N, !.
unit &:- state(X,Y,_,N) && &- state(X,Y,_,M), N<M.
We then get:
?- post(state(0,0,[],0)), posted.
state(0, 0, [], 0).
state(5, 0, [fl], 1).
state(5, 7, [fr,fl], 2).
state(0, 5, [plr,fl], 2).
Etc..
With a little helper predicate we can force an explanation of
the actions that lead to a path:
?- post(state(0,0,[],0)), state(1,7,L,_), explain(L).
0-0
fill left vessel
5-0
pour left vessel into right vessel
0-5
fill left vessel
5-5
pour left vessel into right vessel
3-7
empty right vessel
3-0
pour left vessel into right vessel
0-3
fill left vessel
5-3
pour left vessel into right vessel
1-7
Bye
Source Code: Water Jug State
http://www.xlog.ch/jekejeke/forward/jugs3.p
Source Code: Water Jug State and Path
http://www.xlog.ch/jekejeke/forward/jugs3path.p

Resources