I want to write a prolog program which tells me if a password fulfills the rules, which are:
the password must contain a letter(a-z),
a number(0-9),
a double letter (aa,ll,ww etc.),
must start with a letter (a, aa, c etc.),
must be at least 6 characters long
How can I do that? And how should I "ask questions" after that? (Q1:Is this password correct? Q2:Is it long enough?)
Thank you for your answer in advance. It's very important and I really appreciate it.
Well, I'd go with something like that, but there are maybe far better solutions using DCG or something else :
contains_letter(Password) :- wildcard_match('*[a-zA-Z]*', Password).
contains_number(Password) :- wildcard_match('*[0-9]*', Password).
contains_double_letter(Password) :-
(between(65, 90, Letter) ; between(97, 122, Letter)),
append([_, [Letter, Letter], _], Password),
!.
starts_with_letter(Password) :- wildcard_match('[a-zA-Z]*', Password).
long_enough(Password) :-
length(Password, Length),
Length >= 6.
check_everything(Password) :-
contains_letter(Password),
contains_number(Password),
contains_double_letter(Password),
starts_with_letter(Password),
long_enough(Password).
Usage would be :
?- check_everything("password_to_test").
or just one of the criterias :
?- long_enough("password_to_test").
Note that it uses a swi-pl predicate wildcard_match/2 and that I do not know if it is available in other implementations.
I hope this can be of some help !
Note that contains_letter/1, contains_number/1 and starts_with_letter/1 can all be combined into one wildcard_match/2 btw :
starts_with_letter_has_number(Password) :-
wildcard_match('[a-zA-Z]*[0-9]*', Password).
Related
I'm new to Prolog, and trying to implement an example from a textbook. I have been able to get the example working (through definite help from previous Stack Overflow posts!) finally, but now it is asking me to verify the user input: "Modify the given decision tree program, so that when the user responds to a question with an illegal answer, the system will ask him/her to reenter an answer which is among the specified choices."
In the below program, for marital status, the specified only options considered in the decision tree are "single" or "married." If you enter anything else, the goal is to get you to reenter your decision.
This is not working for me. My code is below:
:-dynamic income/2.
:-dynamic marital_status/2.
:-dynamic mortgage/2.
:-dynamic age/2.
marital_status(joe,married).
income(joe,60000).
mortgage(joe,20000).
age(joe,45).
main(X,Z):-var(X), write('what is your name?'),read(X), invest(X,Z),!.
main(X,Z):-invest(X,Z),!.
ask_marital_status(X,Y):-marital_status(X,Y).
ask_marital_status(X,Y):-not(marital_status(X,Y)), write('what is your marital status: married or single?'), read(Y), nl, asserta(marital_status(X,Y)).
ask_marital_status(X,Y):-Y \=married, Y \=single, write('what is your marital status: married or single?'), read(Y), nl, asserta(marital_status(X,Y)).
%ask_marital_status(X,Y):-Y \= married; Y \= single, ask_marital_status(X,Y).
ask_income(X,Y):-income(X,Y).
ask_income(X,Y):-not(income(X,Y)),write('what is your annual income?'), nl, read(Y), asserta(income(X,Y)).
ask_mortgage(X,Z):-mortgage(X,Z).
ask_mortgage(X,Z):-not(mortgage(X,Z)), write('what is your mortgage?'), read(Z), nl, asserta(mortgage(X,Z)).
ask_age(X,A):-age(X,A).
ask_age(X,A):-not(age(X,A)), write('what is your age?'), read(A), nl, asserta(age(X,A)).
moderate_risk(X):-ask_marital_status(X,Y), Y=married, ask_income(X,I), I=<50000, ask_mortgage(X,Z), Z=<50000,!.
moderate_risk(X):-ask_marital_status(X,M), M=married, ask_income(X,I), I=<50000,!.
moderate_risk(X):-ask_marital_status(X,M), M=single, ask_income(X,I), I=<35000,!.
stable_risk(X):-ask_marital_status(X,M), M=married, ask_income(X,I), I=<50000, ask_mortgage(X,Z), Z>50000,!.
stable_risk(X):-ask_marital_status(X,M), M=single, ask_income(X,I), I>35000, ask_age(X,A), A>50, !.
high_risk(X):-ask_marital_status(X,M), M=single, ask_income(X,I), I>35000, ask_age(X,A), A=<50, !.
invest(X,oil):-stable_risk(X),!.
invest(X,telecommunications):-moderate_risk(X),!.
invest(X,computers):-high_risk(X),!.
The third "ask_martial_status" is my current attempt to get the user to reenter their decision, but it is not working. I have tried it with Prolog's AND operator(,) and their or operator (;) - neither make a difference (for what I place in between Y\= married and Y\=single). When I enter erroneous input, I just get "false" returned. Below is an example:
?- main(X,Z).
what is your name?logan.
what is your marital status: married or single?|: widowed.
false.
The commented out line (with the %) was a previous attempt to get the program working that also failed. I'm surprised I wasn't able to find a quick YouTube video / article to read when I Google'd this issue. Could anyone help me out here?
The traditional way of reading and validating user input is to use the following template:
ask(Data) :-
repeat,
write(Prompt),
read(Data),
valid(Data),
!.
Applying this template to your case, we can write:
ask_marital_status(Status) :-
repeat,
write('What is your marital status (married or single)?'),
read(Status)
( Status == married
; Status == single
),
!.
As a general rule, is best practice to separate asking the user input from processing the input (asserting a fact in your case).
High-level solutions would use message printing and question asking mechanisms for user interaction (see e.g. https://logtalk.org/2019/11/14/abstracting-user-interaction.html). But that's a more advanced topic.
You can solve your problem in this way (snippet of the involved prefocate):
ask_marital_status(X,Y):-
\+ marital_status(X,Y),
write('what is your marital status: married or single?'),
read(Y1),
( (Y1 == single ; Y1 == married) ->
Y = Y1,
asserta(marital_status(X,Y));
ask_marital_status(X,Y)
).
You can check if the value you read (Y1) is single or married with (Y1 = single ; Y1 = married) (; means or). Then, if so (->) you proceed with the rest of the predicate. Otherwise, (after the ; next to asserta/1) you call recursively marital_status/2.
EDIT: thanks to Paulo Moura's comment, =/2 (unification) must be replaced with ==/2 (equality), in order to make the code behave as expected.
I'm trying to train my Wit.ai bot in order to recognize the first name of someone. I'm not very sure if I well understand how the NLP works so I'll give you an example.
I defined a lot of expressions like "My name is XXXX", "Everybody calls me XXXX"
In the "Understanding" table I added an entity named "contact_name" and I add almost 50 keywords like "Michel, John, Mary...".
I put the trait as "free-text" and "keywords".
I'm not sure if this process is correctly. So, I ask you:
does it matter the context like "My name is..." for the NLP? I mean...will it help the bot to predict that after this expression probably a fist name will come on?
is that right to add like 50 values to an entity or it's completly wrong?
what do you suggest as a training process in order to get the first name of someone?
You have done it right by keeping the entity's search strategy as "free-text" and "Keywords". But Adding keywords examples to the entity doesn't make any sense because a person's name is not a keyword.
So, I would recommend a training strategy which is as follows:
Create various templates of the message like, "My name is XYZ", "I am XYZ", "This is XYZ" etc. (all possible introduction messages you could think of)
Remove all keywords and expressions for the entity you created and add these two keywords:
"a b c d e f g h i j k l m n o p q r s t u v w x y z"
"XYZ" (can give any name but maintain this name same for validating the templates)
In the 'Understanding' tab enter the messages and extract the name into the entity ("contact_name" in your case) and validate them
Similarly, validate all message templates keeping the name as "XYZ"
After you have done this for all templates your bot will be able to recognise any name in a given template of the message
The logic behind this is your entity is a free-text and keyword which means it first tries to match the keyword if not matched it tries to find the word in the same position of the templates. Keeping the name same for validations helps to train the bot with the templates and learn the position where the name will be usually found.
Hope this works. I have tried this and worked for me. I am not sure how bot trains in background. I recommend you to start a new app and do this exercise.
Comment if there is any problem.
wit.ai has a pre-trained entity extraction method called wit/contact, which
Captures free text that's either the name or a clear reference to a
person, like "Paul", "Paul Smith", "my husband", "the dentist".
It works good even without any training data.
To read about the method refer to duckling.
i need to do a SQL simulator on Prolog. i need to simulate some functions like create_table, insert, delete, update_table, select_table, drop_table, show_table, etc. I am learning how to do asserts and retracts but im getting some errors in my first function create_table(N,A) where N is the name of the table and A a list with the atributtes
An example is create_table("student",["name","lastname","age"]). This will create my table named "student" with the atributes ["name","lastname","age"].
I was searching how to work with assert and i see i need to do dynamic before making assert, then my code is.
len([],0).
len([_|T],N) :- len(T,X), N is X+1.
create_table(_, []):-!.
create_table(N, Atributos):- len(Atributos, L), dynamic N/L, assert(N(Atributos)).
But i get this error :7: Syntax error: Operator expected on this line
create_table(N, Atributos):- len(Atributos, L), dynamic N/L, assert(N(Atributos)).
What im doing wrong? excuse me, i dont speak good english.
From the error message, seems you're using SWI-Prolog....
Your code could be (note that len/2 can be replaced by the builtin length/2)
create_table(N, Atributos):-
length(Atributos, L),
dynamic(N/L),
T =.. [N|Atributos], % this missing 'constructor' was the cause of the error message
assert(T). % this is problematic
There is an important 'design' problem: the CREATE TABLE SQL statement works at metadata level.
If you do, for instance,
?- assertz(student('Juan', 'Figueira', 20)).
pretending that the predicate student/3 holds table data, you're overlapping data and metadata
using dynamic/1 and assert is a tricky non-logical aspect of Prolog, and dynamically creating dynamic predicates is really unusual. Fundamentally you cannot have a Prolog query with the predicate name as a variable e.g.
query(N,X) :- N=student, N(X).
My suggestion is you remove a layer of complexity and have one dynamic predicate 'table', and assert your SQL tables as new 'table' clauses i.e.
:- dynamic table/2.
:- assertz(table(student,['Joe','Young',18])).
query(N,X) :- table(N,X).
:- query(student,[Name,Lastname,Age]).
I try to create a simple program in prolog, but i have a problem:
:- dynamic at/2, i_am_holding/1, i_am_at/1.
/* some lines of code */
i_am_at(room1).
at(revolver, room1).
take(revolver) :- write('You picked up the revolver.'),nl.
take(X):- i_am_at(Place),
assert(i_am_holding(X)),
retract(at(X,Place)).
/* some lines of code */
I want the user to pick up the revolver,and then (the revolver)to be retracted from the place where he is in, so he won't be able to pick it up again.
When I run my code, the take(revolver) query runs, but the take(X) does not.
Mark is right on the money. You probably want to replace your whole code with something like this:
:- dynamic at/2, holding/1.
at(player, room1).
at(revolver, room1).
take(X) :-
at(player, Place),
at(X, Place),
!,
format('You pick up the ~a.~n', [X]),
retract(at(X,Place)),
assert(holding(X)).
take(X) :-
holding(X),
!,
format('You''re already holding the ~a!~n', [X]).
There are a lot of interesting ways you could take this further. An operator is_at might make the code more readable:
take(X) :-
player is_at Place,
X is_at Place,
...
You could also have some nice case-based reasoning for getting the articles and whatnot right:
subject(X, Some_X) :- mass_noun(X), !, atom_concat('some ', X, Some_X).
subject(X, The_X) :- atom_concat('the ', X, The_X).
mass_noun(water).
then you could integrate these into the output routines:
take(X) :-
...
subject(X, Subj),
format('You take ~a.~n', [Subj]),
...
You could do some fun stuff with DCGs to generate the output too:
:- use_module(library(dcg/basics)).
success(take(X)) --> "You took ", subject(X).
subject(X) --> "the ", atom(X).
You can make that even more generic with some histrionics like this:
success_term(Command) --> { Command =.. CommandList }, success(CommandList).
success([Command, DirectObject]) -->
"You ", past_tense(Command), " ", subject(DirectObject), ".".
subject(Noun) --> "the ", atom(Noun).
past_tense(X) --> { past_tense(X, Y) }, atom(Y).
past_tense(take, took).
past_tense(X, Xed) :- atom_concat(X, 'ed', Xed).
Then run that like so: phrase(success_term(take(revolver)), X), format('~s~n', [X]) and you'll get You took the revolver., which is kind of neat.
These text adventures are a lot of fun to code. I recommend you go through the Amzi Prolog Nani Search tutorial if you haven't yet. There are a lot of great ideas in there!
I want to compute a list of the terms of the sequence
(14747-40*n)/(2621440*(41-n)), n from 1 to 40
I tried entering the above in Wolfram Alpha, and it plots me a graph of the function. This isn't what I want. I've tried variations on this command, as well as guessing at various keywords to stick before it, and I either get back the same thing, or something unhelpful.
The help page on sequences suggests various things you might do with sequences, but doesn't say how to do something simple like this???
The following works:
Table[(14747-40*n)/(2621440*(41-n)) n, {n, 1, 40}]
Clicking on "approximate form" then on "copy plaintext" gives the following:
{0.000140257, 0.000286924, 0.000440507, 0.000601567, 0.000770728,
0.000948683, 0.00113621, 0.00133417, 0.00154356, 0.00176547,
0.00200115, 0.00225204, 0.00251976, 0.00280618, 0.00311345,
0.00344409, 0.00380101, 0.00418764, 0.00460803, 0.00506701,
0.00557035, 0.00612508, 0.00673974, 0.00742493, 0.00819385,
0.00906326, 0.0100547, 0.0111963, 0.0125257, 0.0140939, 0.0159728,
0.0182658, 0.0211282, 0.0248041, 0.0297003, 0.0365488, 0.0468139,
0.0639122, 0.0980936, 0.200607}