Iterating List in Prolog - prolog

I would like to iterate a list in Prolog an write a generated result into a new list.
With the predicate next_level_segments(List of Start-, Endcoordinates)
I would like to calculate four lists of four coordinates between each pair of Start-, and Endcoordinates and store this four lists in Ls.
This means when I call for example
next_level_segments([
[(10,0),(3.3,0)],
[(3.3,0),(0,-5.8)],
[(0,-5.8),(-3.3,0)],
[(-3.3,0),(-10,0)]
])
the predicate segments() should calculate the four next coordinates between
the pair of Start- and Endcoordinates for example [(10,0),(3.3,0)].
So next_level_segments should iterate through the list of Start and Endpoints, segments should do the calculation and the result of four list, with each four pairs of coordinates should be stored in the a resulting list.
When I call next_level_segments() with a list of four coordinates, the calculation is done and the coordinates are generated when i look at the trace, but aren't stored correctly.
As far as I can see it in the trace, the last list of four coordinates is missing.
Maybe somebody may have a look and have some advice what I'm doing wrong.
Thank you
segments([(Sx,Sy),(Ex,Ey)],Ls):-
X2 is Sx+(Ex-Sx)/3,
Y2 is Sy+(Ey-Sy)/3,
R1 is sqrt((X2-Sx)*(X2-Sx)+(Y2-Ey)*(Y2-Ey)),
Phi1 is atan((Y2-Sy)/(X2-Sx)),
X3 is X2 +R1*cos((Phi1-240)*pi/180),
Y3 is Y2 +R1*sin((Phi1+240)*pi/180),
X4 is X2+(X2-Sx),
Y4 is Y2+(Y2-Sy),
Ls=[
[(Sx,Sy),(X2,Y2)],
[(X2,Y2),(X3,Y3)],
[(X3,Y3),(X4,Y4)],
[(X4,Y4),(Ex,Ey)]].
next_level_segments([[(Sx,Sy),(Ex,Ey)]|E],[X|RLs]):-
segments([(Sx,Sy),(Ex,Ey)],X),
next_level_segments(E,RLs).
next_level_segments([],[]).

Your next_level_segments/2 needs only two clauses (instead of the three you are using). The first one should be:
next_level_segments([], []).
Both the first and the third clause you have at the moment should go because they don't do anything useful.
The recursive clause seems fine as it is at the moment.
Corrected like this, I get:
?- next_level_segments(
[[(10,0),(3.3,0)],
[(3.3,0),(0,-5.8)],
[(0,-5.8),(-3.3,0)],
[(-3.3,0),(-10,0)]
],
X).
X = [[[(10, 0), (7.766666666666667, 0)], [(7.766666666666667, 0), (6.649999999999999, -1.9341234017852458)], [(6.649999999999999, -1.9341234017852458), (5.533333333333333, 0)], [(5.533333333333333, 0), (3.3, 0)]],
[[(3.3, 0), (2.2, -1.9333333333333333)], [(2.2, -1.9333333333333333), (0.1262841490828066, -5.451200543142186)], [(0.1262841490828066, -5.451200543142186), (1.1000000000000005, -3.8666666666666667)], [(1.1000000000000005, -3.8666666666666667), (0, -5.8)]],
[[(0, -5.8), (-1.0999999999999999, -3.8666666666666663)], [(-1.0999999999999999, -3.8666666666666663), (-3.0456930398351094, -7.310619872034865)], [(-3.0456930398351094, -7.310619872034865), (-2.1999999999999997, -1.9333333333333327)], [(-2.1999999999999997, -1.9333333333333327), (-3.3, 0)]],
[[(-3.3, 0), (-5.533333333333333, 0)], [(-5.533333333333333, 0), (-6.65, -1.9341234017852458)], [(-6.65, -1.9341234017852458), (-7.766666666666667, 0)], [(-7.766666666666667, 0), (-10, 0)]]
].
Keep in mind that a trivial list iteration like this can also be written simply as:
maplist(segments, Input, Output)
In other words, apply segments/2 to each corresponding element in the two lists. You would have to redefine your segments/3 however to have two arguments instead of three, for example by re-writing the head to:
segments([(Sx,Sy),(Ex,Ey)], Ls)
(put the two first arguments in a list, as they are in your input list)
A small comment: a pair in Prolog is usually written as X-Y, not as (X, Y). Many standard library predicates represent "pairs" as X-Y, for example keysort/2, library(pairs) and so on. If you want to, you could also give your pair a descriptive name like pair(X,Y) or coordinates(X,Y). It doesn't really matter of only two elements, but a "tuple" with three elements like this: (X,Y,Z) is actually a nested term:
?- write_canonical((X,Y,Z)).
','(_,','(_,_))
true.
You get the same problem with X-Y-Z:
?- write_canonical(X-Y-Z).
-(-(_,_),_)
true.
At that point you could again use a term with a descriptive name, for example triple(X, Y, Z) or coordinates(X, Y, Z).

