Applying Effects on A State List - prolog

I want to apply a list of effects in a current state in other words, have a list of effects generated by an action if the current state has a condition that corresponds to the denial of a effect that condition will be removed.
If i have the current state:
[clear(b),on(b,a),on(a,mesa),clear(d),on(d,c),on(c,desk)]
And the list of effects :
[-clear(d), -on(d.c), on(c,d)]
The result would be :
[clear(b),on(b,a),on(a,mesa), on(c,d), on(c,desk)]
This is what i got right now, any help would be appreciated!
applyEffects(currentState,Effects,result)
insert(Element, List,result)
remove(Element,List, result)
applyEffects([],L,L).
applyEffects(L,[],L).
applyEffects([X|XTail], [-X|YTail], A) :-
insert(X, A, B),
applyEffects([X|XTail],YTail, B).
insert(E, L1, [E|L1]).
remove(X, [X|L1], L1).
remove(X, [Y|L1], A):- remove(X,L1,[L1|Y]).

Your insert and remove should both be select (which is often built-in).
You might want to distinguish, if you have a "negative" argument or not:
applyEffects(L,[],L).
applyEffects(L,[-X|R],A):-
!,
applyEffects(L,R,Y),
select(X,Y,A).
applyEffects(L,[X|R],[X|Y]):-
applyEffects(L,R,Y).
The cut used in the second clause is a red cut, to make it green, add a \+ X = - _ line to the third clause.
if you want to allow non-existing negatives, change the second clause to this:
applyEffects(L,[-X|R],A):-
!,
applyEffects(L,R,Y),
(select(X,Y,A),!;
Y = A).
Now applyEffects([],[-on(something)],X) doesn't fail.

Related

Count the number of terms that are not atoms in a nested list

I have these facts:
vehicle(car,blue,[wheel,horn,optional(radio)]).
vehicle(motorcycle,blue,[wheel,optional(navigation),horn]).
vehicle(truck,white,[wheel,horn,optional(trailer)]).
I want to count all optional items (all "optional") of all blue vehicles - in this case 2.
Right now I have a predicate that creates a nested list with the component lists of all blue vehicles:
countAllOptionalComponents:-
findall(X,vehicle(_,blue,X),S),
write(S).
[ [wheel,horn,optional(radio)], [wheel,optional(navigation),horn] ]
My idea was to pass this nested list to another predicate to count all optional components of all "sub-lists", but I'm having trouble. Something like this:
countAllOptionalComponents:-
findall(X,vehicle(_,blue,X),S),
countOptComponents(S,N).
countOptComponents([],0).
countOptComponents([X,Y],N):-
[...]
Maybe the approach I'm following doesn't make much sense.
If you are already using findall() and you know that there can be more than one goal in the middle of findall by wrapping it in () then you can put another findall in there:
countAllOptionalComponents(OptionCount) :-
findall(CarOptions,
(vehicle(_, blue, CarAllItems),
findall(O, member(optional(O), CarAllItems), CarOptions)
), AllOptionsNested),
append(AllOptionsNested, AllOptions),
write(AllOptions),
length(AllOptions, OptionCount).
append/2 flattens nested lists, append([[horn], [radio,aircon]], [horn,radio,aircon]).
One possible solution would be the following:
count(C) :-
findall(X, vehicle(_, blue, X), Ls),
countOpt(Ls, 0, C).
countOpt([], X, X) :- !.
countOpt([H|T], C, NewC) :-
countOpt(T, C, NewC1),
findall(Opt, member(optional(Opt), H), Opts),
printOpts(Opts),
length(Opts, Length),
NewC is NewC1 + Length, !.
printOpts([]).
printOpts([H|T]) :-
print(H),
nl,
printOpts(T).
As in your approach, first gather all lists of features (I guess?) for each vehicle and save it in a List of lists called Ls.
Then select in each sublist of Ls all Optional values (Opt) and add all the lengths of them.
I also added the predicate to print the results.

How to tell prolog if the function returns false then skip it?(15 puzzle game)

