CLIPS Validate Text Entry - validation

Morning, Excuse the silly question but I am busy building a expert system much like the "21 Questions" game that uses questions asked to the user in order to determine the right dog for them. The expert system is coded in CLIPS / .CPS language and one of the requirements I am looking to include is that when the user is asked a yes/no question they are required to input "y" or "n".
In all the resources we have been taught we have only been tough number validation and not a specific character validation and I cannot find any resources that do this either.
This is an example of the number validation I did in order to ensure they input a valid number on one of my questions
(defrule test-integer
(number-in ?number&:(integerp ?number))
=>
(printout t ?number "is valid"
(defrule test-non-int
?number-address <- (number-in ?number&:(not (integerp ?number)))
=>
(printout t ?number " not valid int" crlf)
(retract ?number-address))

This is how you'd do it using rules:
CLIPS>
(defrule test-response
(response-in ?response&y|n)
=>
(printout t ?response " is valid" crlf))
CLIPS>
(defrule test-non-response
?response-address <- (response-in ?response&~y&~n)
=>
(printout t ?response " not valid response" crlf)
(retract ?response-address))
CLIPS> (assert (response-in xyz))
<Fact-1>
CLIPS> (run)
xyz not valid response
CLIPS> (assert (response-in n))
<Fact-2>
CLIPS> (run)
n is valid
CLIPS>
I'd suggest using a function that only accepts correct responses:
CLIPS>
(deffunction ask-question (?question $?allowed-values)
(printout t ?question)
(bind ?answer (read))
(if (lexemep ?answer)
then (bind ?answer (lowcase ?answer)))
(while (not (member ?answer ?allowed-values)) do
(printout t ?question)
(bind ?answer (read))
(if (lexemep ?answer)
then (bind ?answer (lowcase ?answer))))
?answer)
CLIPS> (ask-question "Continue? " y n yes no)
Continue? k
Continue? l
Continue? ye
Continue? YeS
yes
CLIPS>

What i figured out was to link the answer from the one defrule to that of another defrule first to check if the answer was valid and then again if that answer was valid to link it to the correct defrule then that will proceed with the next question.
Code is from my own Expert System:
(defrule Small-CoatType-Full
(Small-Coat f)
(person (name ?name))
=>
(open "result.txt" result "a")
(printout result ?name " Likes Smaller, Fury Dogs" crlf)
(close result)
(printout t "Would you like a low energetic(l) or high energetic(h) breed?" crlf)
(assert (Small-Energy-Level(lowcase(read)))))
(defrule Small-Energy-Level-Wrong
(Small-Energy-Level ?var &~l&~h)
=>
(printout t crlf "Plesae Only Choose (l) or (h)")
(assert (Small-Energy-Level (lowcase(read)))))`

Related

hey i have a problem in this clips expert system code its not printing the result

this is a Diet and Nutrition Expert System i have a problem that i cant print the result to the user after entering the input so can any one help me to make it run correctly?
(defrule read-gender
(initial-fact)
=>
(printout t crlf crlf "Welcome! Diet and Nutrition Expert System" crlf)
(printout t "******************************************" crlf)
(printout t "This output of this program is:" crlf)
(printout t "1. Your Body Mass Index (BMI) and body-status." crlf)
(printout t "2. Recommended daily calories needed based on your body-status." crlf)
(printout t "3. Daily protein needed based on your weight (kgs)." crlf)
(printout t "4. Daily celcium needed based on your age." crlf)
(printout t "5. Daily fiber needed based on your calories needed." crlf)
(printout t "6. Daily carbohydrate needed based on your weight (kgs)." crlf)
(printout t "******************************************" crlf crlf)
(printout t "What is your gender (Female/Male) *case-sensitive*:")
(assert (gender (read))))
(defrule read-age
(gender ?)
=>
(printout t "Please enter your age:")
(assert (age (read))))
(defrule read-height
(gender ?)
=>
(printout t "Please enter your height:")
(assert (height (read))))
(defrule read-weight
(gender ?)
=>
(printout t "Please enter your weight in(KGs):")
(assert (weight (read))))
(defrule read-activity-days
(gender ?)
=>
(printout t "How many day do you exercise for a week:")
(assert (activity-days (read))))
(defrule set-activity-rate-sedentary
(activity-days ?days)
(test (< ?days 2))
=>
(assert (activity-rate "Sedentary"))
(assert (activity-factor 1.2)))
(defrule set-activity-rate-moderate
(activity-days ?days)
(test (and (>= ?days 2) (< ?days 5)))
=>
(assert (activity-rate "Moderate"))
(assert (activity-factor 1.55)))
(defrule set-activity-rate-hard
(activity-days ?days)
(test (>= ?days 5))
=>
(assert (activity-rate "Hard"))
(assert (activity-factor 1.75)))
(defrule calculate-bmi
(weight ?weight)
(height ?height)
=>
(bind ?bmi (* ?weight (/ ?height ?height)))
(assert (bmi ?bmi)))
(defrule set-body-status-underweight
(bmi ?bmi)
(test (< ?bmi 18.5))
=>
(assert (body-status "Underweight")))
(defrule set-body-status-normal-weight
(bmi ?bmi)
(test (and (>= ?bmi 18.5) (< ?bmi 24.9)))
=>
(assert (body-status "Normal-weight")))
(defrule set-body-status-overweight
(bmi ?bmi)
(test (and (>= ?bmi 24.9) (< ?bmi 29.9)))
=>
(assert (body-status "Overweight")))
(defrule calculate-daily-calories-female
(gender "Female")
(activity-factor ?activity-factor)
(weight ?weight)
(age ?age)
(height ?height)
=>
(bind ?bmr (* 655.1 (+ (* 9.563 ?weight) (* 1.85 ?height) (* 4.676 ?age))))
(bind ?daily-calories (* ?bmr ?activity-factor))
(assert (daily-calories ?daily-calories)))
(defrule calculate-daily-calories-male
(gender "Male")
(activity-factor ?activity-factor)
(weight ?weight)
(age ?age)
(height ?height)
=>
(bind ?bmr (* 66.5 (+ (* 13.75 ?weight) (* 5.003 ?height) (* 6.755 ?age))))
(bind ?daily-calories (* ?bmr ?activity-factor))
(assert (daily-calories ?daily-calories)))
(defrule set-daily-calcium-baby
(age ?age)
(test (< ?age 4))
=>
(assert (daily-calcium "210-270mg")))
(defrule set-daily-calcium-child
(age ?age)
(test (and (>= ?age 4) (< ?age 9)))
=>
(assert (daily-calcium "350-450mg")))
(defrule set-daily-calcium-teen
(age ?age)
(test (and (>= ?age 9) (< ?age 19)))
=>
(assert (daily-calcium "800mg")))
(defrule set-daily-calcium-adult
(age ?age)
(test (and (>= ?age 19) (< ?age 51)))
=>
(assert (daily-calcium "1000mg")))
(defrule set-daily-calcium-old
(age ?age)
(test (>= ?age 51))
=>
(assert (daily-calcium "1200mg")))
(defrule calculate-daily-protein-sedentary
(weight ?weight)
(activity-rate "Sedentary")
=>
(bind ?daily-protein (* ?weight 0.8))
(assert (daily-protein ?daily-protein)))
(defrule calculate-daily-protein-moderate
(weight ?weight)
(activity-rate "Moderate")
=>
(bind ?daily-protein (* ?weight 1))
(assert (daily-protein ?daily-protein)))
(defrule calculate-daily-protein-hard
(weight ?weight)
(activity-rate "Hard")
=>
(bind ?daily-protein (* ?weight 1.2))
(assert (daily-protein ?daily-protein)))
(defrule calculate-daily-carbohydrates
(weight ?weight)
=>
(bind ?daily-carbohydrates (* ?weight 2.5))
(assert (daily-carbohydrates ?daily-carbohydrates)))
(defrule protein-advice
(protein-needed ?p)
=>
(printout t crlf crlf" ######## Result ######## " crlf)
(printout t " 1. You need " ?p "g of protein per day." crlf))
(defrule carbohydrate-advice
(carbohydrate-needed ?c)
=>
(printout t " 3. You need " ?c "g of carbohydrate per day." crlf))
(defrule fiber-advice
(fiber-needed ?f)
=>
(printout t " 2. You need " ?f "g of fiber per day." crlf))
(defrule calcium-advice
(calcium-needed ?c)
=>
(printout t " 4. You need " ?c "g of calcium per day." crlf))
(defrule calories-advice-underweight
(body-status underweight)
(calories-needed ?c)
(bmi ?bm)
(body-status ?b)
(carbohydrate-needed ?ca)
(calcium-needed ?ce)
=>
(printout t "
5. Your Body Mass Index (BMI) is " ?bm " (" ?b "), "crlf "
6. You
need " ?c " calories per day. "crlf "
7. For advice from the experts, You may need extra
daily 300 calories (" (+ 300 ?c)") to gain 0.25kg/week." crlf crlf))
(defrule calories-advice-normalweight
(body-status normal-weight)
(calories-needed ?c)
(bmi ?bm)
(body-status ?b)
(carbohydrate-needed ?ca)
(calcium-needed ?ce)
=>
(printout t " 5. Your Body Mass Index (BMI) is " ?bm " (" ?b ")," crlf " 6. You
need " ?c " calories per day to maintain your healthy weight." crlf crlf))
(defrule calories-advice-overweight
(body-status overweight)
(calories-needed ?c)
(bmi ?bm)
(body-status ?b)
(carbohydrate-needed ?ca)
(calcium-needed ?ce)
=>
(printout t " 5. Your Body Mass Index (BMI) is " ?bm " (" ?b ")," crlf " 6. You need " ?c " calories per day. " crlf " 7. For advice from the experts, You may need to reduce your daily calories needed by 300 to " (- ?c 300)))
(defrule calories-advice-obesity
(body-status obesity)
(calories-needed ?c)
(bmi ?bm)
(body-status ?b)
(carbohydrate-needed ?ca)
(calcium-needed ?ce)
=>
(printout t " 5. Your Body Mass Index (BMI) is " ?bm " (" ?b "), "crlf " 6. You
need " ?c " calories per day. "crlf " 7. For advice from the experts, You may need to reduce
your daily calories needed by 500 to (" (- ?c 300)") to loss 0.5kg/week." crlf crlf))
I tried to rewrite the code in different ways but its still working correctly but without any result so can any one please help me to rewrite it correctly?
Don't use an initial-fact pattern in your rules. The initial-fact is
no longer supported in CLIPS 6.4. Just leave the conditions of the
rule empty and it will work in both version 6.3 and 6.4.
The protein-advice defrule expects a protein-needed fact but a
daily-protein fact is asserted by your other rules.
The carbohydrate-advice defrule expects a carbohydrate-needed fact but a daily-carbohydrates fact is asserted by your other rules.
The fiber-advice defrule expects a fiber-needed fact but no fiber
related facts are asserted by any of your rules.
The calcium-advice defrule expects a calcium-needed fact but a daily-calcium fact is asserted by your other rules.
Your other rules that print results have similar issues.

Expert System in Clips doesn't work

In my expert system user must check Developer and Price after he'll see notebook which is suitable for this parameters.
For example with this parameters (on screenshot) I must have result: Model: Noteebok1
But I don't see anything. Where is a problem or bug?
CLP File Code:
(defglobal ?*s* = 0)
(deftemplate Notebook
(slot pModel)
(slot pDeveloper)
(slot pPrice))
;*******************************************************************
(deffunction QuestionOf(?TextQuestion $?variations)
(printout t ?TextQuestion)
(bind ?Answer (read))
(if (lexemep ?Answer)
then (bind ?Answer (lowcase ?Answer)))
(while (not (member ?Answer ?variations)) do
(printout t ?TextQuestion)
(bind ?Answer (read))
(if (lexemep ?Answer)
then (bind ?Answer (lowcase ?Answer))))
?Answer)
;********************************************************************'
(defrule banner
(declare (salience 10))
=>(load-facts D:\fact.txt)
(printout t crlf crlf)
(printout t "Expert system. Nout search")
(printout t crlf crlf))
;******************************************************************'
(defrule QuestionDeveloper
(not (Developer ?))
=>(bind ?asssert(QuestionOf "Check Developer (a-HP,b-Samsung,c-Apple,d-IDontKnow)" a b c d))
(if (eq ?asssert a)then (assert (Developer HP)))
(if (eq ?asssert b)then (assert (Developer Samsung)))
(if (eq ?asssert c)then (assert (Developer Apple)))
(if (eq ?asssert d)then (assert (Developer IDontKnow))))
;******************************************************************'
(defrule QuestionPrice
(not (Price ?))
=>(bind ?asssert(QuestionOf "Price?(a-300,b-400,c-500,d-IDontKnow)" a b c d))
(if (eq ?asssert a)then (assert (Price 300)))
(if (eq ?asssert b)then (assert (Price 400)))
(if (eq ?asssert c)then (assert (Price 500)))
(if (eq ?asssert d)then (assert (Price IDontKnow))))
;******************************************************************'
(defrule Vyvod
(or (Developer ?xDeveloper)(Developer IDontKnow))
(or (Price ?xPrice)(Price IDontKnow))
(Notebook(pModel ?Model)(pDeveloper ?xDeveloper)(pPrice ?xPrice))
=>(bind ?*s*(+ ?*s* 1))
(printout t crlf " " ?*s* ". Model : " ?Model crlf))
;******************************************************************'
Fact.txt:
(Notebook(pModel Notebook1)(pDeveloper HP)(pPrice 500))
(Notebook(pModel Notebook2)(pDeveloper Samsung)(pPrice 400))
(Notebook(pModel Notebook3)(pDeveloper Apple)(pPrice 500))
The facts from the file fact.txt are not being loaded. Check that the file is at the specified path and that you have read access.

Incrementing a global variable within a user answered defrule

I'm trying to increment a defglobal variable (symcount) by 1 if the user defines that they have pain by using the (read) function
(defrule QPain
(initial-fact)
=>
(printout t "Are You In Pain? " crlf)
(bind (ans Answer) (read))
)
(defrule AnsInc
(Answ Answer = "y")
=>
(bind ?*symcount* (+ ?*symcount* 1)))
the increment must only happen of the user presses "y"
otherwise the increment must not happen.
CLIPS> (defglobal ?*symcount* = 0)
CLIPS>
(defrule QPain
=>
(printout t "Are You In Pain? ")
(bind ?answer (read))
(if (eq ?answer y)
then
(bind ?*symcount* (+ ?*symcount* 1))))
CLIPS> (reset)
CLIPS> (run)
Are You In Pain? y
CLIPS> ?*symcount*
1
CLIPS> (reset)
CLIPS> (run)
Are You In Pain? n
CLIPS> ?*symcount*
0
CLIPS>

Get back to above rule in clips

when I try to call a defrule that have been used already, clips stop..
some defrule need to be used more than one time, is there any way to do it
here is an example
(
defrule choice-in-powerPlant2
(powerPlant2-question)
=>
(printout t "Are Filter and Carburetor Air working fine(y/n)?" crlf)
(bind ?response (check-YNoptions-input)); Get user input on type of questions
(if (eq ?response y)
then
(assert (powerPlant1-question)
)
)
(if (or(eq ?response q) (eq ?response Q))
then
(output-exitmessage)
)
(if (eq ?response n)
then
(printout t "Have you fixed this(y/n)?" crlf)
(bind ?response (check-YNoptions-input)); Get user input on type of questions
(if (eq ?response y)
then
(assert (powerPlant1-question)
)
)
(if (eq ?response n)
then
(printout req "Please replace Filter and Carburetor Air " crlf)
(assert (powerPlant3-question))
)
)
)
in rule 2
I want to go back to rule 1 when I enter "y"=yes
" running stopped once I enterd "y" "
If you want to retrigger a rule that matches a specific fact, retract that fact as part of the rule action. If another rule then asserts that specific fact, the rule will be retriggered. For example:
(defrule choice-in-powerPlant2
?f <- (powerPlant2-question)
=>
(retract ?f)
(printout t "Are Filter and Carburetor Air working fine(y/n)?" crlf)
.
.
.
)

clips [EXPRNPSR3] Missing function declaration for person

; template person
(deftemplate person
(slot name (type STRING))
(slot gender (type SYMBOL)(allowed-symbols m f)); male, female
(slot birthyear (type INTEGER))
(slot birthPlace(type STRING))
(slot Fname (type STRING))
(slot Mname (type STRING))
(multislot siblingsName (type STRING))
(slot spouse (type STRING))
(slot height (type INTEGER))
(slot weight (type INTEGER))
(slot hairColor (type STRING))
(slot eyeColor (type STRING))
(multislot oddHabits (type STRING))
)
; menu
(defrule menu
(declare (salience 9000))
(initial-fact)
=>
(printout t crlf
"Menu : " crlf
" 1- Infer family relations " crlf
" 2- Add additional members " crlf
" 3- Modify properties of already existing members " crlf
" 4- List properties of a specific individual by name or reference. " crlf
" 5- Find for all individuals matching a certain property. " crlf
" 6- Find all individuals matching two properties. " crlf
" 7- Display family relations (same like 1) along with their height comparison." crlf
" 8- exit the program" crlf
"Choose 1 - 8 -> "
)
(assert (task type =(read)))
)
; exit
(defrule Exit
(task type 8)
=>
(exit)
)
(defrule AddMember
(task type 2)
=>
(printout t "Enter Name" crlf)
(bind ?name (read))
(printout t "Enter gender" crlf)
(bind ?G (read))
(printout t "Enter birth year" crlf)
(bind ?BY(read))
(printout t "Enter birth place" crlf)
(bind ?BP(read))
(printout t "Enter Father name " crlf)
(bind ?FN (read))
(printout t "Enter Mother name" crlf)
(bind ?MN(read))
(printout t "Enter siblings" crlf)
(bind ?SI(readline))
(printout t "Enter spouse" crlf)
(bind ?SP (read))
(printout t "Enter height" crlf)
(bind ?H (read))
(assert
(person
(name ?name)(gender ?G)(birthyear ?BY)(birthPlace ?BP)(Fname ?FN)(Mname ?MN)(siblingsName ?SI )(spouse ?SP) (height ?H))
)
)
(defrule Modify
(task type 3)
=>
(printout t " (a) to modify gender" crlf)
(printout t " (b) to modify Birth Year" crlf)
(printout t " (c) to modify Birth Place" crlf)
(printout t " (d) to modify Father Name" crlf)
(printout t " (e) to modify Mother Name" crlf)
(printout t " (f) to modify Spouse" crlf)
(printout t " (g) to modify height" crlf)
(printout t " (h) to modify weight" crlf)
(assert (task type =(read)))
)
(defrule ModifyGender
(task type a)
=>
(printout t "Enter the name of person that you want to modify" crlf)
(bind ?n (read))
(printout t " Enter new value" crlf)
(bind ?V (read))
?num <- (person (name ?n))
(printout t " num is " ?num " " crlf)
(modify ?num (gender ?V))
)
When loading the file of my project an error shows up:
[EXPRNPSR3] Missing function declaration for person.
Error:
(defrule MAIN::ModifyGender
(task type a)
=>
(printout t "Enter the name of person that you want to modify" crlf)
(bind ?n (read))
(printout t " Enter new value" crlf)
(bind ?V (read))
?num
<-
Can anyone help me?
Patterns matching facts are only allowed in the condition portion of a rule, not in the actions of the rule. You can either use multiple rules to determine which person to change and to apply the change:
(defrule ModifyGender-ask
?f <- (task type a)
=>
(retract ?f)
(printout t "Enter the name of person that you want to modify" crlf)
(bind ?n (read))
(printout t " Enter new value" crlf)
(bind ?V (read))
(assert (modify-gender ?n ?V)))
(defrule ModifyGender-apply
?f <- (modify-gender ?n ?v)
?num <- (person (name ?n))
=>
(retract ?f)
(modify ?num (gender ?v)))
(defrule ModifyGender-don't-apply
?f <- (modify-gender ?n ?v)
(not (person (name ?n)))
=>
(retract ?f))
Or you can use the fact-set query functions to locate and change the person from the actions of the rule:
(defrule ModifyGender
?f <- (task type a)
=>
(retract ?f)
(printout t "Enter the name of person that you want to modify" crlf)
(bind ?n (read))
(printout t " Enter new value" crlf)
(bind ?V (read))
(if (any-factp ((?p person)) (eq ?p:name ?n))
then
(do-for-fact ((?p person)) (eq ?p:name ?n)
(modify ?p (gender ?V)))
else
(printout t "Person " ?n " does not exist." crlf)))

Resources