Prolog find corresponding element from list - list

tennis([court, singles, doubles, outdoor, ball, racket]).
games([tennis, diving, soccer]). /* A list of games */
game_detail(tennis, [[court, 'two for doubles'], [singles, 'one for singles']]).
I am making a game that prolog program answers for the question of questioner.
At first, I give questioner the list of all available options and questioner can ask program with query has(X).
I made options for each games(Olympic games for a Q&A game).
However, How can I make the program answer the corresponding option's detail?
In here, the second element(string) in a list in another list.
Thank you for any help.
Whole code I wrote so far is below.
/* Game database */
tennis([court, singles, doubles, outdoor, ball, racket]).
diving([pool, singles, jump]).
soccer([ball, number, field]).
basketball([ball, number, field, foul]).
baseball([ball, number, field]).
fencing([number, field, foul]).
games([tennis, diving, soccer]). /* A list of games */
game_detail(tennis, [[court, 'two for doubles'], [singles, 'one for singles']]).
game_detail(diving, [[pool, '50m pool'], [singles, 'one swims 50m']]).
game_detail(soccer, [[ball, 'designated ball'], [number, '11 players']]).
/* Calling the corresponding answer for valid options */
detail(Game,[Option|Rest]).
detail(X,Y) :- game_detail(X,Options) .
Options = [[court, 'two'], [singles, 'one for']].
/* Random game selection */
rand(X) :- games(Y), random_member(X,Y), assert(selected(X)).
:- dynamic selected/1.
game_init :-
retract(selected(Y)),
retract(all_options(Z)),
all_options.
/* Counter */
:- dynamic counter/1.
counter(0). /* Initialize counter as 0 */
increment :- /* Set counter increment as 1 */
retract(counter(C)),
succ(C, C1),
assertz(counter(C1)).
cnt_init :- /* Initialize counter as 0 for next game */
retract(counter(C)),
assertz(counter(0)).
/* Showing all options of randomly selected game */
:- dynamic all_options/1.
all_options :- rand(X), call(X,Z), write(Z), assert(all_options(Z)).
/* Pop up the option from questioner */
delMember(_, [], []).
delMember(X, [X|Xs], Y) :-
delMember(X, Xs, Y).
delMember(X, [T|Xs], [T|Y]) :-
dif(X, T),
delMember(X, Xs, Y).
/* Answering has(X) query */
has(X) :- counter(C), all_options(Y),
( C=10 ->
write('Guess the game')
; C<10, member(X,Y) ->
write('Yes'), increment,
delMember(X,Y,Z),
retract(all_options(Y)), assert(all_options(Z))
; C<10, not(member(X,Y)) ->
write('No'), increment
; write('Invalid options')).
/* Answering is(X) query */
is(X) :- selected(Y), counter(C),
(X=Y ->
write('successful guess'), cnt_init, game_init
; C=10, not(X=Y) ->
write('unsuccessful guess'), cnt_init, game_init
; C<10, not(X=Y) ->
write('unsuccessful guess'), increment
).
/* Initialize program settings */
:- initialization(all_options).

Related

Erlang - Common items from two lists