I have made a function which in it I call several functions, but when one of them returns false the main function stops and returns false. So is there a way to tell Prolog if the function returns false then skip it and check the rest?
In detail: I am trying to make the 15 puzzle game as a project,
and I want to make function that gives me all the possible next moves.
I end up with calling all the previous functions that controls the blank tile.
next_move(Board, Moves):-
swapup(Board,Result),
swapdown(Board,Result),
swapright(Board,Result),
swapleft(Board,Result).
I want this function to return all the next possible moves
Here is the full code:
position([Tile|_], Tile, 0).
position([_|Tail], Tile, Index):-
position(Tail, Tile, Index1),
Index is Index1+1.
swap(Board,I,J,R) :-
same_length(Board,R),
append(BeforeI,[AtI|PastI],Board),
append(BeforeI,[AtJ|PastI],Bs),
append(BeforeJ,[AtJ|PastJ],Bs),
append(BeforeJ,[AtI|PastJ],R),
length(BeforeI,I),
length(BeforeJ,J).
swapup(Board,Result):-
position(Board,0,Index),
Index \=0,
Index \=1,
Index \=2,
Index \=3,
Up is Index-4,
swap(Board,Up,Index,Result).
swapdown(Board,Result):-
position([],0,Index),
Index \=12,
Index \=13,
Index \=14,
Index \=15,
Down is Index+4,
swap(Board, Down, Index, Result).
swapright(Board,Result):-
position([],0,Index),
Index \=3,
Index \=7,
Index \=11,
Index \=15,
Right is Index+1,
swap(Board, Right, Index, Result).
swapleft(Board,Result):-
position([],0,Index),
Index \=0,
Index \=4,
Index \=8,
Index \=12,
Left is Index-1,
swap(Board, Left, Index, Result).
swap(Board,Result) :- swapup(Board,Result).
swap(Board,Result) :- swapdown(Board,Result).
swap(Board,Result) :- swapright(Board,Result).
swap(Board,Result) :- swapleft(Board,Result).
next_move(Board,Moves) :- findall(Result,swap(Board,Result),Moves).
Here's a simple program:
a.
b :- fail.
c.
g :- a, b, c.
I can ask if g succeeds:
?- g.
false.
It does not.
I can solve this two ways.
(1)
g :- a, b, c.
g :- a, c.
(2)
g :- a, (b; true), c.
Either way, g succeeds now:
?- g.
true.
Update
This is the code you've posted:
next_move(Board, Moves) :-
swapup(Board,Result),
swapdown(Board,Result),
swapright(Board,Result),
swapleft(Board,Result).
On the LHS you have a variable Moves that is not on the RHS. Moves can never be unified and will always remain a variable.
Let's ignore that for a minute and look at the swap predicates.
If I assume that Result is a valid move given the current state of the Board then what your code is saying next_move(Board, Moves) succeeds when each of the swap predicates succeed and that can't happen unless the move you get from each of the swap predicates is the same.
Once swapup(Board,Result) succeeds it will have unified Result with the "swap up" move. Then you ask if swapdown(Board,Result) succeeds. Well, Result isn't a variable anymore so you're asking if the Result you get from swapdown is the same as the Result you get from swapup. I'm guessing it's not.
It's possible that you need something like this:
next_move(Board,[U,D,R,L]):-
swapup(Board,U),
swapdown(Board,D),
swapright(Board,R),
swapleft(Board,L).
But that's not clear because I don't know what value you get when your open space on your board is already at an edge.
It's probably more likely that you need this:
swap(Board,Result) :- swapup(Board,Result).
swap(Board,Result) :- swadown(Board,Result).
swap(Board,Result) :- swapright(Board,Result).
swap(Board,Result) :- swapleft(Board,Result).
next_move(Board,Moves) :- findall(Result,swap(Board,Result),Moves).
But all of this is guessing without seeing your full code.
Here's your code working now. There were a number of issues.
position/3 just simply didn't work.
Here's a version that does:
position(List,Element,Index) :-
position(List,Element,0,Index).
position([Element|_],Element,Index,Index).
position([_|Tail],Element,Counter,Index) :-
Next is Counter + 1,
position(Tail,Element,Next,Index).
You were always calling swap/4 with the same order of the two indices. You have to make sure they go in in ascending order. swap/4 didn't work in any case. Here's the new version:
swap(BoardIn,I,J,BoardOut) :-
position(BoardIn,X,I), % find the value `X` at position `I`
position(BoardIn,Y,J), % find the value `Y` at position `J`
append(Left,[X|MiddleEnd1],BoardIn), % find the list that is `Left` of `X`
append(Middle,[Y|End],MiddleEnd1), % find the `Middle` that is left of `Y` and the list `End` that is to the right of `Y`
append(Middle,[X|End],MiddleEnd2), % put `X` between `Middle` and `End`.
append(Left,[Y|MiddleEnd2],BoardOut). % put the `Y` between `Left` & `Middle`.
I cleaned up the swap*/2 predicates.
swapup(BoardIn,BoardOut):-
position(BoardIn,0,Index),
Up is Index - 4,
Up >= 0,
swap(BoardIn,Up,Index,BoardOut).
swapdown(BoardIn,BoardOut):-
position(BoardIn,0,Index),
Down is Index + 4,
Down =< 15,
swap(BoardIn,Index,Down,BoardOut).
swapright(BoardIn,BoardOut):-
position(BoardIn,0,Index),
Index mod 4 =\= 3,
Right is Index + 1,
swap(BoardIn,Index,Right,BoardOut).
swapleft(BoardIn,BoardOut):-
position(BoardIn,0,Index),
Index mod 4 =\= 0,
Left is Index - 1,
swap(BoardIn,Left,Index,BoardOut).
swap(BoardIn,BoardOut) :- swapup(BoardIn,BoardOut).
swap(BoardIn,BoardOut) :- swapdown(BoardIn,BoardOut).
swap(BoardIn,BoardOut) :- swapright(BoardIn,BoardOut).
swap(BoardIn,BoardOut) :- swapleft(BoardIn,BoardOut).
And finally, here's the next_move/2 predicate:
next_move(BoardIn,Moves) :-
length(BoardIn,16),
position(BoardIn,0,_),
findall(BoardOut,swap(BoardIn,BoardOut),Moves).
Now I can call this query:
?- next_move([1,0,2,3,4,5,6,7,8,9,10,11,12,13,14,15],Result),write(Result).
I get this result:
[[1,5,2,3,4,0,6,7,8,9,10,11,12,13,14,15],[1,2,0,3,4,5,6,7,8,9,10,11,12,13,14,15],[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]]

