Prolog - program skipping over read? - prolog

Title more or less says it all. I got the following code in SWI-PROLOG:
get_card(1):-
nb_getval(playerOneHand, Hand),
write("Select which cards you want to play:"), nl,
read(Input),
handle_input(Input).
get_card(2):-
nb_getval(playerTwoHand, Hand),
write("Select which cards you want to play:"), nl,
read(Input),
handle_input(Input).
Expected input-format right now is something like [ 0, 1 ]. to play your first two cards, [ 0 ]. to only play your first card, so on and so forth. While I know this is beyond horrible as far as input formats go, the priority right now is to atleast get it working, then move on to a better UI from there.
This is what happens:
I'm very new to Prolog so bear with me, but this is how I'm looking at it: It seems to be "skipping" over our read and is now expecting a new command to be entered instead (ENTER has been pressed in the above picture).
I feel like the solution should be very simple but unfortunately is nothing I can seem to wrap my head around. Thanks in advance!
EDIT: Example code that can be ran to reproduce the issue, unless it's only happening on my system for some reason:
% Initialize globals
?- nb_setval(playerOneHand, []).
?- nb_setval(playerTwoHand, []).
handle_input(Input, Hand):-
write("Input is "), write(Input), nl,
write("Hand is "), write(Hand), nl.
get_card(1):-
nb_getval(playerOneHand, Hand),
write("Select which cards you want to play: "), nl,
read(Input),
handle_input(Input, Hand).
get_card(2):-
nb_getval(playerTwoHand, Hand),
write("Select which cards you want to play: "), nl,
read(Input),
handle_input(Input, Hand).
?- write("Player 1: "), get_card(1), nl,
write("Player 2: "), get_card(2), nl.
Using SWI-Prolog and the given code in a test.pl file, it is simply consulted via the terminal interface (File -> Consult -> test.pl). Trying to give SWI-Prolog ANY kind of input then results in the issue at hand.

As mentioned by Isabelle Newbie in the comments, swipl.exe (that is started by default) has a long-running bug associated with proper input/output. Navigating to where Prolog is installed and instead using swipl-win.exe seems to have done the trick.

Related

How can I print the contents of a list stored in database, one by one?

I am trying to learn Prolog on my own and wanted to figure out how to print the contents of a list stored in a database, one by one.
My thought is that if I open (consult) this in SWI-Prolog, I can then run the code using go(). and get it to output the values in the valueslist.
valueslist(['papua new guinea',botswana,'netherlands antilles',sweden,cameroon]).
printlist([]).
printlist([X|List]) :-
write(X),nl,
printlist(List).
go :-
write('Here is an example list of countries: '), nl,
printlist(valueslist).
As it is right now the code just prints Here is an example list of countries: followed by false.
What I wanted it to do is print that Here us an example... followed by the countries list like
papua new guinea
botswana
netherlands antilles
sweden
cameroon
How would one properly do accomplish something like this in Prolog?
Actually I found an answer by continuing to tinker with it. I am not sure if this is a good way to do it in Prolog but it is giving the output I hoped for.
The code that prints out the list looks like so:
valueslist(['papua new guinea',botswana,'netherlands antilles',sweden,cameroon]).
printlist([]).
printlist([X|List]) :-
write(X),nl,
printlist(List).
go :-
write('Here is an example list of countries: '), nl,
valueslist(List),
printlist(List).

Prolog Returning Elements Within Facts to The User

I have a Prolog knowledge base with some "symptom" facts called facts.pl. Here is an example of my KB:
symptom("Typhoid", "muscle_pain").
symptom("Typhoid", "bloating").
symptom("Meningitis", "headache").
symptom("Meningitis", "fever").
symptom("Meningitis", "stiff neck" ).
symptom("Measles", "cough").
symptom("Measles", "runny_nose").
I have written a short prolog program in another file called "diseaseSearch.pl". This program consults facts.pl and is supposed to allow the user to enter a disease name and prints the disease's corresponding symptoms to the screen.
My code:
:- write('loading disease database'), nl.
:- [facts].
:- write('disease database loaded'), nl, nl.
getsymptoms:-
write('> Enter a diseae name followed by a period.'), nl,
write('For Example: Measles'), nl,
write('Disease Name?:'),
read(Input), nl,
symptom(Input,Output),
write(Output).
If I enter "Measles." the output should be "cough" and "runny_nose". However, with the code above no matter which disease I enter it always returns the result from the first fact which is "muscle_pain". SWI output found here
I found a similar method from an online tutorial, I am trying to learn the basics of Prolog input and output right now. Am I on the right track? Some tips to solve this problem would be greatly appreciated!
I guess you are entering Measles without " " and prolog takes it as a variables. Either you should enter it with "". If you enter Measles then it's a variables but if you enter "Measles" then it's a term.
If you want to enter without annotations then you need to make a database in which you have all terms(means that they start with small letter) then you don't need annotation.