Erlang Newbie here . Suppose I have two lists which are like this .
L1= [{'Lady in the Water',2.5},
{'Snakes on a Plane',3.5},
{'Just My Luck',3.0},
{'Superman Returns',3.5},
{'You, Me and Dupree',2.5},
{'The Night Listener',3.0}]
and
L2 = [{'Lady in the Water',3.0},
{'Snakes on a Plane',3.5},
{'Just My Luck',1.5},
{'Superman Returns',5.0},
{'You, Me and Dupree',3.5}]
I want the common ratings in a list of tuple like
[{2.5,3.0},{3.5,3.5},{3.0,1.5},{3.5,5.0},{2.5,3.5}]
My code is like this
common_rating(R1,R2)->common_rating(R1,R2,0,0).
common_rating(_X,[],M,N) ->{M,N};
common_rating(X,[Y|Y1],A,B)->
{M,R}=X,
{N,K }= Y,
case M=/=N of
true -> common_rating(X,Y1,A,B);
false -> common_rating(X,[],A+R,B+K)
end.
common_rating_final([],_R2,J) ->J;
common_rating_final([X|X1],R2,J)->
common_rating_final(X1,R2,J++[common_rating(X,R2)]).
To better understand the code
common_rating function expects a tuple of {movie,rating} and finds the same movie and rating from another list(B) and returns {rating,rating_B}
Now common_rating_final recursively goes over a list ,lets say A, and uses common_rating to find {rating_A,rating_B} for all movies that are common in A and B both
but when I run my code
my_module:common_rating_final(L1,L2,[]).
it returns me
[{2.5,3.0},{3.5,3.5},{3.0,1.5},{3.5,5.0},{2.5,3.5},{0,0}]
I can filter the {0,0} part but I think my logic is flawed but could not able to write a code which returns only the common ratings without the {0,0} part .
Please assist .
TL;DR
[{X2, Y2} || {X1, X2} <- L1, {Y1, Y2} <- L2, X1 =:= Y1].
Maybe the "cracks" here can find a better (more efficient, etc.) solution, but this one works. Basically it pattern matches ("deconstruct") the Ls and compares the first element of the tuples, returning the second element if the first ones happen to be equal.
The whole stuff/proof:
gorre#uplink:~$ erl
Erlang/OTP 19 [erts-8.3] [source] [64-bit] [smp:4:4] [async-threads:10] [kernel-poll:false]
Eshell V8.3 (abort with ^G)
1> L1= [{"Lady in the Water",2.5}, {"Snakes on a Plane",3.5}, {"Just My Luck",3.0}, {"Superman Returns",3.5}, {"You, Me and Dupree",2.5}, {"The Night Listener",3.0}].
[{"Lady in the Water",2.5},
{"Snakes on a Plane",3.5},
{"Just My Luck",3.0},
{"Superman Returns",3.5},
{"You, Me and Dupree",2.5},
{"The Night Listener",3.0}]
2> L2 = [{"Lady in the Water",3.0}, {"Snakes on a Plane",3.5}, {"Just My Luck",1.5}, {"Superman Returns",5.0}, {"You, Me and Dupree",3.5}].
[{"Lady in the Water",3.0},
{"Snakes on a Plane",3.5},
{"Just My Luck",1.5},
{"Superman Returns",5.0},
{"You, Me and Dupree",3.5}]
3> [{X2, Y2} || {X1, X2} <- L1, {Y1, Y2} <- L2, X1 =:= Y1].
[{2.5,3.0},{3.5,3.5},{3.0,1.5},{3.5,5.0},{2.5,3.5}]
4>
Notice that I changed the atoms into strings (it works the same way though).

Prolog, find a item in given list of sublists and return sublist containing item(the one we are searching) and store it in a new list

%ProLog, Find will take three inputs which is
[item], [[a,0,0,1], [b,0,0,0]], StoreItHere
Code:
find([H|T], [[H|T1]|T2], ShiftData):-
append([], T1, ShiftData).
Output:
find([a],[[a,1,0,0], [b,0,0,0]], StoreItHere).
StoreItHere = [1,0,0].
%% Now, I want to iterate through a item's list to search for subsist in a list of subsists.
For eg. if the input is:
find([a,b,c,d],
[[a,1,0,0],[b,0,0,0],[z,1,0,0],[h,0,1,0],[c,1,0,0],[d,1,1,0],
StoreItHere).
Output Should be:
StoreItHere = [[1,0,0],[0,0,0],[1,0,0],[1,1,0]].
Code that I write gives me False.
Code:-
find([H|T], [[H|T1]|T2], ShiftData):-
append([], T1, ShiftData),
find(T), T2, ShiftData).

Recursively Assigning One List Element to Another in Prolog

