Return values from database - Prolog - prolog

Good morning, I'm learning prolog.
But I already searched, but I didn't find a solution, it must be very simple, but I got stuck
I created a database like the following
data base([
movie(["Titanic"], [["Jack", "Dawson"] ,["Rose", "DeWitt", "Bukater"]], ["James","Cameron"] ),
movie(["Hulk"], [["Bruce", "Banner"] ,["Betty", "Ross"]], ["Ang","Lee"] )
]).
This database contains the name of the film, the name of the main characters and then the director.
The goal would be to create a function:
Example
find_movies_by_character("Bruce Banner")
Need return Titanic
I imagine something might be wrong, I'm open to new ideas

data base([ with that space in it, doesn't seem to be valid syntax in SWI Prolog. Wherever did you get that from?
This database contains the name of the film, the name of the main characters and then the director.
More specifically, the database contains a list containing movie terms, each containing a list containing the name of the film and (a list containing lists of parts of names of the main characters) and (a list containing parts of names of directors).
From how complicated it is to write out, it will be at least that complicated to work with. If you can simplify it, it will get easier to work with:
movie('Titanic', ['Jack Dawson', 'Rose DeWitt Bukater'], 'James Cameron').
movie('Hulk', ['Bruce Banner', 'Betty Ross'], 'Ang Lee').
find_movie_by_character(Character, MovieName) :-
movie(MovieName, Characters, _),
member(Character, Characters).
e.g.
?- find_movie_by_character('Bruce Banner', X).
X = 'Hulk'

Related

How to extend prolog driver and determine number of columns and rows by reading an eps file

Good day! I would like to ask for help in understanding Prolog code as well as learning how to extend its functionality. Based on my limited yet newbie knowledge of programming, the function of the first given code (is quite like a main file), everything originates from it and thus it is the first file that is run before calling any other function.
main.pl
printSequences([]).
printSequences([Sequence|Sequences]):-
writeln(Sequence),
printSequences(Sequences).
loadHelpers:-
['helpers'],
['part01'],
['part02'],
['part03'],
['part04'].
part01:-
readExtremePegSolitaireFile('test04.eps',_,Game),
printGame(Game),
columnsAndRows(Game).
part02:-
readExtremePegSolitaireFile('part01test01.eps',_,Game),
printGame(Game),
openSpaces(Game).
part03:-
readExtremePegSolitaireFile('test04.single.eps',_,Game),
printGame(Game),
setof(Moves,fewestMoves(Game,Moves),AllMoves),
writeln(moves),
printSequences(AllMoves).
part04:-
readExtremePegSolitaireFile('test04.eps',_,Game),
printGame(Game),
noIslands(Game).
I don't think I have any problems understanding the first given code above, but my problem is mostly with this second given code and how to go about manipulating other files. I can't seem to understand the prefix part (is this the definition of a list of lists?) Also am I correct that most of the other functions are declared in this helper file to make the code more organized?
helpers.pl
:- module( helpers,
[ readExtremePegSolitaireFile/3
, printGame/1
]
).
prefix([H],[]).
prefix([H|T],[H|PreT]):-
prefix(T,PreT).
readExtremePegSolitaireFile(File,Moves,Game):-
open(File,read,Input),
read(Input,Moves),
readGame(Input,Temp),
prefix(Temp,Game),
close(Input).
readGame(Input,[]):-
at_end_of_stream(Input),
!.
readGame(Input,[Row|Rows]):-
\+ at_end_of_stream(Input),
read(Input,Row),
readGame(Input,Rows).
printGame(Game):-
writeln(game),
printRows(Game).
printRows([]).
printRows([Row|Rows]):-
writeln(Row),
printRows(Rows).
Last is a peg solitaire board that is given with the first line being the list of moves performed and the following lines are the board declarations (1,2,3,4 - players, x - peg, and '-' as empty spaces)
test04.eps
[r,d,u,r,l,l,l,d,l,u,r,r].
[2,-,x,x,x,x,x].
[x,x,-,x,-,x,x].
[x,3,x,-,x,-,x].
[x,-,4,x,x,x,x].
[x,x,-,x,x,-,x].
[x,x,x,1,-,x,x].
[x,x,x,x,x,x,x].
I would like to know how one would be able to calculate the number of columns and rows via a query columnsAndRows(Game). My first plan of action was to use something like this: (Which would be able to calculate the length of the rows by counting each element in the list however, it seems to have calculated all the elements in the list. 2 things that I noticed was:
It didn't stop at the end of the row
Apparently it didn't print the entire board, it was missing the last line of the board!
columnsAndRows(Game) :-
flatten(Game, FlatList),
length(FlatList,FlatListSize),
writeln(FlatListSize).
?- [a04tests].
?- loadHelpers.
?- part01.
game
[2,-,x,x,x,x,x]
[x,x,-,x,-,x,x]
[x,3,x,-,x,-,x]
[x,-,4,x,x,x,x]
[x,x,-,x,x,-,x]
[x,x,x,1,-,x,x]
42
true
I'm honestly really lost and I'd appreciate any guidance as to where to begin, or even a process flow for this program. Many thanks!

Logic for parsing names

I am wanting to solve this problem, but am kind of unsure how to correctly structure the logic for doing this. I am given a list of user names and I am told to find an extracted name for that. So, for example, I'll see a list of user names such as this:
jason
dooley
smith
rob.smith
kristi.bailey
kristi.betty.bailey
kristi.b.bailey
robertvolk
robvolk
k.b.dula
kristidula
kristibettydula
kristibdula
kdula
kbdula
alexanderson
caesardv
joseluis.lopez
jbpritzker
jean-luc.vey
dvandewal
malami
jgarciathome
christophertroethlisberger
How can I then turn each user name into an extracted name? The only parameter I am given is that every user name is guaranteed to have at least a partial person's name.
So for example, kristi.bailey would be turned into "Kristi Bailey"
alexanderson would be turned into "Alex Anderson"
So, the pattern I see is that, if I see a period I will turn that into two strings (possibly a first and last name). If I see three periods then it will be first, middle. The problem I am having trouble finding the logic for is when the name is just clumped up together like alexanderson or jgarciathome. How can I turn that into an extracted name? I was thinking of doing something like if I see 2 consonants and a vowel in a row I would separate the names, but I don't think that'll work.
Any ideas?
I'd use a string.StartsWith method and a string.EndsWith method and determine the maximum overlap on each. As long as it's more than 2 characters, call that the common name. Sort them into buckets based on the common name. It's a naive implementation, but it that's where I'd start.
Example:
string name1 = "kristi.bailey";
string name2 = "kristi.betty.bailey";
// We've got a 6 character overlap for first name:
name2.StartsWith(name1.Substring(0,6)) // this is true
// We've got a 6 character overlap for last name:
name2.EndsWith(name1.Substring(7)) // this is true
HTH!

SWI-Prolog: how to insert a new clause to a database

I'm sorry, this has probably been asked before but I can't find a good answer.
I'm writing a Prolog assignment, in which we must write a database with insert, delete, etc. I'm currently stuck on the insert part. I'm trying to use tell, listing and told for this, but the results are often unpredictable, deleting random parts of the file. Here's the full code of my database, banco.pl:
:- dynamic progenitor/2.
progenitor(maria,joao).
progenitor(jose,joao).
progenitor(maria,ana).
progenitor(jose,ana).
insere(X,Y) :- dynamic progenitor/2, assert(progenitor(X,Y)).
tell('banco.pl'), listing(progenitor), told.
I then run the following on SWI-Prolog:
insere(luiz,luiza).
And get the following result on banco.pl:
:- dynamic progenitor/2.
progenitor(maria, joao).
progenitor(jose, joao).
progenitor(maria, ana).
progenitor(jose, ana).
Note that the clause I tried to insert isn't even in the file, and the lines defining commit and insere are missing.
How would I do this correctly?
tell starts writing to the beginning of the file. so you're overwriting everything else that was in the file. you have these options:
put your progenitor predicate (and just that) in another file.
use append/1 to write to the end of the file with portray_clause. this only helps for insert, but you stated that you want delete too.
read the other clauses into a list and reprint them, then use listing/1 :
(text for formatting)
read_all_other_clauses(All_Other_Clauses):-
see('yourfilename.pl'),
read_all_other_clauses_(All_Other_Clauses,[]),
seen.
read_all_other_clauses_(Other,Acc0):-
(read(Clause) ->
(Clause = progenitor(_,_) -> % omit those clauses, because they'll be printed with listing/1
read_all_other_clauses_(Other,Acc0);
read_all_other_clauses_(Other,[Clause|Acc0]));
Other = Acc0). % read failed, we're done
operation(Insert, X,Y):-
(call,(Insert) ->
assert(progenitor(X,y));
retract(progenitor(X,y))),
read_all_other_clauses(Others),
tell('yourfilename.pl'), % After the reading!
maplist(portray_clause,Others), %Maplist is a SWI built-in, easy to rewrite, if you don't have it.
listing(progenitor/2),
told.
insert(X,Y):- operation(true,X,Y).
delete(X,Y):- operation(fail,X,Y).
Note that you could use the read_all_other_clauses for your delete only, if you change the line with the omit comment. Then you could use the solution proposed in #2 for your insere

Prolog query not returning the expected result

For university exam revision, I came across a past paper question with a Prolog database with the following structures:
% The structure of a media production team takes the form
% team(Producer, Core_team, Production_assistant).
% Core_team is an arbitrarily long list of staff structures,
% but excludes the staff structures for Producer and
% and Production_assistant.
% staff structures represent employees and take the form
% staff(Surname,Initial,file(Speciality,Grade,CV)).
% CV is an arbitrarily long list of titles of media productions.
team(staff(lyttleton,h,file(music,3,[my_music,best_tunes,showtime])),
[staff(garden,g,file(musical_comedy,2,[on_the_town,my_music])),
staff(crier,b,file(musical_comedy,2,[on_the_town,best_tunes]))],
staff(brooke-taylor,t,file(music,2,[my_music,best_tunes]))).
team(staff(wise,e,file(science,3,[horizon,frontiers,insight])),
[staff(morcambe,e,file(science,3,[horizon,leading_edge]))],
staff(o_connor,d,file(documentary,2,[horizon,insight]))).
team(staff(merton,p,file(variety,2,[showtime,dance,circus])),
[staff(smith,p,file(variety,1,[showtime,dance,circus,my_music])),
staff(hamilton,a,file(variety,1,[dance,best_tunes]))],
staff(steaffel,s,file(comedy,2,[comedians,my_music]))).
team(staff(chaplin,c,file(economics,3,[business_review,stock_show])),
[staff(keaton,b,file(documentary,3,[business_review,insight])),
staff(hardy,o,file(news,3,[news_report,stock_show,target,now])),
staff(laurel,s,file(economics,3,[news_report,stock_show,now]))],
staff(senate,m,file(news,3,[business_review]))).
One of the rules I have to write is the following:
Return the initial and surname of any producer whose team includes 2
employees whose CVs include a production entitled ‘Now’.
This is my solution:
recurseTeam([],0).
recurseTeam[staff(_,_file(_,_,CV))|List],Sum):-
member(now,CV),
recurseTeam(List,Rest),
Sum is Rest + 1.
query(Initial,Surname):-
team(staff(Surname,Initial,file(Speciality,Grade,CV)),Core_team,Production_assistant),
recurseTeam([staff(Surname,Initial,file(Speciality,Grade,CV)),Production_assistant|Core_team,Sum),
Sum >= 2.
The logic I have here is that I have a recursive predicate which takes each staff member in turn, and a match is found only if the CV list contains the production 'now', and as you can see it will return the Initial and Surname of a Producer if at least 2 employees CV contains the 'now' production.
So, at least as far as I can see, it should return the c,chaplin producer, right? Because this team has staff members who have CV's which contains the 'now' production.
But when I query it, e.g.
qii(Initial,Surname).
It returns 'false'.
When I remove the "member(now,CV)" predicate, it successfully returns all four producers. So it would seem the issues lies with this rule. Member is the built-in predicate for querying the contents of lists, and 'CV' is the list structure that is contained within the file structure of a staff structure.
Any ideas why this isn't working as I had expected?
Any suggestions on what else I could try here?
You need one more clause for the recurseTeam predicate, namely for the case that the first argument is a non-empty list, but its first element is a file structure that does not contain now.
In the current version, recurseTeam simply fails as soon as it encounters such an element in the list.
One possible solution is to add the following third clause for recurseTeam:
recurseTeam([staff(_,_,file(_,_,CV))|List],Sum):-
\+ member(now,CV),
recurseTeam(List,Sum).
Alternatively, one can use a cut ! in the second recurseTeam clause after member(now,CV) and drop \+ member(now,CV) in the third clause. This is more efficient, since it avoids calling member(now,CV) twice. (Note, however, that this is a red cut – the declarative and the operational semantics of the program are no longer the same. Language purists may find this disturbing – "real programmers" don't care.)

Why cant i get the answer to the zebra puzzle in prolog?

this is my code currently, I am trying to solve the zebra puzzle.
exists(A,(A,_,_,_,_)).
exists(A,(_,A,_,_,_)).
exists(A,(_,_,A,_,_)).
exists(A,(_,_,_,A,_)).
exists(A,(_,_,_,_,A)).
rightOf(A,B,(B,A,_,_,_)).
rightOf(A,B,(_,B,A,_,_)).
rightOf(A,B,(_,_,B,A,_)).
rightOf(A,B,(_,_,_,B,A)).
middleHouse(A,(_,_,A,_,_)).
firstHouse(A,(A,_,_,_,_)).
nextTo(A,B,(B,A,_,_,_)).
nextTo(A,B,(_,B,A,_,_)).
nextTo(A,B,(_,_,B,A,_)).
nextTo(A,B,(_,_,_,B,A)).
nextTo(A,B,(A,B,_,_,_)).
nextTo(A,B,(_,A,B,_,_)).
nextTo(A,B,(_,_,A,B,_)).
nextTo(A,B,(_,_,_,A,B)).
:- Houses = (house(N1,P1,S1,D1,C1),house(N2,P2,S2,D2,C2),house(N3,P3,S3,D3,C3),house(N4,P4,S4,D4,C4),house(N5,P5,S5,D5,C5)),
exists(house(english,_,_,_,red),Houses),
exists(house(spainish,dog,_,_,_),Houses),
exists(house(_,_,_,coffee,green),Houses),
exists(house(ukrainian,_,_,tea,_),Houses),
rightOf(house(_,_,_,_,green),house(_,_,_,_,ivory),Houses),
exists(house(_,dog,oldgold,_,_),Houses),
exists(house(_,_,kools,_,yellow),Houses),
middleHouse(house(_,_,_,milk,_),Houses),
firstHouse(house(norwegian,_,_,_,_),Houses),
nextTo(house(_,_,chesterfields,_,_),house(_,fox,_,_,_),Houses),
nextTo(house(_,_,kools,_,_),house(_,horse,_,_,_),Houses),
exists(house(_,_,luckystike,orangejuice,_),Houses),
exists(house(japanise,_,parliments,_,_),Houses),
nextTo(house(norwegian,_,_,_,_),house(_,_,_,_,blue),Houses),
exists(house(WaterDrinker,_,_,water,_),Houses),
exists(house(ZebraOwner,zebra,_,_,_),Houses).
I have typed this up and saved it as zebra.pl, this I open it and enter [zebra] into SWI-prolog, it returns a warning message about the singleton use of N1,P1,C1 etc.. and returns true, then i ask it to print water drinker using print(WaterDrinker) and it returns _G317 and true,
why is it doing this and not returning the answer which could be norwegian, it does the same if i ask it return any variable like C3 or ZebraOwner
The main problem is that you cannot write a goal like :- Houses = ... in the middle of your program. Rather, you should write something like
solution(WaterDrinker, ZebraOwner) :-
Houses = ...
and then after the program has been loaded type
solution(W, Z).
at the -? prompt to compute the solution.
You also don't specify that all the values should be distinct. If you do that you will use the variables a second time and the warning will go away.
If you really need a variable only once you can prepend it with an underscore to make the warning go away. Or you can just use an underscore, like you already did many times.

Resources