Prolog read predicate cant read user key in in initialization?

I want to have a prolog program which can auto run once I compile finish and it should read input from user keyboard. However when i use
:- write('Your name is: '), nl, read(X).
there is not any effect on read(X), which it means that there us not any prompt for users to key in. Is there any solution for this problem? My prolog compiler is WIN-Prolog 5.0, thanks for your helo :)
maybe you need something like
:- initialization(main). % changed to be ISO compliant, was :- initialization main.
main :- write('Your name is: '), nl, read(X).
at least, ISO Prologs do it in this way....
Since read/1 is meant to parse Prolog (it's a full fledged parser), you must supply a Prolog term, and don't forget, as Joel76 suggested, to complete input with a dot: for instance:
Your name is:
|: 'Carlo'.

How to turn off "true" and "false" outputs in Prolog?

I would like to write a small text-based adventure game using Prolog (this might be a dumb idea but I am not here to discuss that).
The only problem is that I can't manage to print text on screen without the "true" and "false" values to appear as well.
For instance if I try something like:
take(desk) :- write('This thing is way too heavy for me to carry!').
where take is a one place predicate and desk a name I get as an output:
?- take(desk).
This thing is way too heavy for me to carry!
true.
How can I get rid of this "true" or "false" outputs?
Just to mention that I also tried with the format/1 one place predicate for simple text output and also the format/2 two place predicate (when I want to output the name of a variable) but it gives exactly the same problem.
I have also seen this answer but first it is not detailed enough (at least not for someone like me) and second, I hope deep inside that there is a simpler manner to do it.
And finally, I am using SWI-Prolog.
Thank you.
A simplistic method would be to create a little REPL (read, evaluate, print loop) of your own. Something like this:
game :-
repeat,
write('> '),
read(X),
call(X),
fail.
This will just prompt and execute whatever you enter at the prompt. In conjunction with your take fact (and another I added for illustration):
take(desk) :- write('This thing is way too heavy for me to carry!'), nl.
take(chair) :- write('This is easier to carry.'), nl.
You would get:
?- game.
> take(desk).
This thing is way too heavy for me to carry!
> take(chair).
This is easier to carry.
>
You don't get the true or false because the game goal doesn't resolve until you exit the loop somehow. You could add checks for a quit or bye or whatever to exit the game loop. Ctrl-C or Ctrl-D can be used as well to abort the loop. You might need to add some other "features" to make it work to your needs or liking.

swi-prolog user login and registration

I have user input/ login as following:
login:- write('username: '), read(User), nl, write('password: '), read(Pass).
and i have a database with usernames and passwords. I use find predicate to get all rows as a list like shown in the code:
find(R):-findall(Row, rs('SELECT name FROM patient where name=\'James\'', Row), R).
?- find(R).
R = [row('James'), row('James'), row('James'), row('James')].
Is there a way to use user input from read() and check if that user is in database?
I tried member(User, R) but it's not working properly.
I know prolog is not best language for this kind of stuff(login/registration). The reason why I'm doing this is that i'm working on helath care expert system in swi-prolog and i need login and reg for patients.
Is there a why this can be done? I'm new to prolog so im getting stuck on lots of stupid things.
Thanks!
.............
#gusbro I tried with member(row(User) as you told me:
check:-findall(Row, rs('SELECT name FROM patient where name=\'James\'', Row), R),
read(User), member(row(User), R);
write('wrong username!').
But i always get the same no matter what i write:
?- check.
|: Bla.
true ;
wrong username!
true.
?- check.
|: James.
true ;
wrong username!
true.
What you tried didn't work because you are trying to unify terms of the form row(Atom) with Atom.
It should work fine if you do member(row(User), R).
However, note that in your example it will succeed more than once because you have repeated "rows"...
You might want to consider using setof/3 instead of findall/3, as it will eliminate duplicates from the resulting list (and as a side effect if will fail if there are no matches of the template of setof)

Resources