Some explanation about 8 queen solution that use permutation - prolog

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.

Related

Prolog - finding min element in list

I'm trying to find the minimum element in the list with comparing the squares. I did the following below:
min_elem([Min],Min).
min_elem([Head | Tail], Min) :-
min_elem(Tail, Tail_min),
Min is min(Head ^ 2, Tail_min ^ 2).
It actually worked with a few tests, but I noticed when tracing the following test:
Tracing example
So after it checks the square, it'll use the previous. I.e., when 8^2 goes to 64 and then it does 64^2. How can I prevent this? 🤔 Thanks!!!
If I understand you correctly, you want min_elem(XS,X) to be true iff X is the minimum of the squares in XS.
Based on this understanding, there are two problems:
In your base case, you are not taking the square.
In your recursive case, you are taking the square of the minimum of the squares in the tail.
To fix these problems, square the minimum in the base case and remove the square in the recursive case:
min_elem([X],Min) :- Min is X ^ 2.
min_elem([Head | Tail], Min) :-
min_elem(Tail, Tail_min),
Min is min(Head ^ 2, Tail_min).

Prolog - questions related to graph traversal

I'm fairly new to prolog and logic programming in general and took up this example to learn but I'm having a hard time with the solution. So, if someone can help me out or point me in the right direction, that would be really great.
The following is a list of predicates flight(city-a,city-b,airline,distance,time,cost) and country(city,state)
flight(london,dublin,aerlingus,500,45,150).
flight(rome,london,ba,1500,150,400).
flight(rome,paris,airfrance,1200,120,500).
flight(paris,dublin,airfrance,600,60,200).
flight(berlin,moscow,lufthansa,3000,300,900).
flight(paris,amsterdam,airfrance,400,30,100).
flight(berlin,dublin,lufthansa,1200,120,900).
flight(london,newyork,ba,5000,700,1100).
flight(dublin,newyork,aerlingus,4500,360,800).
flight(dublin,cork,ryanair,300,50,50).
flight(dublin,rome,ryanair,2000,150,70).
flight(dublin,chicago,aerlingus,5500,480,890).
flight(amsterdam,hongkong,klm,7000,660,750).
flight(london,hongkong,ba,7500,700,1000).
flight(dublin,amsterdam,ryanair,1000,90,60).
flight(moscow,newyork,aerflot,9000,720,1000).
flight(moscow,hongkong,aerflot,5500,420,500).
flight(newyork,chicago,aa,3000,240,430).
flight(dublin,london,aerlingus,500,45,150).
flight(london,rome,ba,1500,150,400).
flight(paris,rome,airfrance,1200,120,500).
flight(dublin,paris,airfrance,600,60,200).
flight(moscow,berlin,lufthansa,3000,300,900).
flight(amsterdam,paris,airfrance,400,30,100).
flight(dublin,berlin,lufthansa,1200,120,900).
flight(newyork,london,ba,5000,700,1100).
flight(newyork,dublin,aerlingus,4500,360,800).
flight(cork,dublin,ryanair,300,50,50).
flight(rome,dublin,ryanair,2000,150,70).
flight(chicago,dublin,aerlingus,5500,480,890).
flight(hongkong,amsterdam,klm,7000,660,750).
flight(hongkong,london,ba,7500,700,1000).
flight(amsterdam,dublin,ryanair,1000,90,60).
flight(newyork,moscow,aerflot,9000,720,1000).
flight(hongkong,moscow,aerflot,5500,420,500).
flight(chicago,newyork,aa,3000,240,430).
flight(dublin,sao_paulo,airfrance,10000,900,800).
flight(sao_paulo,newyork,airfrance,7000,840,650).
flight(rio,berlin,lufthansa,11000,1200,1100).
country(dublin,ireland).
country(cork,ireland).
country(london,uk).
country(rome,italy).
country(moscow,russia).
country(hongkong,china).
country(amsterdam,holland).
country(berlin,germany).
country(paris,france).
country(newyork,usa).
country(chicago,usa).
country(sao_paulo,brazil).
country(rio,brazil).
I need to design the following predicates -
1) trip(X,Y,T) where X and Y are two cities and T is the list of all cities connecting X and Y. eg. trip(rome,dublin,T) = [rome,london,dublin].
2) all_trip(X,Y,T) where X and Y are two cities and T is the list all possible solutions of predicate 1.
3) trip_dist(X,Y,[T,D]) where X and Y are two cities and W is a list [T|D] where the first element T is the trip from predicate 1 and D is the distance.
4) trip_cost(X,Y,[T,C]) same as predicate 3 but C is the total cost of the trip.

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.

Beginner Prolog issue

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))

Resources