This is a homework assignment and my first experience with Prolog. My goal is to create a list of Assignments from a list of people and a list of tasks. If a person has the letter identifier which matches the tasks then that persons ID and the Tasks ID are matched up and placed in a list of Assignments. My function prints out a list but it does not look like it is comparing all the elements. A sample input: schedule([p1,p2,p3],[t1,t2],Result). A sample output would look like [[p1,t1],[p2,t2][p3,t1],[p3,t2]].
What I have so far:
%%
%% person(ID, TASK_CAPABILITIES, AVAILABLE_HOURS)
%%
%% How many hours each person has available and what classes of tasks they
%% are capable of performing.
%%
person(p1, [c,a], 20).
person(p2, [b], 10).
person(p3, [a,b], 15).
person(p4, [c], 30).
%%
%% task(ID, REQUIRED_HOURS, TASK_CLASS)
%%
%% How long each task requires and what class it falls under.
%%
task(t1, a, 5).
task(t2, b, 10).
task(t3, c, 15).
task(t4, c, 10).
task(t5, a, 15).
task(t6, b, 10).
%test arithmetic functions
add(X, Y, Z) :- Z is X + Y.
subtract(X,Y,Z) :- Z is X - Y.
schedule([],[],[]).
schedule(People,
[Task|OtherTasks],
[[PersonId, TaskId]|RestOfAssignments]):-
member(PersonId, People),
person(PersonId, PersonCapabilities,_),
member(TaskId, [Task|OtherTasks]),
task(TaskId, TaskType,_),
member(TaskType, PersonCapabilities),
schedule( _, OtherTasks, RestOfAssignments).
My reasoning behind what I wrote was that the list of People would be compared to each task, then that task would be replaced by the next task and the comparison would repeat. What I see in the trace of this function instead is that the tasks are being removed from the list but are only compared to the first two People. My question is how can I get the schedule function to check the full list of people for each task?
Your problem seems ill specified, and you are simplifying too much... the code should keep into account hours availability as well as memberships. Ignoring this problem, select/3 instead of member/2 could help to model a naive solution:
schedule([],_,[]).
% peek a suitable task for PersonId
schedule([PersonId|People], Tasks, [[PersonId, TaskId]|RestOfAssignments]):-
select(TaskId, Tasks, RestTasks),
person(PersonId, PersonCapabilities,_),
task(TaskId, TaskType,_),
memberchk(TaskType, PersonCapabilities),
schedule(People, RestTasks, RestOfAssignments).
% if no suitable task for PersonId
schedule([_PersonId|People], Tasks, Assignments):-
schedule(People, Tasks, Assignments).
yields these solutions
?- schedule([p1,p2,p3],[t1,t2],Result).
Result = [[p1, t1], [p2, t2]] ;
Result = [[p1, t1], [p3, t2]] ;
Result = [[p1, t1]] ;
Result = [[p2, t2], [p3, t1]] ;
Result = [[p2, t2]] ;
Result = [[p3, t1]] ;
Result = [[p3, t2]] ;
Result = [].

prolog, i have list of structure how to Extract data and return new list of other structure?

I implementing Family program in prolog i have a problem to implement some rules.
first of all i implement this rule:
number_of_children_couple(_list):-
findall(children(_f,_m,_n),children(_f,_m,_n),_list).
return list:
19 ?- number_of_children_couple(_list).
_list = [children(mordechai, miriam, 1), children(salax, naima, 1), children(eli, bella, 2), children(..., ..., ...)|...].
my problem is how to implement :
number_of_children_person(_list28,list_person):-
first argument:
_list28 = _list //the above list ,that return from the rule
and second argument is :
list_person = [children(mordechai, 1), children(salax, 1),children(eli, 2),children(..., ...)|...]
and i also use with:
%_num is number of children for couple
children(_father,_mother,_num):-
couple(_mother,_father),
findall(_child,parents(_mother,_father,_child),_children),
length1(_children,_num).
%_num is number of children for _person
children(_person,_num):-
gender(_person,_),
findall(_child,parent(_person,_child),_list),
length1(_list,_num).
if what you want is to drop an argument from children/3 structure, can be done in a number of ways, the simpler being
number_of_children_person([],[]).
number_of_children_person([children(A,_,C)|R],[children(A,C)|T]) :-
number_of_children_person(R,T).
or more succintly
number_of_children_person(L3,L2) :-
findall(children(A,C), member(children(A,B,C),L3), L2).

Prolog If Then Else fail with member predicate

Hello guys I am working on a prolog game and I need to write a piece of code that will:
Take a number (ArmyNo) from the user.
Take an X coordinate
Take an Y coordinate.
Then I have a list that is named TempBoard and it looks like this:
([
(1,1,-,-),(1,2,-,-),(1,3,-,-),(1,4,-,-),
(2,1,-,-),(2,2,-,-),(2,3,-,-),(2,4,-,-),
(3,1,-,-),(3,2,-,-),(3,3,-,-),(3,4,-,-),
(4,1,-,-),(4,2,-,-),(4,3,-,-),(4,4,-,-)
]).
before I add this (X,Y,w,ArmyNO) to the list I first want to check it if it is already there.
I attempted to do that by using this code but it does not seem to work properly:
%#######Got the number####
repeat,
%Get Cordinates X & Y.
writelist( [TempBoard,'select coordinates for the horizontal axis 1 to 4 to place your soldier Mr. Human',nl]),
read(X),
writelist(['select coordinates for the vertical axis 1 to 4 to place your soldier Mr. Human',nl]),
read(Y),
%Check if they are in the list.
(
member( (X,Y,w,ArmyNo),TempBoard ) ->
( replace((X,Y,w,ArmyNo),TempBoard,NewBoard) ) ;
(
writelist(['selected positions are not available in the table Mr.Human',nl]) , fail
)
).
%%
(X, Y, w, ArmyNo)
cannot be unified with any member of your example list because w doesn't unify with -. You may have meant W.