Related

for-loop in prolog doesn't work

I'm trying to do a for loop in Prolog which doesn't work. The program should do following:
generate(N,[S,E],FinalSegments):-
segments([S,E],Initialsegments),
iterate_level(N,Initialsegments,FinalSegments).
When I'm calling generate(5,[(10,0),(-10,0)]) the first step is, that generate(5,[(10,0),(-10,0)],FinalSegments) is being called and this predicate generates 4 coordinates between the Startpoint (10,0) and the Endpoint (-10,0), and store those four ccordinates in the listFinalSegments. This is actually done correctly. In the next step the predicate iterate_level(N,Initialsegments,FinalSegments) is being called.
The predicate iterate_level(), takes the four coordinates from the last step as a list called Initialsegments:
Initialsegments:([[ (10, 0), (3.333333333333333, 0)],
[ (3.3333, 0), (-3.5527e-15, -5.7735)],
[ (-3.5527e-15, -5.77350), (-3.3333, 0)],
[(-3.3333, 0), (-10, 0)]])
And now iterate_level(5,Initialsegments,FinalSegments) should be a for-loop which should generate 16 coordinates after the first iteration, then 64 coordinates after the second iteration...
But here is my problem that this is not really working and I don't know what I'm still doing wrong.
It seem to me, when I'm looking at the trace, that
iterate_level(N,Ls,F):-
seq(0,N,Index),
next_level_segments(Index,Ls,F).
when next_level_segments(Index,Ls,F) is called within the for-loop, the list
Ls which should contain four times more coordinates after each iteration is not refreshed.(Maybe this is the problem).
When I call generate(3,[[(60,0),(-60,0)]],X). I get four times always the same 16 coordinates as a result but I should get 1024 different coordinates.
Maybe someone may have some time to have a look at this problem an give me some help.
Thanks
This is my implementation until now:
generate(N,[S,E],FinalSegments):-
segments([S,E],Initialsegments),
iterate_level(N,Initialsegments,FinalSegments).
generate(N,[],[]).
seq(From,_,From).
seq(From,To,X) :-
From<To,
Next is From+1,
seq(Next,To,X).
iterate_level(N,Ls,F):-
seq(0,N,Index),
next_level_segments(Index,Ls,F).
%fail.
iterate_level(Ls,F).
iterate_level([],[]).
segments([(Sx,Sy),(Ex,Ey)],Ls):-
X2 is Sx+(Ex-Sx)/3,
Y2 is Sy+(Ey-Sy)/3,
R1 is sqrt((X2-Sx)*(X2-Sx)+(Y2-Ey)*(Y2-Ey)),
Phi1 is atan((Y2-Sy)/(X2-Sx)),
X3 is X2 +R1*cos((Phi1-240)*pi/180),
Y3 is Y2 +R1*sin((Phi1+240)*pi/180),
X4 is X2+(X2-Sx),
Y4 is Y2+(Y2-Sy),
Ls=[
[(Sx,Sy),(X2,Y2)],
[(X2,Y2),(X3,Y3)],
[(X3,Y3),(X4,Y4)],
[(X4,Y4),(Ex,Ey)]
].
next_level_segments(N,[[(Sx,Sy),(Ex,Ey)]|E],[X|RLs]):-
segments([(Sx,Sy),(Ex,Ey)],X),
next_level_segments(N,E,RLs).
next_level_segments(N,[],[]).
So, first of all, Prolog doesn't do for-loops in the traditional sense - what you actually want to do is recurse over the list with an accumulator. This can be achieved as follows.
Firstly, generate(0, [[X|Y]|Z], [[X|Y]|Z]) :- !., which says "if I am trying to generate the 0th iteration of a list of lists, I have achieved my goal and I should succeed". This also cuts, as there is only ever going to be a single solution here.
generate(N, [[P1, P2]|Tail], Final) does the main body of the (outer) recursion. As long as this is a positive iteration (ie exclude negatives), we do_generate an iteration of coordinates, and recurse for another iteration (with iteration 0 succeeding as above).
do_generate([],[]). states that if we're trying to generate coordinates between an empty list, we're done for this level.
do_generate([Current|Rest], Interim) takes the first pair of coordinates and generates the set of four pairs of coordinates (using segments([(Sx,Sy),(Ex,Ey)],Ls) as before), then recurses onto the rest of the list of coordinates. Once we reach the above base-case, we append all the lists together from last to first to get the new set of coordinates. This is then unified with Interim, to send back to generate(N, [[P1, P2]|Tail], Final) for further recursion or unification with Final using the outer base-case.
As a caveat, in order to get output looking like input for the final base-case, the input is now required to be a list of lists of coordinate-pairs, not just a list of coordinate-pairs.
All put together, you get the following:
generate(0, [[X|Y]|Z], [[X|Y]|Z]) :- !.
generate(N, [[P1, P2]|Tail], Final) :-
N > 0,
do_generate([[P1, P2]|Tail], Interim),
N1 is N-1,
generate(N1, Interim, Final).
do_generate([], []).
do_generate([Current|Rest], Interim) :-
segments(Current, Segs),
do_generate(Rest, RestSegs),
append(Segs, RestSegs, Interim).
segments([(Sx,Sy), (Ex,Ey)], Ls) :-
X2 is Sx+(Ex-Sx)/3,
Y2 is Sy+(Ey-Sy)/3,
R1 is sqrt((X2-Sx)*(X2-Sx)+(Y2-Ey)*(Y2-Ey)),
Phi1 is atan((Y2-Sy)/(X2-Sx)),
X3 is X2+R1*cos((Phi1-240)*pi/180),
Y3 is Y2+R1*sin((Phi1+240)*pi/180),
X4 is X2+(X2-Sx),
Y4 is Y2+(Y2-Sy),
Ls=[[(Sx,Sy),(X2,Y2)],
[(X2,Y2),(X3,Y3)],
[(X3,Y3),(X4,Y4)],
[(X4,Y4),(Ex,Ey)]].

