finding players in the same the team in prolog - prolog

I'm trying to solve a prolog question. I'm trying to print the players who is playing in Arsenal. I couldn't solve the problem.
player(rick,arsenal)
player(tom,dortmund)
player(paul,bayern)
player(tim,liverpool)
player(john,arsenal)
player(andrew,arsenal)
the output has to be:
?- sameteam(????)
X= [rick,john,andrew]

First, your facts need to be terminated with a "." to be correct Prolog syntax
player(rick,arsenal).
player(tom,dortmund).
player(paul,bayern).
player(tim,liverpool).
player(john,arsenal).
player(andrew,arsenal).
In "relational database fashion", let's first collect the ground atoms (in the sense of "logic atoms", i.e. "facts") that match the condition "plays at arsenal".
Fire up your preferred Prolog, and then:
?- [user].
|: player(rick,arsenal).
|: player(tom,dortmund).
|: player(paul,bayern).
|: player(tim,liverpool).
|: player(john,arsenal).
|: player(andrew,arsenal).
|: ^D% user://2 compiled 0.00 sec, 6 clauses
true.
?- player(Who,arsenal).
Who = rick ;
Who = john ;
Who = andrew.
Now we just need to "collect them into a list" and we can do that easily using setof/3:
?- setof(Who,player(Who,arsenal),Players).
Players = [andrew, john, rick].
This is all bog-standard "asking the database" work.
We can pack the above into a predicate for easier usage:
?- [user].
|: sameteam(Players) :- setof(Who,player(Who,arsenal),Players).
|: ^D% user://3 compiled 0.00 sec, 1 clauses
true.
?- sameteam(Players).
Players = [andrew, john, rick].

Related

change the output in Prolog - for detecting covid symptoms

I would like to ask if you could advise me how to create a condition or redo the code. I need the output of the program to detect the symptoms of covid19. If I mark 'yes' at least 3 times out of ten symptoms in the program, the output will be 'you have covid19 symptoms'. If 'yes' less than 3 times, the output will be 'you have no covid19 symptoms'.
Thank you
start :- x(Disease), write('the verdict is : '), write(Disease),nl, undo.
x(symptoms) :- symptoms,!.
x(withoutsymptoms). /* without symptoms */
symptoms :- verify(conjunctivitis),
verify(sore_throat),
verify(fatigure),
verify(shake),
verify(diarrhea),
verify(runny_nose),
verify(cold),
verify(muscle_pain),
verify(chest_pressure),
verify(loss_of_taste),
verify(fever).
ask(Question) :-
write('How are you? '),
write(Question),
write('? '),
read(Response),
nl,
( (Response == yes ; Response == yes)
->
assert(yes(Question)) ;
assert(no(Question)), fail).
:- dynamic yes/1,no/1.
verify(S) :-
(yes(S)
->
true ;
(no(S)
->
fail ;
ask(S))).
undo :- retract(yes(_)),fail.
undo :- retract(no(_)),fail.
undo.
That attempt looks confusing. How about the following, which additionally doesn't use assertz/1 to poke the Prolog database, but collects the responses in a list for later analysis.
Also, instead of using the "term deserializer" read/1, we use read_line_to_string/2
% ---
% Symptoms are listed naturally in a list.
% There are 11 symptoms
symptoms( [conjunctivitis,
sore_throat,
fatigue,
shake,
diarrhea,
runny_nose,
cold,
muscle_pain,
chest_pressure,
loss_of_taste,
fever] ).
% ---
% Go through the symptoms list, collecting answers
ask_about_symptoms([],[]).
ask_about_symptoms([Symptom|MoreSymptoms],[Answer-Symptom|MorePairs]) :-
repeat,
format("Do you have: ~s?\n",[Symptom]),
read_line_to_string(user_input,S1),
string_lower(S1,S2),
(
member(S2,["yes","y","ja","oui"])
->
Answer = yes
;
member(S2,["no","n","nein","non"])
->
Answer = no
;
format("Please try again\n",[]),fail % Back to "repeat"
),
ask_about_symptoms(MoreSymptoms,MorePairs).
is_yes_pair(yes-_).
ask_candidate :-
symptoms(Symptoms),
ask_about_symptoms(Symptoms,AnswerPairs),
!, % don't go back to asking
include(is_yes_pair,AnswerPairs,Included),
format("So you say you have the following symptoms: ~q~n",[Included]),
length(Included,Hits),
((Hits>=3) -> format("Looks bad.~n",[]) ; format("You probably don't have it.~n",[])).
Example run:
?- [rona].
true.
?- ask_candidate.
Do you have: conjunctivitis?
|: y
Do you have: sore_throat?
|: y
Do you have: fatigue?
|: n
Do you have: shake?
|: n
Do you have: diarrhea?
|: n
Do you have: runny_nose?
|: y
Do you have: cold?
|: foo
Please try again
Do you have: cold?
|: bar
Please try again
Do you have: cold?
|: n
Do you have: muscle_pain?
|: n
Do you have: chest_pressure?
|: y
Do you have: loss_of_taste?
|: y
Do you have: fever?
|: y
So you say you have the following symptoms: [yes-conjunctivitis,yes-sore_throat,yes-runny_nose,yes-chest_pressure,yes-loss_of_taste,yes-fever]
Looks bad.
true.

SWI Prolog Database