Prolog notBetween function

I need some help here with Prolog.
So I have this function between that evaluates if an element is between other two.
What I need now is a function that evaluates if a member is not between other two, even if it is the same as one of them.
I tried it :
notBetween(X,Y,Z,List):-right(X,Y,List),right(Z,Y,List). // right means Z is right to Y and left the same for the left
notBetween(X,Y,Z,List):-left(X,Y,List),left(Z,Y,List).
notBetween(X,Y,Z,List):-Y is Z;Y is X.
I am starting with Prolog so maybe it is not even close to work, so I would appreciate some help!
When it come to negation, Prolog behaviour must be handled more carefully, because negation is 'embedded' in the proof engine (see SLD resolution to know a little more about abstract Prolog). In your case, you are listing 3 alternatives, then if one will not be true, Prolog will try the next. It's the opposite of what you need.
There is an operator (\+)/2, read not. The name has been chosen 'on purpose' different than not, to remember us that it's a bit different from the not we use so easily during speaking.
But in this case it will do the trick:
notBeetwen(X,Y,Z,List) :- \+ between(X,Y,Z,List).
Of course, to a Prolog programmer, will be clearer the direct use of \+, instead of a predicate that 'hides' it - and requires inspection.
A possibile definition of between/4 with basic lists builtins
between(X,Y,Z,List) :- append(_, [X,Y,Z|_], List) ; append(_, [Z,Y,X|_], List).
EDIT: a simpler, constructive definition (minimal?) could be:
notBetween(X,Y,Z, List) :-
nth1(A, List, X),
nth1(B, List, Y),
nth1(C, List, Z),
( B < A, B < C ; B > A, B > C ), !.
EDIT: (==)/2 works with lists, without side effects (it doesn't instance variables). Example
1 ?- [1,2,3] == [1,2,3].
true.
2 ?- [1,2,X] == [1,2,X].
true.
3 ?- [1,2,Y] == [1,2,X].
false.

Prolog - how to understand lists

I don't know much, how to understand that fact p([H|T], H, T). I know C/C++/Java etc.. but this looks diferrent. So when i pass first argument to "function" p, it separates it into H and T and makes it accessible through this vars? I don't know how to logically understand this.
http://www.doc.gold.ac.uk/~mas02gw/prolog_tutorial/prologpages/lists.html
p([H|T], H, T).
Lets see what happens when we ask some simple queries.
?- p([a,b,c], X, Y).
X=a
Y=[b,c]
yes
In Prolog we have relations, in a way similar to relationals DBs.
Then p/3 it's a relation among a list (first argument), its head H and its tail T.
Appropriately the tutorial' author used descriptive and synthetic symbols as Variables.
Syntactically, variables are symbols starting Uppercase and can get any value, but only one time (that is, cannot be 'reassigned').
The page you refer to says, "Consider the following fact.
p([H|T], H, T)."
So we must treat this as a fact. That means, it's like having a predicate
p([H|T], H, T):- true. % or, p(L,H,T) :- L=[H|T].
Now, when you query p([a,b,c], X, Y)., one is put besides the other:
p([a,b,c], X, Y). % a query
p([H|T], H, T) :- true. % a rule's clause: _head_ :- _body_.
the equivalences are noted: [a,b,c] = [H|T], X = H, Y = T and treated as unification equations. The first gets further translated into
a = H % list's head element
[b,c] = T % list's tail
because [A|B] stands for a list with A the head element of the list, and B the list's tail, i.e. all the rest of its elements, besides the head. H and T are common mnemonic names for these logical variables.
So on the whole, we get X = H = a, Y = T = [b,c].
This process is what's known as unification of a query and a rule's head (the two things starting with a p "functor", and both having the 3 "arguments").
Since the query and the head of a rule's "clause" matched (had same functor and same number of arguments), and their arguments were all successfully unified, pairwise, using the above substitution, we only need to prove the body of that rule's clause (that was thus selected).
Since it is true, we immediately succeed, with the successful substitution as our result.
That's how Prolog works.
TL;DR: yes, when you call p(L,H,T) with a given list L, it will be destructured into its head H and tail T. But you may call it with a given list T, a value H, and a variable L, and then a new list will be constructed from the head and the tail. And if L is given as well, it will be checked whether its head is H, and its tail is T.
This is because Prolog's unification is bi-directional: A = B is the same as B = A. Unification with a variable is like setting that variable, and unification with a value is like checking the (structural) equality with that value.
Calling p(L,H,T) is really equivalent to the unification L = [H|T].

update nth element of a list

I am new to prolog , I have a list in prolog like A=[1,2,3,4], and than I accessed nth element using nth(N,[_|T],R). Now I have Nth element in R, than I have done some calculation on R. Now what I want is to update that nth element in list.
Because of I am doing a lot of calculations with each element in list I can't make a new list each time.
I didn't find any method to update list.
With regard to our conversation, you can add two lists together, creating a third, by specifying that the two head elements of the source lists, added together, make the head element of the result list, and that this applies to the remainder of the lists.
There is also a need for a base case, that is, when the two source lists are empty, so should the result list.
addLists([X|A], [Y|B], [Z|C]) :- Z is X+Y, addLists(A, B, C).
addLists([], [], []).
Remember you are always aiming to specify the constraints of the answer, more than the method of answering it. Prolog is very different to other programming languages in that you do not tell it how to do something, you simply tell it conditions that are true for the answer and let it extrapolate it.
From the comments you exchanged with #Orbling seems that what you need is a kind of maplist/4
process_list(A, B, C) :-
maplist(process_elem, A, B, C).
process_elem(A, B, C) :- C is A + B. % or whatever needed
If you are using the index in process_elem then this is not appropriate. Then make a recursive visit of list, passing down the index
process_list(A, B, C) :-
process_list(1, A, B, C).
process_list(I, [A|As], [B|Bs], [C|Cs]) :-
C is A + B * I, % or whatever needed
J is I + 1,
!, process_list(J, As, Bs, Cs).
process_list(_, [], [], []).
edit Just to add to the various ways exposed in answers to the question #Orbling suggests, here a way using nth0/4
?- I = 6, nth0(I,"hello world",_,T), nth0(I,U,0'W,T), format('~s',[U]).
hello World

Resources