What i'm trying to do is:
Given a list of characters to know which list best contradicts it, so image I put on the list [kraken,scorpia,zulrah] so it will check the type of attack of each and would see would be the most effective type of attack for each and with that, I would receive a list of 3 bosses.
% boss(Name, Type) Name = Name of boss, Type = Attack type
boss(kraken,magic).
boss(scorpia,melee).
boss(zulrah,ranged).
boss(cerberus,melee).
boss(abyssal_sire,melee).
boss(obor,melee).
boss(sarachnis,ranged).
boss(skotizo,melee).
boss(venenatis,magic).
superEffective(magic,melee). %magic is more effective against melee
superEffective(ranged,magic). %ranged is more effective against magic
superEffective(melee,ranged). %melee is more effective against ranged
First, create a predicate to verify the counter of a single Boss:
verify_con(Boss, ConBoss) :- boss(Boss,MainSkill),
superEffective(MainSkill,ConSkill),
boss(ConBoss,ConSkill), !.
Notice that this predicate will get always the first best counter to the input boss. If you want all the possible combinations, just delete the , ! at the end.
Second, use recursion to iterate over the input list and build the output list. You can use append/3 to append the output array.
verify_con_list([],[]).
verify_con_list([H|T], LIST) :- verify_con(H, ConBoss),
verify_con_list(T, L1),
append([ConBoss],L1, LIST).
If necessary, you can define the append/3 function at the top of your code like this:
append([], X, X).
append([H|T], X, [H|S]) :- append(T, X, S).
Examples
Single output:
?- verify_con(kraken, A).
A = scorpia
List input:
?- verify_con_list([kraken, scorpia, zulrah], Con).
Con = [scorpia, zulrah, kraken]
Full code:
append( [], X, X).
append( [X | Y], Z, [X | W]) :- append( Y, Z, W).
% boss(Name, Type) Name = Name of boss, Type = Attack type
boss(kraken,magic).
boss(scorpia,melee).
boss(zulrah,ranged).
boss(cerberus,melee).
boss(abyssal_sire,melee).
boss(obor,melee).
boss(sarachnis,ranged).
boss(skotizo,melee).
boss(venenatis,magic).
superEffective(magic,melee). %magic is more effective against melee
superEffective(ranged,magic). %ranged is more effective against magic
superEffective(melee,ranged). %melee is more effective against ranged
verify_con(Boss, ConBoss) :- boss(Boss,MainSkill),
superEffective(MainSkill,ConSkill),
boss(ConBoss,ConSkill), !.
verify_con_list([],[]).
verify_con_list([H|T], LIST) :- verify_con(H, ConBoss),
verify_con_list(T, L1),
append([ConBoss],L1, LIST).
%verify_con(kraken, A).
%verify_con_list([kraken, scorpia, zulrah], Con).
Related
I am currently attempting to write a Prolog program which will add a given character to the end of a list. The list's I want to append are elements within a list. This is what I currently have.
extends(X, [], []).
extends(X, [[Head]|Lists], Y):-
append([X], [Head], Y),
extends(X, Lists, [Y]).
Here I'm attempting to concatenate X and Head, storing it in Y. However I want Y to be a list of lists, so when it repeats the process again the next concatenation will be stored also in Y. So at the end of the program Y would store the results of all the concatenations. I would want the result to look like as follows.
?- extends(a, [[b,c], [d,e,f], [x,y,z]], Y).
Y = [[b,c,a], [d,e,f,a], [x,y,z,a]].
Could anyone help me out with this?
You want to apply some operation to corresponding elements of two lists. That operation talks about lists itself. It's easy to get confused with the nested levels of lists, so let's try not to think in those terms. Instead, define first a predicate that does the extension of one list:
element_list_extended(Element, List, Extended) :-
append(List, [Element], Extended).
This behaves as follows, using cases from your example:
?- element_list_extended(a, [b, c], Extended).
Extended = [b, c, a].
?- element_list_extended(a, List, [x, y, z, a]).
List = [x, y, z] ;
false.
Looks good so far. All we need to do is to apply this operation to corresponding elements of two lists:
extends(_Element, [], []).
extends(Element, [Xs | Xss], [Ys | Yss]) :-
element_list_extended(Element, Xs, Ys),
extends(Element, Xss, Yss).
And this works:
?- extends(a, [[b,c], [d,e,f], [x,y,z]], Y).
Y = [[b, c, a], [d, e, f, a], [x, y, z, a]] ;
false.
The key to making it work was to decompose the problem into two parts and to solve those simpler parts separately.
Now, if we like, since the definition of element_list_extended/3 is a single clause containing a single goal, we might decide to do without it and inline its definition into extends/3:
extends(_Element, [], []).
extends(Element, [Xs | Xss], [Ys | Yss]) :-
append(Xs, [Element], Ys),
extends(Element, Xss, Yss).
As you can see, you were quite close! You just had some superfluous brackets because you got confused about list nesting. That's precisely where decomposing the problem helps.
(As the other answer said, SWI-Prolog has some useful libraries that allow you to express even this in even shorter code.)
extends(PostFix, ListIn, ListOut) :-
maplist({PostFix}/[In,Out]>>append(In,[PostFix],Out),ListIn, ListOut).
This is using library(yall) a maplist/3 and append/3.
d_edge(a, b, 5).
e_edge(a, c, 6).
f_edge(b, c, 8).
% I will have a list of rules for the graph point
% from source to destination with weight.
list2pair([T], [A,B], [(T,A,B)]).
list2pair([T1|Tt], [A1,A2|T], Result) :-
list2pair(Tt, [A1|T], R1),
append([(T1,A1,A2)], R1, Result).
I want to come up with the result like
[d_edge(a,b), f_edge(b,c)]
my 1st arg will be the list of names [d_edge,f_edge]
my 2nd arg will be the list of vertexes [a,b,c].
My current code generates [(d_edge,a,b),(f_edge,b,c)].
Whenever I try to update the predicate from (T1,A1,A2) to T1(,A1,A2)
I get an error saying that it is not valid predicate.
I understand why I am getting the error. But I couldn't find a way around it.
First things first: T1(,A1,A2) is syntactically incorrect.
Here's how you could proceed using the built-in predicate (=..)/2 (a.k.a. "univ"):
list2pair([T], [A1,A2], [X]) :-
X =.. [T,A1,A2].
list2pair([T1|Tt], [A1,A2|T], [X|Xs]) :-
X =.. [T1,A1,A2],
list2pair(Tt, [A2|T], Xs).
Sample query using SICStus Prolog 4.3.2:
| ?- list2pair([d_edge,f_edge], [a,b,c], Xs).
Xs = [d_edge(a,b),f_edge(b,c)] ? ; % expected result
no
Note that the above only "constructs" these compound terms—it does not ensure that suitable facts d_edge/3, f_edge/3 etc really do exist.
I am trying to create an included_list(X,Y) term that checks if X is a non-empty sublist of Y.
I already use this for checking if the elements exist on the Y list
check_x(X,[X|Tail]).
check_x(X,[Head|Tail]):- check_x(X,Tail).
And the append term
append([], L, L).
append([X | L1], L2, [X | L3]) :- append(L1, L2, L3).
to create a list, in order for the program to finish on
included_list([HeadX|TailX],[HeadX|TailX]).
but I am having problems handling the new empty list that I am trying to create through "append" (I want to create an empty list to add elements that are confirmed to exist on both lists.)
I have found this
sublist1( [], _ ).
sublist1( [X|XS], [X|XSS] ) :- sublist1( XS, XSS ).
sublist1( [X|XS], [_|XSS] ) :- sublist1( [X|XS], XSS ).
but it turns true on sublist([],[1,2,3,4)
Since you're looking for a non-contiguous sublist or ordered subset, and not wanting to include the empty list, then:
sub_list([X], [X|_]).
sub_list([X], [Y|T]) :-
X \== Y,
sub_list([X], T).
sub_list([X,Y|T1], [X|T2]) :-
sub_list([Y|T1], T2).
sub_list([X,Y|T1], [Z|T2]) :-
X \== Z,
sub_list([X,Y|T1], T2).
Some results:
| ?- sub_list([1,4], [1,2,3,4]).
true ? a
no
| ?- sub_list(X, [1,2,3]).
X = [1] ? a
X = [2]
X = [3]
X = [1,2]
X = [1,3]
X = [1,2,3]
X = [2,3]
(2 ms) no
| ?- sub_list([1,X], [1,2,3,4]).
X = 2 ? a
X = 3
X = 4
(2 ms) no
Note that it doesn't just tell you if one list is a sublist of another, but it answers more general questions of, for example, What are the sublists of L? When cuts are used in predicates, it can remove possible valid solutions in that case. So this solution avoids the use of cut for this reason.
Explanation:
The idea is to generate a set of rules which define what a sublist is and try to do so without being procedural or imperative. The above clauses can be interpreted as:
[X] is a sublist of the list [X|_]
[X] is a sublist of the list [Y|T] if X and Y are different and [X] is a sublist of the list T. The condition of X and Y different prevents this rule from overlapping with rule #1 and greatly reduces the number of inferences required to execute the query by avoiding unnecessary recursions.
[X,Y|T1] is a sublist of [X|T2] if [Y|T1] is a sublist of T2. The form [X,Y|T1] ensures that the list has at least two elements so as not to overlap with rule #1 (which can result in any single solution being repeated more than once).
[X,Y|T1] is a sublist of [Z|T2] if X and Z are different and [X,Y|T1] is a sublist of T2. The form [X,Y|T1] ensures that the list has at least two elements so as not to overlap with rule #2, and the condition of X and Z different prevents this rule from overlapping with rule #3 (which can result in any single solution being repeated more than once) and greatly reduces the number of inferences required to execute the query by avoiding unnecessary recursions.
Here is what you an do:
mysublist(L,L1):- sublist(L,L1), notnull(L).
notnull(X):-X\=[].
sublist( [], _ ).
sublist( [X|XS], [X|XSS] ) :- sublist( XS, XSS ).
sublist( [X|XS], [_|XSS] ) :- sublist( [X|XS], XSS ).
Taking a reference from this:
Prolog - first list is sublist of second list?
I just added the condition to check if it was empty beforehand.
Hope this helps.
If order matters. Example [1,2,3] is sublist of [1,2,3,4] but [1,3,2] not.
You can do something like this.
sublist([],L).
sublist([X|L1],[X|L2]):- sublist(L1,L2)
I would use append :
sublist(X, []) :-
is_list(X).
sublist(L, [X | Rest]) :-
append(_, [X|T], L),
sublist(T, Rest).
Basically we can check if M is a sublist of L if M exists in L by appending something on its back and/or its front.
append([], Y, Y).
append([X|XS],YS,[X|Res]) :- append(XS, YS, Res).
sublist(_, []).
sublist(L, M) :- append(R, _, L), append(_, M, R).
I have this list in Prolog:
[[13,Audi A3,11.11.2011,75000,berlina,audi,12100,verde pisello,[4wd],3.0000133333333334],[11,santafe,11.11.2011,80000,fuoristrada,audi,2232232,verde pisello,[Metalizzata,Sedile in Pelle,4wd],7.0000125]]|
I want to sort this list for last value of sublist, as example I want to have this result:
[[11,santafe,11.11.2011,80000,fuoristrada,audi,2232232,verde pisello,[Metalizzata,Sedile in Pelle,4wd],7.0000125],[13,Audi A3,11.11.2011,75000,berlina,audi,12100,verde pisello,[4wd],3.0000133333333334]]
predsort it's your friend. Then sort is easy, but to sell an Audi verde pisello will remain very, very hard...
sort_on_last(List, Sorted) :-
predsort(compare_last, List, Sorted).
compare_last(R, X, Y) :-
last(X, Xl),
last(Y, Yl),
compare(R, Xl, Yl).
To try it:
test :- sort_on_last(
[[11,santafe,'11.11.2011',80000,fuoristrada,audi,2232232,'verde pisello',['Metalizzata','Sedile in Pelle','4wd'],7.0000125],
[13,'Audi A3','11.11.2011',75000,berlina,audi,12100,'verde pisello',['4wd'],3.0000133333333334]
], S),
maplist(writeln, S).
?- test.
[13,Audi A3,11.11.2011,75000,berlina,audi,12100,verde pisello,[4wd],3.0000133333333334]
[11,santafe,11.11.2011,80000,fuoristrada,audi,2232232,verde pisello,[Metalizzata,Sedile in Pelle,4wd],7.0000125]
true.
A particularity of predsort/3: it acts as sort/2, thus remove duplicates.
To avoid this problem, compare_last/3 can be changed, avoiding return =, in this way:
compare_last(R, X, Y) :-
last(X, Xl),
last(Y, Yl),
( Xl < Yl -> R = (<) ; R = (>) ).
How do you write a Prolog procedure map(List, PredName, Result) that applies the predicate PredName(Arg, Res) to the elements of List, and returns the result in the list Result?
For example:
test(N,R) :- R is N*N.
?- map([3,5,-2], test, L).
L = [9,25,4] ;
no
This is usually called maplist/3 and is part of the Prolog prologue. Note the different argument order!
:- meta_predicate(maplist(2, ?, ?)).
maplist(_C_2, [], []).
maplist( C_2, [X|Xs], [Y|Ys]) :-
call(C_2, X, Y),
maplist( C_2, Xs, Ys).
The different argument order permits you to easily nest several maplist-goals.
?- maplist(maplist(test),[[1,2],[3,4]],Rss).
Rss = [[1,4],[9,16]].
maplist comes in different arities and corresponds to the following constructs in functional languages, but requires that all lists are of same length. Note that Prolog does not have the asymmetry between zip/zipWith and unzip. A goal maplist(C_3, Xs, Ys, Zs) subsumes both and even offers more general uses.
maplist/2 corresponds to all
maplist/3 corresponds to map
maplist/4 corresponds to zipWith but also unzip
maplist/5 corresponds to zipWith3 and unzip3
...