How can I verify if a coordinate is in a list

I'm generating random coordinates and adding on my list, but first I need verify if that coordinate already exists. I'm trying to use member but when I was debugging I saw that isn't working:
My code is basically this:
% L is a list and Q is a count that define the number of coordinate
% X and Y are the coordinate members
% check if the coordniate already exists
% if exists, R is 0 and if not, R is 1
createCoordinates(L,Q) :-
random(1,10,X),
random(1,10,Y),
convertNumber(X,Z),
checkCoordinate([Z,Y],L,R),
(R is 0 -> print('member'), createCoordinates(L,Q); print('not member'),createCoordinates(L,Q-1).
checkCoordinate(C,L,R) :-
(member(C,L) -> R is 0; R is 1).
% transforms the number N in a letter L
convertNumber(N,L) :-
N is 1, L = 'A';
N is 2, L = 'B';
...
N is 10, L = 'J'.
%call createCoordinates
createCoordinates(L,20).
When I was debugging this was the output:
In this picture I'm in the firts interation and L is empty, so R should be 1 but always is 0, the coordinate always is part of the list.
I have the impression that the member clause is adding the coordinate at my list and does'nt make sense
First off, I would recommend breaking your problem down into smaller pieces. You should have a procedure for making a random coordinate:
random_coordinate([X,Y]) :-
random(1, 10, XN), convertNumber(XN, X),
random(1, 10, Y).
Second, your checkCoordinate/3 is converting Prolog's success/failure into an integer, which is just busy work for Prolog and not really improving life for you. memberchk/2 is completely sufficient to your task (member/2 would work too but is more powerful than necessary). The real problem here is not that member/2 didn't work, it's that you are trying to build up this list parameter on the way out, but you need it to exist on the way in to examine it.
We usually solve this kind of problem in Prolog by adding a third parameter and prepending values to the list on the way through. The base case then equates that list with the outbound list and we protect the whole thing with a lower-arity procedure. In other words, we do this:
random_coordinates(N, Coordinates) :- random_coordinates(N, [], Coordinates).
random_coordinates(0, Result, Result).
random_coordinates(N, CoordinatesSoFar, FinalResult) :- ...
Now that we have two things, memberchk/2 should work the way we need it to:
random_coordinates(N, CoordinatesSoFar, FinalResult) :-
N > 0, succ(N0, N), % count down, will need for recursive call
random_coordinate(Coord),
(memberchk(Coord, CoordinatesSoFar) ->
random_coordinates(N, CoordinatesSoFar, FinalResult)
;
random_coordinates(N0, [Coord|CoordinatesSoFar], FinalResult)
).
And this seems to do what we want:
?- random_coordinates(10, L), write(L), nl.
[[G,7],[G,3],[H,9],[H,8],[A,4],[G,1],[I,9],[H,6],[E,5],[G,8]]
?- random_coordinates(10, L), write(L), nl.
[[F,1],[I,8],[H,4],[I,1],[D,3],[I,6],[E,9],[D,1],[C,5],[F,8]]
Finally, I note you continue to use this syntax: N is 1, .... I caution you that this looks like an error to me because there is no distinction between this and N = 1, and your predicate could be stated somewhat tiresomely just with this:
convertNumber(1, 'A').
convertNumber(2, 'B').
...
My inclination would be to do it computationally with char_code/2 but this construction is actually probably better.
Another hint that you are doing something wrong is that the parameter L to createCoordinates/2 gets passed along in all cases and is not examined in any of them. In Prolog, we often have variables that appear to just be passed around meaninglessly, but they usually change positions or are used multiple times, as in random_coordinates(0, Result, Result); while nothing appears to be happening there, what's actually happening is plumbing: the built-up parameter becomes the result value. Nothing interesting is happening to the variable directly there, but it is being plumbed around. But nothing is happening at all to L in your code, except it is supposedly being checked for a new coordinate. But you're never actually appending anything to it, so there's no reason to expect that anything would wind up in L.
Edit Notice that #lambda.xy.x solves the problem in their answer by prepending the new coordinate in the head of the clause and examining the list only after the recursive call in the body, obviating the need for the second list parameter.
Edit 2 Also take a look at #lambda.xy.x's other solution as it has better time complexity as N approaches 100.
Since i had already written it, here is an alternative solution: The building block is gen_coord_notin/2 which guarantees a fresh solution C with regard to an exclusion list Excl.
gen_coord_notin(C, Excl) :-
random(1,10,X),
random(1,10,Y),
( memberchk(X-Y, Excl) ->
gen_coord_notin(C, Excl)
;
C = X-Y
).
The trick is that we only unify C with the new result, if it is fresh.
Then we only have to fold the generations into N iterations:
gen_coords([], 0).
gen_coords([X|Xs], N) :-
N > 0,
M is N - 1,
gen_coords(Xs, M),
gen_coord_notin(X, Xs).
Remark 1: since coordinates are always 2-tuples, a list representation invites unwanted errors (e.g. writing [X|Y] instead of [X,Y]). Traditionally, an infix operator like - is used to seperate tuples, but it's not any different than using coord(X,Y).
Remark 2: this predicate is inherently non-logical (i.e. calling gen_coords(X, 20) twice will result in different substitutions for X). You might use the meta-level predicates var/1, nonvar/1, ground/1, integer, etc. to guard against non-sensical calls like gen_coord(1-2, [1-1]).
Remark 3: it is also important that the conditional does not have multiple solutions (compare member(X,[A,B]) and memberchk(X,[A,B])). In general, this can be achieved by calling once/1 but there is a specialized predicate memberchk/2 which I used here.
I just realized that the performance of my other solutions is very bad for N close to 100. The reason is that with diminishing possible coordinates, the generate and test approach will take longer and longer. There's an alternative solution which generates all coordinates and picks N random ones:
all_pairs(Ls) :-
findall(X-Y, (between(1,10,X), between(1,10,Y)), Ls).
remove_index(X,[X|Xs],Xs,0).
remove_index(I,[X|Xs],[X|Rest],N) :-
N > 0,
M is N - 1,
remove_index(I,Xs,Rest,M).
n_from_pool(_Pool, [], 0).
n_from_pool(Pool, [C|Cs], N) :-
N > 0,
M is N - 1,
length(Pool, L),
random(0,L,R),
remove_index(C,Pool,NPool,R),
n_from_pool(NPool, Cs, M).
gen_coords2(Xs, N) :-
all_pairs(Pool),
n_from_pool(Pool, Xs, N).
Now the query
?- gen_coords2(Xs, 100).
Xs = [4-6, 5-6, 5-8, 9-6, 3-1, 1-3, 9-4, 6-1, ... - ...|...] ;
false.
succeeds as expected. The error message
?- gen_coords2(Xs, 101).
ERROR: random/1: Domain error: not_less_than_one' expected, found0'
when we try to generate more distinct elements than possible is not nice, but better than non-termination.

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.

Prolog, finding largest value from a setOf list

I have a predicate which purpose is to print out which country that has the biggest area(one with biggest border = biggest area). This is how my predicate looks like:
/* If I write get_country(X, 'Europe'). then all the countries in Europe
that isn't bordering a sea gets printed out.
However as you can see I am creating a list
with all of the countries and then I want to
take the largest country from all of these
and print that one out. But instead
all of the countries gets printed out
with their length, ex: X = hungary ; 359 (length) ... */
get_country(Country, Region):-
encompasses(Country,Region,_),
not(geo_sea(_,Country,_)),
setof(Length, country_circumference(Country,Length), Cs),
largest(Cs, X),
write(X).
The predicates used within that predicate follows:
country_circumference(Country, X):-
setof(Length, get_border_length(Country, Length), Cs),
sum(Cs, X).
largest([X],X).
largest([X|Xs],R) :-
largest(Xs,Y),
R is max(X,Y).
Can anyone tell me what I am doing wrong here? How do I simply get all of my countries into the list and then traverse through the list to find the one with the biggest border instead of just printing them out one after one as I put them into the list? Thanks in advance.
Prolog defines a natural order of terms. For example, the following are true:
foo(3, z) #< foo(10, x)
bar(2, 9) #< foo(3, 1)
Note the use of the term comparison operator #< versus the numeric comparison <. The predicate, setof/3, will do term comparison.
If you want to find the country that has the longest border, then you can do so by taking advantage of the term comparison and collect like terms in setof/3 that have the item you want to sort by as the first argument. In this case, we'd want the circumference first. In addition, if I'm understanding the intended meaning of your get_country predicate correctly, you need to include the queries that define the countries you want to consider as part of the query in the setof/3:
get_country(Country, Region):-
setof(L-C-R, X^Y^Z^( encompasses(C, R, X),
\+ geo_sea(Y, C, Z),
country_circumference(C, L) ), Cs),
reverse(Cs, HighToLowAreas),
member(_-Country-Region, HighToLowAreas), !.
The member/2 at the end of the predicate clause will find the first element in the list HighToLowAreas that matches _-Country-Region, which will be the first element if Country and Region are initially uninstantiated.
The existential quantifiers X^Y^Z^ are needed to exclude these from being selectors in the query. Using _ won't do that in the context of setof/3. Here, we're using the term form, -(-(X,Y),Z) since it's conveniently written, X-Y-Z. But you could just as well use, foo(X, Y, Z) here. The reverse/2 puts the list Cs in descending order, and we just pick off the Country and Region from the head of that list with, [_-Country-Region].

PROLOG: Check if first list contains 3 times less of each element than second list

I need to check if each element in second list has 3 times more instances then the same element in the first list. My function returns false all the time and I don't know what I'm dong wrong.
Here is the code:
fourth(_,[ ]).
fourth(A,[HF|TF]) :-
intersection(A, HF, NewA),
intersection(TF, HF, NewB),
append(HF, NewB, NewT),
append(NewA, NewA, NewAA),
append(NewA, NewAA, NewAAA),
length(NewAAA) == length(NewT),
select(HF, TF, NewTF),
fourth(A, NewTF).
Example:
?- fourth([1,2,3], [1,1,1]).
true.
?- fourth([1,2,3], [1,1,1,1]).
false.
?- fourth([1,2,3], [1,1]).
false.
?- fourth([1,2,2,3], [1,1,2,2,1,2,2,2,2]).
true.
I would make myself a select/3 predicate: select(X,From,Left), and then for each elt of a first list I'd call it three times with same first argument on a second list, progressively passing it forward, getting me a final Left3 without the three occurences of X; iand I'd do that for each elt of a first list. Then if I'd succeed and end up with an empty list, that means it had exactly three times each elt from the first list.
Your code seems needlessly complicated. It also contains bugs where you use HF instead of the list [HF].
So what's the logic you want to implement?:
take the next element from the second list (leaving the tail)
check if it's in the first list, and if it is, remove it (else fail)
remove it two more times from the tail of the second list
and this gives:
fourth(_,[ ]).
fourth(A,[HF|TF]) :-
once(select(HF, A, AR)), % using once/1 to avoid choicepoints
once(select(HF, TF, TF1)),
once(select(HF, TF1, TFR)),
fourth(AR, TFR).
Here is your code with suggestions on why it fails :
fourth(_,[]).
fourth(A,[HF|TF]) :-
intersection(A, HF, NewA),
intersection(TF, HF, NewB),
It's not intersection/3 that you want to use, for two reasons :
1) it doesn't filter only HF in A.
2) it fails if you call it with an element, so at least use [HF] instead
of HF
Instead, use include/3 : include(=(HF), A, NewA). See SWI-pl doc for more info.
append(HF, NewB, NewT),
append(NewA, NewA, NewAA),
append(NewA, NewAA, NewAAA),
Use of append/2 is better, especially for your NewAAA list.
length(NewAAA) == length(NewT),
You can't compare lengths like that. First, length/1 doesn't exist in
built-in swi-pl predicates. Instead, compare directly the lists or use
length/2 twice and then compare the results.
select(HF, TF, NewTF),
fourth(A, NewTF).
Only removing once HT in TF will cause your algorithm to fail. You need
to remove all the occurrences of HT in TF, with subtract/3 for example...
If you want a working solution respecting your original work, I'll add it, so feel free to ask, but as it was tagged homework I'll let you those working leads first...
% Blocks in our "block world"
%
% b3
% b4 b7
% b1 b5 b8
% b2 b6 b9
%==============
% Block Stacking
on(b1,b2).
on(b3,b4).
on(b4,b5).
on(b5,b6).
on(b7,b8).
on(b8,b9).
% Stack order
left(b2,b6).
left(b6,b9).
% Generalize "above"
above(Above,Below) :- on(Above,Below).
above(Above,Below) :- on(Above,AnyBlock), above(AnyBlock,Below).
% isLeft(X,Y) resolves to true if X is a block left of any block Y.
% isLeft/2 simply invokes leftOf/2 followed by a cut (!) to guarantee that
% only one result is generated.
%
% For Example: isleft(b1,b7) produces true
% isleft(b2,b6) produces true
% isleft(b4,b5) produces false.
% isleft(b9,b3) produces false.
isLeft(X,Y) :- leftOf(X,Y), !.
% Show an implementation of leftOf below. The implementation will involve a
% few cases (like the above predicate above), but can be completed using only the
% provided left and above predicates.

Resources