is there a way I can query a SWI Prolog database to check if it doesn't contain an element?
I have tried using "not" but doesn't seem to work with this version of Prolog.
maybe you're looking for clause/2. A dummy session sample
1 ?- [user].
|: a(1).
|: a(2).
|: a(X) :- b(X).
|: b(3).
|: b(4).
% user://1 compiled 0.03 sec, 6 clauses
true.
2 ?- clause(a(X),Body).
X = 1,
Body = true ;
X = 2,
Body = true ;
Body = b(X).
3 ?- clause(b(X),Body).
X = 3,
Body = true ;
X = 4,
Body = true.
4 ?- clause(c(X),Body).
false.
you can see that c/1 is not defined...
Anyway, SWi-Prolog database is a complex beast, and it offers much more control about its contents.

Prolog: how to write n amount of characters of a string?

I'm really new to prolog and i have to write a predicate what takes in a string and an integer and writes out as many characters of that string as the integer value is. How can i do this ?
Example:
myPredicate('Hello',4). %will write out 'Hell'
myPredicate('New in prolog',6). %will write out 'New in'
format it's the appropriate predicate to perform formatted output, but it doesn't provide a truncation of values. Then you could define a service predicate like print_n/2:
6 ?- [user].
|: print_n(W,N) :- sub_atom(W,0,N,_,S),write(S).
% user://1 compiled 0.04 sec, 2 clauses
true.
7 ?- print_n(hello,3).
hel
true.
then format/2 can invoke your service predicate by means of #:
8 ?- format('hello ~#~n', [print_n(world,3)]).
hello wor
true.

How to read an array "list" & print it in prolog?

How to read an array "list" & print it in prolog ?
I need to :-
Prompt user to insert an array
The user some how tells me that He's finished
Then I print it
I just can't think of how to make this in a predicate.
Is this what you would like to have?
1 ?- p(X).
|: a.
|: b.
|: c.
|: d.
|: end.
Code:-
X = [a, b, c, d].
This is how one can implement this behaviour:
p(X) :- read(A), q(A,X-[]).
q(end,X-X) :- !.
q(A,[A|X]-Y) :- read(B), q(B,X-Y).

Prolog syntax - using function results

I am trying to perform a sum operation on every result of :
combination(0,_,[]).
combination(K,L,[X|Xs]) :-
K > 0,
el(X,L,R),
K1 is K-1,
combination(K1,R,Xs).
el(X,[X|L],L).
el(X,[_|L],R) :- el(X,L,R).
For example, the user will enter is_sum_equal_10 ([1,2,3,4,5,6,7]) and the result will be true if the sum of any of the permutations equals 10.
I am struggling with putting it all together, can someone please help me define the is_sum_equal_10 rule that uses the combination rule for each permutation?
OK, well it's pretty easy to write really, you just need a rule to say if a particular combination sums to 10, and then another extra one to count up through the different sizes of combination lists (which is required due to the way you wrote combination with the K that you need to decrease as you check the rule).
1 ?- [user].
|: combination(0,_,[]).
|: combination(K,L,[X|Xs]) :- K > 0,
|: el(X,L,R), K1 is K-1, combination(K1,R,Xs).
|: el(X,[X|L],L).
|: el(X,[_|L],R) :- el(X,L,R).
|:
|: totals_10([],10).
|: totals_10([X|Xs],T) :- N is T+X, totals_10(Xs,N).
|:
|: is_comb_sum_equal_10(Numbers,_,R) :- combination(R,Numbers,C), totals_10(C,0).
|: is_comb_sum_equal_10(Numbers,N,R) :- Rnext is R+1, Rnext =< N,
|: is_comb_sum_equal_10(Numbers,N,Rnext).
|:
|: is_sum_equal_10(Numbers) :- length(Numbers,N), is_comb_sum_equal_10(Numbers,N,0).
|:
% user://1 compiled 0.13 sec, 1,824 bytes
true.
2 ?- is_sum_equal_10([2,3,5]).
true .
3 ?- is_sum_equal_10([2,235,124,3,3347,5,2373]).
true .
4 ?- is_sum_equal_10([2,235,124,3,3347,6,2373]).
false.
5 ?- is_sum_equal_10([1,1,1,1,1,-1,1,1,1,1,12]).
false.
6 ?- is_sum_equal_10([1,1,1,1,1,-1,1,1,1,1,11]).
true ;
false.
Since you don't care about the actual list or how big it is in the is_sum_equal_10 thing, you can just sum the combinations as you go along, and even better, check the sum is correct as a rule for the base case. I think it's a bit neater if you subtract from the desired total to get to 0 at the base rather than adding up and checking at the end against the value you want. This gives you a very simple single ruleset to look for a certain sum.
7 ?- [user].
|: is_subset_sum(0,[]).
|: is_subset_sum(N,[_|Xs]) :- is_subset_sum(N,Xs).
|: is_subset_sum(N,[X|Xs]) :- R is N-X, is_subset_sum(R,Xs).
|:
% user://2 compiled 0.03 sec, 540 bytes
true.
8 ?- is_subset_sum(10,[3,5,6]).
false.
9 ?- is_subset_sum(10,[123,4,1,77,3,2,34]).
true .
10 ?- is_subset_sum(11,[0,2,4,6,8,10,12,14,16,18,20,22]).
false.
This approach is of course both much easier to understand, and a lot more efficient.

Resources