Removed the overwrite of the pointer slot

It was causing segmentation faults to occur

;------------------------------------------------------------------------------
;Copyright (c) 2012, Joshua Scoggins
;All rights reserved.
;
;Redistribution and use in source and binary forms, with or without
;modification, are permitted provided that the following conditions are met:
;    * Redistributions of source code must retain the above copyright
;      notice, this list of conditions and the following disclaimer.
;    * Redistributions in binary form must reproduce the above copyright
;      notice, this list of conditions and the following disclaimer in the
;      documentation and/or other materials provided with the distribution.
;    * Neither the name of Joshua Scoggins nor the
;      names of its contributors may be used to endorse or promote products
;      derived from this software without specific prior written permission.
;
;THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
;ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
;WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
;DISCLAIMED. IN NO EVENT SHALL Joshua Scoggins BE LIABLE FOR ANY
;DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
;(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
;LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
;ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
;(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
;SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;------------------------------------------------------------------------------
; Environment.clp - A wrapper over a CLIPS environment
;------------------------------------------------------------------------------
(defclass core::Environment
 "A wrapper over a clips environment"
 (is-a Object InteropObject))
 ;(role concrete)
 ;(slot pointer (source composite) (access initialize-only)
 ; (visibility public)))

(defmessage-handler core::Environment init around ()
 (call-next-handler)
 (if (eq ?self:pointer 0) then
  (bind ?self:pointer (env-create))))

(defmessage-handler core::Environment destroy primary ()
                    (if (not (is-currently-executing-environment ?self:pointer)) then
                      (env-destroy ?self:pointer)
                      (return (delete-instance))
                      else
                      (printout
                        werror
                        "ERROR: attempted to destroy the executing environment."
                        crlf)
                      (return FALSE)))

(defmessage-handler core::Environment is-currently-executing-environment primary ()
                    (return (is-currently-executing-environment ?self:pointer)))

(defmessage-handler core::Environment run ($?count)
                    (bind ?size (length$ $?count))
                    (if (= 0 ?size) then
                      (if (is-currently-executing-environment ?self:pointer) then
                        (run)
                        else
                        (env-run ?self:pointer))
                      else
                      (bind ?num (nth$ 1 ?count))
                      (if (and (> ?num 0) (integerp ?num)) then
                        (if (is-currently-executing-environment ?self:pointer) then
                          (run ?num)
                          else
                          (env-run ?self:pointer ?num))
                        else
                        (printout werror "ERROR: invalid count provided." crlf))))

(defmessage-handler core::Environment eval (?string)
                    (if (stringp ?string) then
                      (if (is-currently-executing-environment ?self:pointer) then
                        (eval ?string)
                        else
                        (env-eval ?self:pointer ?string))
                      else
                      (printout werror "ERROR: string expected" crlf)))

(defmessage-handler core::Environment build (?string)
                    (if (stringp ?string) then
                      (if (is-currently-executing-environment ?self:pointer) then
                        (build ?string)
                        else
                        (env-build ?self:pointer ?string))
                      else
                      (printout werror "ERROR: string expected" crlf)))

(defmessage-handler core::Environment facts ()
                    (if (is-currently-executing-environment ?self:pointer) then
                      (facts)
                      else
                      (env-facts ?self:pointer)))
(defmessage-handler core::Environment instances ()
                    (if (is-currently-executing-environment ?self:pointer) then
                      (instances)
                      else
                      (env-instances ?self:pointer)))

(defmessage-handler core::Environment rules ()
                    (if (is-currently-executing-environment ?self:pointer) then
                      (rules)
                      else
                      (env-rules ?self:pointer)))

(defmessage-handler core::Environment assert ($?elements)
                    (bind ?length (length$ ?elements))
                    (if (= 0 ?length) then
                      (printout werror "ERROR: No arguments provided" crlf)
                      else
                      (env-assert-string ?self:pointer
							  (implode$ $?elements))))

;------------------------------------------------------------------------------
;Copyright (c) 2012, Joshua Scoggins
;All rights reserved.
;
;Redistribution and use in source and binary forms, with or without
;modification, are permitted provided that the following conditions are met:
;    * Redistributions of source code must retain the above copyright
;      notice, this list of conditions and the following disclaimer.
;    * Redistributions in binary form must reproduce the above copyright
;      notice, this list of conditions and the following disclaimer in the
;      documentation and/or other materials provided with the distribution.
;    * Neither the name of Joshua Scoggins nor the
;      names of its contributors may be used to endorse or promote products
;      derived from this software without specific prior written permission.
;
;THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
;ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
;WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
;DISCLAIMED. IN NO EVENT SHALL Joshua Scoggins BE LIABLE FOR ANY
;DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
;(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
;LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
;ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
;(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
;SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;------------------------------------------------------------------------------
; Environment.clp - A wrapper over a CLIPS environment
;------------------------------------------------------------------------------
(defclass core::Environment
 "A wrapper over a clips environment"
 (is-a Object InteropObject)
 (role concrete)
 (slot pointer (source composite) (access initialize-only)
  (visibility public) (range 0 0) (default-dynamic 0)))

(defmessage-handler core::Environment init around ()
 (call-next-handler)
 (if (eq ?self:pointer 0) then
  (bind ?self:pointer (env-create))))

(defmessage-handler core::Environment destroy primary ()
                    (if (not (is-currently-executing-environment ?self:pointer)) then
                      (env-destroy ?self:pointer)
                      (return (delete-instance))
                      else
                      (printout
                        werror
                        "ERROR: attempted to destroy the executing environment."
                        crlf)
                      (return FALSE)))

(defmessage-handler core::Environment is-currently-executing-environment primary ()
                    (return (is-currently-executing-environment ?self:pointer)))

(defmessage-handler core::Environment run ($?count)
                    (bind ?size (length$ $?count))
                    (if (= 0 ?size) then
                      (if (is-currently-executing-environment ?self:pointer) then
                        (run)
                        else
                        (env-run ?self:pointer))
                      else
                      (bind ?num (nth$ 1 ?count))
                      (if (and (> ?num 0) (integerp ?num)) then
                        (if (is-currently-executing-environment ?self:pointer) then
                          (run ?num)
                          else
                          (env-run ?self:pointer ?num))
                        else
                        (printout werror "ERROR: invalid count provided." crlf))))

(defmessage-handler core::Environment eval (?string)
                    (if (stringp ?string) then
                      (if (is-currently-executing-environment ?self:pointer) then
                        (eval ?string)
                        else
                        (env-eval ?self:pointer ?string))
                      else
                      (printout werror "ERROR: string expected" crlf)))

(defmessage-handler core::Environment build (?string)
                    (if (stringp ?string) then
                      (if (is-currently-executing-environment ?self:pointer) then
                        (build ?string)
                        else
                        (env-build ?self:pointer ?string))
                      else
                      (printout werror "ERROR: string expected" crlf)))

(defmessage-handler core::Environment facts ()
                    (if (is-currently-executing-environment ?self:pointer) then
                      (facts)
                      else
                      (env-facts ?self:pointer)))
(defmessage-handler core::Environment instances ()
                    (if (is-currently-executing-environment ?self:pointer) then
                      (instances)
                      else
                      (env-instances ?self:pointer)))

(defmessage-handler core::Environment rules ()
                    (if (is-currently-executing-environment ?self:pointer) then
                      (rules)
                      else
                      (env-rules ?self:pointer)))

(defmessage-handler core::Environment assert ($?elements)
                    (bind ?length (length$ ?elements))
                    (if (= 0 ?length) then
                      (printout werror "ERROR: No arguments provided" crlf)
                      else
                      (env-assert-string ?self:pointer
							  (implode$ $?elements))))


update clips

update clips

;;***********************
;;* BEER QUESTION RULES *
;;***********************

; random questions for user type and scenario recognition

(defrule determine-preferred-carbonation
   (declare (salience ?*very-high-priority*))
   (start)
   =>
   (assert (UI-state (display "Do you generally prefer to drink low, medium or high carbonated drinks? 🍾")
                     (relation-asserted preferred-carbonation)
                     (valid-answers low medium high))))

(defrule determine-whether-he-is-a-regular-beer-drinker
   (declare (salience ?*very-high-priority*))
   (start)
   =>
   (assert (UI-state (display "Are you a regular beer drinker? 🍺")
                     (relation-asserted regular-beer-drinker)
                     (valid-answers yes no))))

(defrule determine-preferred-color
   (declare (salience ?*very-high-priority*))
   (regular-beer-drinker yes)
   =>
   (assert (UI-state (display "Do you generally prefer pale, amber, brown or dark beer? 🍺")
                     (relation-asserted preferred-color)
                     (valid-answers pale amber brown dark))))

(defrule determine-preferred-fermentation
   (declare (salience ?*very-high-priority*))
   (regular-beer-drinker yes)
   =>
   (assert (UI-state (display "Do you generally prefer to drink top, bottom or wild fermented beer?")
                     (relation-asserted preferred-fermentation)
                     (valid-answers top bottom wild))))

(defrule determine-whether-he-eats-fermented-foods
   (declare (salience ?*very-high-priority*))
   (start)
   =>
   (assert (UI-state (display "Do you generally eat fermented foods (probiotic yogurt, kefir, kombucha)? 🍶")
                     (relation-asserted fermented-foods-eater)
                     (valid-answers yes no))))

(defrule determine-whether-he-should-drive
   (declare (salience ?*very-high-priority*))
   (start)
   =>
   (assert (UI-state (display "Do you have to drive? 🚘")
                     (relation-asserted driver)
                     (valid-answers yes no))))

(defrule determine-preferred-alcohol
   (declare (salience ?*very-high-priority*))
   (driver no)
   =>
   (assert (UI-state (display "Do you generally prefer to drink low, mild, high or very high alcoholic drinks? 🍹")
                     (relation-asserted preferred-alcohol)
                     (valid-answers low mild high "very high"))))

(defrule determine-whether-he-should-smoke-a-cigar
   (declare (salience ?*very-high-priority*))
   (start)
   =>
   (assert (UI-state (display "Do you have to smoke a cigar? If yes, is the cigar claro, maduro or oscuro? 🚬")
                     (relation-asserted which-cigar)
                     (valid-answers claro maduro oscuro no))))

(defrule determine-preferred-flavor
   (declare (salience ?*very-high-priority*))
   (start)
   =>
   (assert (UI-state (display "What kind of flavor do you generally prefer?")
                     (relation-asserted preferred-flavor)
                     (valid-answers clean sweet bitter roasty fruity spicy sour "don't know"))))

; depth questions for meal type recognition

(defrule determine-food-style
   (start)
   =>
   (assert (UI-state (display "Are you vegetarian, vegan or omnivorous?")
                     (relation-asserted food-style)
                     (valid-answers vegetarian vegan omnivorous))))

(defrule determine-main-meal-for-omnivorous-or-vegetarian
   (or (food-style omnivorous)
       (food-style vegetarian))
   =>
   (assert (UI-state (display "Is the main meal pizza, entrée, cheese or dessert? 🧀")
                     (relation-asserted main-meal-for-omnivorous-or-vegetarian)
                     (valid-answers pizza entrée cheese dessert other))))

(defrule determine-main-meal-for-vegan
   (food-style vegan)
   =>
   (assert (UI-state (display "Is the main meal pizza, entrée or dessert?")
                     (relation-asserted main-meal-for-vegan)
                     (valid-answers pizza entrée dessert other))))

   ; ... if main meal is cheese

(defrule determine-which-cheese-style
   (main-meal-for-omnivorous-or-vegetarian cheese)
   =>
   (assert (UI-state (display (str-cat "Is the cheese style fresh (Mascarpone, Ricotta, Chèvre, Feta, Cream Cheese, "
                                       "Quark, Cottage), semi-soft (Colby, Fontina, Havarti, Monterey Jack), firm/hard "
                                       "(Gouda, Cheddar, Swiss, Parmesan), blue (Roquefort, Gorgonzola, Danish), "
                                       "natural rind (Brie, Camembert, Triple Crème, Mimolette, Stilton, Lancashire, "
                                       "Tomme de Savoie) or washed rind (Epoisses, Livarot, Taleggio)? 🧀"))
                     (help (format nil "%s %n%s %n%s %n%s %n%s %n%s"
                                       (str-cat "🧀 Fresh cheeses have not been aged, or are very slightly cured. These "
                                                "cheeses have a high moisture content and are usually mild and have a "
                                                "very creamy taste and soft texture.")
                                       (str-cat "🧀 [Semi-soft](goo.gl/izu1Bw) cheeses have a smooth, generally, creamy "
                                                "interior with little or no rind. These cheeses are generally high in "
                                                "moisture content and range from very mild in flavor to very pungent.")
                                       (str-cat "🧀 [Firm/hard](goo.gl/yrfoJK) cheeses have a taste profiles range from "
                                                "very mild to sharp and pungent. They generally have a texture profile "
                                                "that ranges from elastic, at room temperature, to the hard cheeses that "
                                                "can be grated.")
                                       (str-cat "🧀 [Blue](goo.gl/9KkNww) cheeses have a distinctive blue/green veining, "
                                                "created when the penicillium roqueforti mold, added during the make "
                                                "process, is exposed to air. This mold provides a distinct flavor to the "
                                                "cheese, which ranges from fairly mild to assertive and pungent.")
                                       (str-cat "🧀 [Natural rind](goo.gl/ys8pkz) cheeses have rinds that are "
                                                "self-formed during the aging process. Generally, no molds or microflora "
                                                "are added, nor is washing used to create the exterior rinds, and those "
                                                "that do exhibit molds and microflora in their rinds get them naturally "
                                                "from the environment.")
                                       (str-cat "🧀 [Washed rind](goo.gl/Kh3BwD) cheeses are surface-ripened by washing "
                                                "the cheese throughout the ripening/aging process with brine, beer, "
                                                "wine, brandy, or a mixture of ingredients, which encourages the growth "
                                                "of bacteria. The exterior rind of washed rind cheeses may vary from "
                                                "bright orange to brown, with flavor and aroma profiles that are quite "
                                                "pungent, yet the interior of these cheeses is most often semi-soft "
                                                "and, sometimes, very creamy.")))
                     (why (format nil "%s %n%s %n%s %n%s %n%s %n%s"
                                      (str-cat "🧀 Fresh cheeses are light cheeses which pair excellently with the "
                                               "softer flavors of Wheat and Lambic beers.")
                                      (str-cat "🧀 [Semi-soft](goo.gl/izu1Bw) cheeses can be paired with many different "
                                               "craft beers, such as German Kölsch or Bock and Pale Ale beers.")
                                      (str-cat "🧀 [Firm/hard](goo.gl/yrfoJK) cheeses are easily paried with an equally "
                                               "broad range of craft beer styles, such as Pilsner, Bock, Brown Ale and "
                                               "Imperial Stout.")
                                      (str-cat "🧀 [Blue](goo.gl/9KkNww) are stronger-flavored cheeses which are most "
                                               "successfully balanced with stonger-flavored bolder beers like IPAs or "
                                               "Imperial IPAs.")
                                      (str-cat "🧀 [Natural rind](goo.gl/ys8pkz) cheeses include Tomme de Savoie styles "
                                               "which pair well with Golden Ales or Blondes. Traditional British-style "
                                               "ales work well with English-style natural rind cheeses, such as "
                                               "Lancashire and Stilton.")
                                      (str-cat "🧀 [Washed rind](goo.gl/Kh3BwD) itself, while potentially pungent, is "
                                               "often creamy. Pair Belgian-styles ales, like Triples and Golden Strong "
                                               "ales with these varieties.")))
                     (relation-asserted which-cheese-style)
                     (valid-answers fresh semi-soft firm/hard blue "natural rind" "washed rind" "don't know"))))

(defrule determine-which-fresh-cheese
   (which-cheese-style fresh)
   =>
   (assert (UI-state (display "Is the fresh cheese Mascarpone, Ricotta, Chèvre, Feta, Cream Cheese or other? 🧀")
                     (why (str-cat "🧀 Italian-Style Mascarpone, Ricotta and soft Chèvre will match the delicate notes "
                                   "of the beer and neither will overwhelm the palate in the beginning of a meal."))
                     (relation-asserted which-fresh-cheese)
                     (valid-answers Mascarpone Ricotta Chèvre Feta "Cream Cheese" other))))

(defrule determine-whether-he-should-eat-Mascarpone-with-fruit
   (which-fresh-cheese Mascarpone)
   =>
   (assert (UI-state (display "Do you have to eat Mascarpone with fruit?")
                     (relation-asserted mascarpone-with-fruit)
                     (valid-answers yes no))))

(defrule determine-which-semi-soft-cheese
   (which-cheese-style semi-soft)
   =>
   (assert (UI-state (display "Is the semi-soft cheese Colby, Havarti, Monterey Jack or other? 🧀")
                     (why (str-cat "🧀 Fontina, Havarti and milder blue cheeses can be enhanced by the carbonation of "
                                   "Kölsch style ales. The gentle notes of grass in the cheese can be brought out by "
                                   "using the malt of a Bock or the hops of a Pale Ale."))
                     (relation-asserted which-semi-soft-cheese)
                     (valid-answers Colby Havarti "Monterey Jack" other))))

(defrule determine-which-firm/hard-cheese
   (which-cheese-style firm/hard)
   =>
   (assert (UI-state (display "Is the firm/hard cheese Gouda, Cheddar, Swiss, Parmesan or other? 🧀")
                     (why (str-cat "🧀 Cheddar and Swiss cheeses can mimic the Maillard reaction when paired with a beer "
                                   "style, such as a Brown Ale. Roasty stouts can add a creaminess to the firm and hard "
                                   "cheeses on the palate."))
                     (relation-asserted which-firm/hard-cheese)
                     (valid-answers Gouda Cheddar Swiss Parmesan other))))

(defrule determine-which-type-of-Gouda
   (which-firm/hard-cheese Gouda)
   =>
   (assert (UI-state (display "Is the Gouda cheese aged, smoked or other? 🧀")
                     (relation-asserted which-type-of-Gouda)
                     (valid-answers aged smoked other))))

(defrule determine-which-color-of-Cheddar
   (which-firm/hard-cheese Cheddar)
   =>
   (assert (UI-state (display "Is the Cheddar cheese white or yellow? 🧀")
                     (relation-asserted which-color-of-Cheddar)
                     (valid-answers white yellow))))

(defrule determine-which-Cheddar-seasoning
   (which-firm/hard-cheese Cheddar)
   =>
   (assert (UI-state (display "Is the Cheddar cheese seasoning mild, medium, aged or other? 🧀")
                     (relation-asserted which-Cheddar-seasoning)
                     (valid-answers mild medium aged other))))

(defrule determine-if-Cheddar-is-sharp
   (or (which-Cheddar-seasoning medium)
       (which-Cheddar-seasoning aged))
   =>
   (assert (UI-state (display "Is the Cheddar cheese sharp? 🧀")
                     (relation-asserted Cheddar-is-sharp)
                     (valid-answers yes no "don't know"))))

(defrule determine-which-type-of-Swiss
   (which-firm/hard-cheese Swiss)
   =>
   (assert (UI-state (display "Is the Swiss cheese Emmental, Gruyère or other? 🧀")
                     (why (str-cat "🧀 Emmentaler-style cheeses can mimic the Maillard reaction when paired with a beer "
                                   "style, such as a Brown Ale."))
                     (relation-asserted which-type-of-Swiss)
                     (valid-answers Emmental Gruyère other))))

(defrule determine-which-blue-cheese
   (which-cheese-style blue)
   =>
   (assert (UI-state (display (str-cat "Is the blue cheese Stilton or other? 🧀"))
                     (why "🧀 Stilton cheese can be intensified the sweetness on the palate with a Barley Wine.")
                     (relation-asserted which-blue-cheese)
                     (valid-answers Stilton other))))

(defrule determine-which-natural-rind-cheese
   (which-cheese-style "natural rind")
   =>
   (assert (UI-state (display (str-cat "Is the natural rind cheese Brie, Camembert, Triple Crème, Mimolette, Stilton, "
                                       "or other? 🧀"))
                     (why (str-cat "🧀 Lancashire, Stilton, Brie and Camembert all share a rich creamy base that can be "
                                   "refreshed with a Golden, Blond or Pale Ale or intensified the sweetness on the "
                                   "palate with a Barley Wine."))
                     (relation-asserted which-natural-rind-cheese)
                     (valid-answers Brie Camembert "Triple Crème" Mimolette Stilton other))))

(defrule determine-which-washed-rind-cheese
   (which-cheese-style "washed rind")
   =>
   (assert (UI-state (display "Is the washed rind cheese Taleggio or other? 🧀")
                     (why (str-cat "🧀 Classic Belgian yeast flavors spur a tighter carbonation as well as bring out "
                                   "delicate sweet notes that can cut through the funk of a washed rind cheeses."))
                     (relation-asserted which-washed-rind-cheese)
                     (valid-answers Taleggio other))))

   ; ... if main meal is entrée

(defrule determine-which-entrée-omnivorous
   (food-style omnivorous)
   (main-meal-for-omnivorous-or-vegetarian entrée)
   =>
   (assert (UI-state (display (str-cat "Is the main component of the entrée grain (farro, arborio, wild rice, polenta), "
                                       "legumes (lentils, fava, chickpea, green beans), fish, meat, vegetables, fats "
                                       "or other?"))
                     (relation-asserted which-entrée-omnivorous)
                     (valid-answers grain legumes fish meat vegetables fats other))))

(defrule determine-which-entrée-vegetarian
   (food-style vegetarian)
   (main-meal-for-omnivorous-or-vegetarian entrée)
   =>
   (assert (UI-state (display (str-cat "Is the main component of the entrée grain (farro, arborio, wild rice, polenta), "
                                       "legumes (lentils, fava, chickpea, green beans), vegetables, vegetables fats "
                                       "(avocados, olive oil, peanut butter, nuts and seeds) or other?"))
                     (relation-asserted which-entrée-vegetarian)
                     (valid-answers grain legumes vegetables "vegetables fats" other))))

(defrule determine-which-entrée-vegan
   (main-meal-for-vegan entrée)
   =>
   (assert (UI-state (display (str-cat "Is the main component of the entrée grain (farro, arborio, wild rice, polenta), "
                                       "legumes (lentils, fava, chickpea, green beans), vegetables, vegetables fats "
                                       "(avocados, olive oil, peanut butter, nuts and seeds), or other?"))
                     (relation-asserted which-entrée-vegan)
                     (valid-answers grain legumes vegetables "vegetables fats" other))))

(defrule determine-which-vegetables
   (or (which-entrée-omnivorous vegetables)
       (which-entrée-vegetarian vegetables)
       (which-entrée-vegan vegetables))
   =>
   (assert (UI-state (display (str-cat "Does the vegetables are root (parsnips, carrots), grilled (peppers, onions, "
                                       "mushrooms) or other?"))
                     (relation-asserted which-vegetables)
                     (valid-answers root grilled other))))

(defrule determine-which-fish
   (which-entrée-omnivorous fish)
   =>
   (assert (UI-state (display (str-cat "Does the fish is shellfish (clams, scallops, lobster, crab), bluefish (salmon, "
                                        "trout, tuna) or other? 🦐 🐟"))
                     (relation-asserted which-fish)
                     (valid-answers shellfish bluefish other))))

(defrule determine-which-fats
   (which-entrée-omnivorous fats)
   =>
   (assert (UI-state (display (str-cat "Does the fats are vegetable (avocados, olive oil, peanut butter, nuts "
                                       "and seeds) or animal (duck/pork fat, dairy)?"))
                     (relation-asserted which-fats)
                     (valid-answers vegetable animal other))))

(defrule determine-which-meat
   (which-entrée-omnivorous meat)
   =>
   (assert (UI-state (display (str-cat "Does the meat is rich meats (beef strip loin, lamb), game birds (duck, quail, "
                                       "quinoa), braised meats (beef short-rib, pork shoulder), pork or other?"))
                     (relation-asserted which-meat)
                     (valid-answers "rich meats" "game birds" "braised meats" pork other))))

(defrule determine-which-pork
   (which-meat pork)
   =>
   (assert (UI-state (display "Does the pork is prosciutto, speck, mortadella, sausage or other?")
                     (relation-asserted which-pork)
                     (valid-answers prosciutto speck mortadella sausage other))))

(defrule determine-which-sausage
   (which-pork sausage)
   =>
   (assert (UI-state (display "Does the sausage is capocollo, soppressata, salame piccante or other?")
                     (relation-asserted which-sausage)
                     (valid-answers capocollo soppressata "salame piccante" other))))

(defrule determine-which-dessert
   (or (which-entrée-omnivorous dessert)
       (which-entrée-vegetarian dessert))
   =>
   (assert (UI-state (display (str-cat "Does the dessert is creamy (cheesecake, ice cream, creme brûlée, mousse cake), "
                                       "chocolate or other? 🍫"))
                     (relation-asserted which-dessert)
                     (valid-answers creamy chocolate other))))

(defrule determine-which-chocolate
   (which-dessert chocolate)
   =>
   (assert (UI-state (display (str-cat "Does the chocolate is white, milk (35% cacao ca.), semisweet (55% cacao ca.), "
                                       "bittersweet (70% cacao ca.) or unsweetened/bitter (100% cacao)? 🍫"))
                     (relation-asserted which-chocolate)
                     (valid-answers white milk semisweet bittersweet unsweetened/bitter "don't know"))))

;(defrule determine-predominant-dish-taste
;   (start)
;   =>
;   (assert (UI-state (display "Which is the predominant taste of the dish?")
;                     (relation-asserted predominant-dish-taste)
;                     (valid-answers sweet acid spice umami "not tasted yet"))))

;(defrule determine-dish-cooking-method
;   (start)
;   =>
;   (assert (UI-state (display (str-cat "Does the dish cooking method is dry-heat (broiling, grilling, roasting, baking, "
;                                       "sautéing, pan-frying, deep-frying), moist-heat (poaching, simmering, boiling, "
;                                       "steaming) or it is a combination of both (braising, stewing)?"))
;                     (relation-asserted dish-cooking-method)
;                     (valid-answers dry-heat moist-heat combination "don't know"))))

;;***********************
;;* BEER QUESTION RULES *
;;***********************

; random questions for user type and scenario recognition

(defrule determine-preferred-carbonation
   (declare (salience ?*very-high-priority*))
   (start)
   =>
   (assert (UI-state (display "Do you generally prefer to drink low, medium or high carbonated drinks? 🍾")
                     (relation-asserted preferred-carbonation)
                     (valid-answers low medium high))))

(defrule determine-whether-he-is-a-regular-beer-drinker
   (declare (salience ?*very-high-priority*))
   (start)
   =>
   (assert (UI-state (display "Are you a regular beer drinker? 🍺")
                     (relation-asserted regular-beer-drinker)
                     (valid-answers yes no))))

(defrule determine-preferred-color
   (declare (salience ?*very-high-priority*))
   (regular-beer-drinker yes)
   =>
   (assert (UI-state (display "Do you generally prefer pale, amber, brown or dark beer? 🍺")
                     (relation-asserted preferred-color)
                     (valid-answers pale amber brown dark))))

(defrule determine-preferred-fermentation
   (declare (salience ?*very-high-priority*))
   (regular-beer-drinker yes)
   =>
   (assert (UI-state (display "Do you generally prefer to drink top, bottom or wild fermented beer?")
                     (relation-asserted preferred-fermentation)
                     (valid-answers top bottom wild))))

(defrule determine-whether-he-eats-fermented-foods
   (declare (salience ?*very-high-priority*))
   (start)
   =>
   (assert (UI-state (display "Do you generally eat fermented foods (probiotic yogurt, kefir, kombucha)? 🥛")
                     (relation-asserted fermented-foods-eater)
                     (valid-answers yes no))))

(defrule determine-whether-he-should-drive
   (declare (salience ?*very-high-priority*))
   (start)
   =>
   (assert (UI-state (display "Do you have to drive? 🚘")
                     (relation-asserted driver)
                     (valid-answers yes no))))

(defrule determine-preferred-alcohol
   (declare (salience ?*very-high-priority*))
   (driver no)
   =>
   (assert (UI-state (display "Do you generally prefer to drink low, mild, high or very high alcoholic drinks? 🍹")
                     (relation-asserted preferred-alcohol)
                     (valid-answers low mild high "very high"))))

(defrule determine-whether-he-should-smoke-a-cigar
   (declare (salience ?*very-high-priority*))
   (start)
   =>
   (assert (UI-state (display "Do you have to smoke a cigar? If yes, is the cigar claro, maduro or oscuro? 🚬")
                     (relation-asserted which-cigar)
                     (valid-answers claro maduro oscuro no))))

(defrule determine-preferred-flavor
   (declare (salience ?*very-high-priority*))
   (start)
   =>
   (assert (UI-state (display "What kind of flavor do you generally prefer?")
                     (relation-asserted preferred-flavor)
                     (valid-answers clean sweet bitter roasty fruity spicy sour "don't know"))))

; depth questions for meal type recognition

(defrule determine-food-style
   (start)
   =>
   (assert (UI-state (display "Are you vegetarian, vegan or omnivorous?")
                     (relation-asserted food-style)
                     (valid-answers vegetarian vegan omnivorous))))

(defrule determine-main-meal-for-omnivorous-or-vegetarian
   (or (food-style omnivorous)
       (food-style vegetarian))
   =>
   (assert (UI-state (display "Is the main meal pizza, entrée, cheese or dessert? 🧀")
                     (relation-asserted main-meal-for-omnivorous-or-vegetarian)
                     (valid-answers pizza entrée cheese dessert other))))

(defrule determine-main-meal-for-vegan
   (food-style vegan)
   =>
   (assert (UI-state (display "Is the main meal pizza, entrée or dessert?")
                     (relation-asserted main-meal-for-vegan)
                     (valid-answers pizza entrée dessert other))))

   ; ... if main meal is cheese

(defrule determine-which-cheese-style
   (main-meal-for-omnivorous-or-vegetarian cheese)
   =>
   (assert (UI-state (display (str-cat "Is the cheese style fresh (Mascarpone, Ricotta, Chèvre, Feta, Cream Cheese, "
                                       "Quark, Cottage), semi-soft (Colby, Fontina, Havarti, Monterey Jack), firm/hard "
                                       "(Gouda, Cheddar, Swiss, Parmesan), blue (Roquefort, Gorgonzola, Danish), "
                                       "natural rind (Brie, Camembert, Triple Crème, Mimolette, Stilton, Lancashire, "
                                       "Tomme de Savoie) or washed rind (Epoisses, Livarot, Taleggio)? 🧀"))
                     (help (format nil "%s %n%s %n%s %n%s %n%s %n%s"
                                       (str-cat "🧀 Fresh cheeses have not been aged, or are very slightly cured. These "
                                                "cheeses have a high moisture content and are usually mild and have a "
                                                "very creamy taste and soft texture.")
                                       (str-cat "🧀 [Semi-soft](goo.gl/izu1Bw) cheeses have a smooth, generally, creamy "
                                                "interior with little or no rind. These cheeses are generally high in "
                                                "moisture content and range from very mild in flavor to very pungent.")
                                       (str-cat "🧀 [Firm/hard](goo.gl/yrfoJK) cheeses have a taste profiles range from "
                                                "very mild to sharp and pungent. They generally have a texture profile "
                                                "that ranges from elastic, at room temperature, to the hard cheeses that "
                                                "can be grated.")
                                       (str-cat "🧀 [Blue](goo.gl/9KkNww) cheeses have a distinctive blue/green veining, "
                                                "created when the penicillium roqueforti mold, added during the make "
                                                "process, is exposed to air. This mold provides a distinct flavor to the "
                                                "cheese, which ranges from fairly mild to assertive and pungent.")
                                       (str-cat "🧀 [Natural rind](goo.gl/ys8pkz) cheeses have rinds that are "
                                                "self-formed during the aging process. Generally, no molds or microflora "
                                                "are added, nor is washing used to create the exterior rinds, and those "
                                                "that do exhibit molds and microflora in their rinds get them naturally "
                                                "from the environment.")
                                       (str-cat "🧀 [Washed rind](goo.gl/Kh3BwD) is used to describe those cheeses that "
                                                "are surface-ripened by washing the cheese throughout the ripening/aging "
                                                "process with brine, beer, wine, brandy, or a mixture of ingredients, "
                                                "which encourages the growth of bacteria. The exterior rind of washed "
                                                "rind cheeses may vary from bright orange to brown, with flavor and "
                                                "aroma profiles that are quite pungent, yet the interior of these "
                                                "cheeses is most often semi-soft and, sometimes, very creamy.")))
                     (why (format nil "%s %n%s %n%s %n%s %n%s %n%s"
                                      (str-cat "🧀 Fresh cheeses are light cheeses which pair excellently with the "
                                               "softer flavors of Wheat and Lambic beers.")
                                      (str-cat "🧀 The vast variety of [semi-soft](goo.gl/izu1Bw) can be paired with "
                                               "many different craft beers, such as German Kölsch or Bock and Pale Ale "
                                               "beers.")
                                      (str-cat "🧀 Because of their variety, [firm/hard](goo.gl/yrfoJK) are easily "
                                               "paried with an equally broad range of craft beer styles, such as "
                                               "Pilsner, Bock, Brown Ale and Imperial Stout.")
                                      (str-cat "🧀 [Blue](goo.gl/9KkNww) are stronger-flavored cheeses which are most "
                                               "successfully balanced with stonger-flavored bolder beers like IPAs or "
                                               "Imperial IPAs.")
                                      (str-cat "🧀 [Natural rind](goo.gl/ys8pkz) cheeses include Tomme de Savoie styles "
                                               "which pair well with Golden Ales or Blondes. Traditional British-style "
                                               "ales work well with English-style natural rind cheeses, such as "
                                               "Lancashire and Stilton.")
                                      (str-cat "🧀 [Washed rind](goo.gl/Kh3BwD) itself, while potentially pungent, is "
                                               "often creamy. Pair Belgian-styles ales, like Triples and Golden Strong "
                                               "ales with these varieties.")))
                     (relation-asserted which-cheese-style)
                     (valid-answers fresh semi-soft firm/hard blue "natural rind" "washed rind" "don't know"))))

(defrule determine-which-fresh-cheese
   (which-cheese-style fresh)
   =>
   (assert (UI-state (display "Is the fresh cheese Mascarpone, Ricotta, Chèvre, Feta, Cream Cheese or other? 🧀")
                     (why (str-cat "🧀 Italian-Style Mascarpone, Ricotta and soft Chèvre will match the delicate notes "
                                   "of the beer and neither will overwhelm the palate in the beginning of a meal."))
                     (relation-asserted which-fresh-cheese)
                     (valid-answers Mascarpone Ricotta Chèvre Feta "Cream Cheese" other))))

(defrule determine-whether-he-should-eat-Mascarpone-with-fruit
   (which-fresh-cheese Mascarpone)
   =>
   (assert (UI-state (display "Do you have to eat Mascarpone with fruit?")
                     (relation-asserted mascarpone-with-fruit)
                     (valid-answers yes no))))

(defrule determine-which-semi-soft-cheese
   (which-cheese-style semi-soft)
   =>
   (assert (UI-state (display "Is the semi-soft cheese Colby, Havarti, Monterey Jack or other? 🧀")
                     (why (str-cat "🧀 Fontina, Havarti and milder blue cheeses can be enhanced by the carbonation of "
                                   "Kölsch style ales. The gentle notes of grass in the cheese can be brought out by "
                                   "using the malt of a Bock or the hops of a Pale Ale."))
                     (relation-asserted which-semi-soft-cheese)
                     (valid-answers Colby Havarti "Monterey Jack" other))))

(defrule determine-which-firm/hard-cheese
   (which-cheese-style firm/hard)
   =>
   (assert (UI-state (display "Is the firm/hard cheese Gouda, Cheddar, Swiss, Parmesan or other? 🧀")
                     (why (str-cat "🧀 Cheddar and Swiss cheeses can mimic the Maillard reaction when paired with a beer "
                                   "style, such as a Brown Ale. Roasty stouts can add a creaminess to the firm and hard "
                                   "cheeses on the palate."))
                     (relation-asserted which-firm/hard-cheese)
                     (valid-answers Gouda Cheddar Swiss Parmesan other))))

(defrule determine-which-type-of-Gouda
   (which-firm/hard-cheese Gouda)
   =>
   (assert (UI-state (display "Is the Gouda cheese aged, smoked or other? 🧀")
                     (relation-asserted which-type-of-Gouda)
                     (valid-answers aged smoked other))))

(defrule determine-which-color-of-Cheddar
   (which-firm/hard-cheese Cheddar)
   =>
   (assert (UI-state (display "Is the Cheddar cheese white or yellow? 🧀")
                     (relation-asserted which-color-of-Cheddar)
                     (valid-answers white yellow))))

(defrule determine-which-Cheddar-seasoning
   (which-firm/hard-cheese Cheddar)
   =>
   (assert (UI-state (display "Is the Cheddar cheese seasoning mild, medium, aged or other? 🧀")
                     (relation-asserted which-Cheddar-seasoning)
                     (valid-answers mild medium aged other))))

(defrule determine-if-Cheddar-is-sharp
   (or (which-Cheddar-seasoning medium)
       (which-Cheddar-seasoning aged))
   =>
   (assert (UI-state (display "Is the Cheddar cheese sharp? 🧀")
                     (relation-asserted Cheddar-is-sharp)
                     (valid-answers yes no "don't know"))))

(defrule determine-which-type-of-Swiss
   (which-firm/hard-cheese Swiss)
   =>
   (assert (UI-state (display "Is the Swiss cheese Emmental, Gruyère or other? 🧀")
                     (why (str-cat "🧀 Emmentaler-style cheeses can mimic the Maillard reaction when paired with a beer "
                                   "style, such as a Brown Ale."))
                     (relation-asserted which-type-of-Swiss)
                     (valid-answers Emmental Gruyère other))))

(defrule determine-which-blue-cheese
   (which-cheese-style blue)
   =>
   (assert (UI-state (display (str-cat "Is the blue cheese Stilton or other? 🧀"))
                     (why "🧀 Stilton cheese can be intensified the sweetness on the palate with a Barley Wine.")
                     (relation-asserted which-blue-cheese)
                     (valid-answers Stilton other))))

(defrule determine-which-natural-rind-cheese
   (which-cheese-style "natural rind")
   =>
   (assert (UI-state (display (str-cat "Is the natural rind cheese Brie, Camembert, Triple Crème, Mimolette, Stilton, "
                                       "or other? 🧀"))
                     (why (str-cat "🧀 Lancashire, Stilton, Brie and Camembert all share a rich creamy base that can be "
                                   "refreshed with a Golden, Blond or Pale Ale or intensified the sweetness on the "
                                   "palate with a Barley Wine."))
                     (relation-asserted which-natural-rind-cheese)
                     (valid-answers Brie Camembert "Triple Crème" Mimolette Stilton other))))

(defrule determine-which-washed-rind-cheese
   (which-cheese-style "washed rind")
   =>
   (assert (UI-state (display "Is the washed rind cheese Taleggio or other? 🧀")
                     (why (str-cat "🧀 Classic Belgian yeast flavors spur a tighter carbonation as well as bring out "
                                   "delicate sweet notes that can cut through the funk of a washed rind cheeses."))
                     (relation-asserted which-washed-rind-cheese)
                     (valid-answers Taleggio other))))

   ; ... if main meal is entrée

(defrule determine-which-entrée-omnivorous
   (food-style omnivorous)
   (main-meal-for-omnivorous-or-vegetarian entrée)
   =>
   (assert (UI-state (display (str-cat "Is the main component of the entrée grain (farro, arborio, wild rice, polenta), "
                                       "legumes (lentils, fava, chickpea, green beans), fish, meat, vegetables, fats "
                                       "or other?"))
                     (relation-asserted which-entrée-omnivorous)
                     (valid-answers grain legumes fish meat vegetables fats other))))

(defrule determine-which-entrée-vegetarian
   (food-style vegetarian)
   (main-meal-for-omnivorous-or-vegetarian entrée)
   =>
   (assert (UI-state (display (str-cat "Is the main component of the entrée grain (farro, arborio, wild rice, polenta), "
                                       "legumes (lentils, fava, chickpea, green beans), vegetables, vegetables fats "
                                       "(avocados, olive oil, peanut butter, nuts and seeds) or other?"))
                     (relation-asserted which-entrée-vegetarian)
                     (valid-answers grain legumes vegetables "vegetables fats" other))))

(defrule determine-which-entrée-vegan
   (main-meal-for-vegan entrée)
   =>
   (assert (UI-state (display (str-cat "Is the main component of the entrée grain (farro, arborio, wild rice, polenta), "
                                       "legumes (lentils, fava, chickpea, green beans), vegetables, vegetables fats "
                                       "(avocados, olive oil, peanut butter, nuts and seeds), or other?"))
                     (relation-asserted which-entrée-vegan)
                     (valid-answers grain legumes vegetables "vegetables fats" other))))

(defrule determine-which-vegetables
   (or (which-entrée-omnivorous vegetables)
       (which-entrée-vegetarian vegetables)
       (which-entrée-vegan vegetables))
   =>
   (assert (UI-state (display (str-cat "Does the vegetables are root (parsnips, carrots), grilled (peppers, onions, "
                                       "mushrooms) or other?"))
                     (relation-asserted which-vegetables)
                     (valid-answers root grilled other))))

(defrule determine-which-fish
   (which-entrée-omnivorous fish)
   =>
   (assert (UI-state (display (str-cat "Does the fish is shellfish (clams, scallops, lobster, crab), bluefish (salmon, "
                                        "trout, tuna) or other? 🦐 🐟"))
                     (relation-asserted which-fish)
                     (valid-answers shellfish bluefish other))))

(defrule determine-which-fats
   (which-entrée-omnivorous fats)
   =>
   (assert (UI-state (display (str-cat "Does the fats are vegetable (avocados, olive oil, peanut butter, nuts "
                                       "and seeds) or animal (duck/pork fat, dairy)?"))
                     (relation-asserted which-fats)
                     (valid-answers vegetable animal other))))

(defrule determine-which-meat
   (which-entrée-omnivorous meat)
   =>
   (assert (UI-state (display (str-cat "Does the meat is rich meats (beef strip loin, lamb), game birds (duck, quail, "
                                       "quinoa), braised meats (beef short-rib, pork shoulder), pork or other?"))
                     (relation-asserted which-meat)
                     (valid-answers "rich meats" "game birds" "braised meats" pork other))))

(defrule determine-which-pork
   (which-meat pork)
   =>
   (assert (UI-state (display "Does the pork is prosciutto, speck, mortadella, sausage or other?")
                     (relation-asserted which-pork)
                     (valid-answers prosciutto speck mortadella sausage other))))

(defrule determine-which-sausage
   (which-pork sausage)
   =>
   (assert (UI-state (display "Does the sausage is capocollo, soppressata, salame piccante or other?")
                     (relation-asserted which-sausage)
                     (valid-answers capocollo soppressata "salame piccante" other))))

(defrule determine-which-dessert
   (or (which-entrée-omnivorous dessert)
       (which-entrée-vegetarian dessert))
   =>
   (assert (UI-state (display (str-cat "Does the dessert is creamy (cheesecake, ice cream, creme brûlée, mousse cake), "
                                       "chocolate or other? 🍫"))
                     (relation-asserted which-dessert)
                     (valid-answers creamy chocolate other))))

(defrule determine-which-chocolate
   (which-dessert chocolate)
   =>
   (assert (UI-state (display (str-cat "Does the chocolate is white, milk (35% cacao ca.), semisweet (55% cacao ca.), "
                                       "bittersweet (70% cacao ca.) or unsweetened/bitter (100% cacao)? 🍫"))
                     (relation-asserted which-chocolate)
                     (valid-answers white milk semisweet bittersweet unsweetened/bitter "don't know"))))

;(defrule determine-predominant-dish-taste
;   (start)
;   =>
;   (assert (UI-state (display "Which is the predominant taste of the dish?")
;                     (relation-asserted predominant-dish-taste)
;                     (valid-answers sweet acid spice umami "not tasted yet"))))

;(defrule determine-dish-cooking-method
;   (start)
;   =>
;   (assert (UI-state (display (str-cat "Does the dish cooking method is dry-heat (broiling, grilling, roasting, baking, "
;                                       "sautéing, pan-frying, deep-frying), moist-heat (poaching, simmering, boiling, "
;                                       "steaming) or it is a combination of both (braising, stewing)?"))
;                     (relation-asserted dish-cooking-method)
;                     (valid-answers dry-heat moist-heat combination "don't know"))))


Create task1.clp

Create task1.clp

(defrule zachisl
  =>
    (printout t "Input the count of students")
    (bind ?n (read))
    (loop-for-count (?i 1 ?n) do
      (printout t "Input the last name:")
      (bind ?lastName (read))
      (assert (student ?lastName 1))
    )
)

error: pathspec 'ssu-ai-level-2/chapter5/task1.clp' did not match any file(s) known to git


Create task1.clp

Create task1.clp

(defrule replace
 =>
 (bind ?str (readline))
 (bind ?a (readline))
 (bind ?b (readline))
 (bind ?n (str-length ?str))
 (bind ?k 0)
 (loop-for-count (?i 1 ?n) do
    (bind ?c1 (sub-string ?i ?i ?str))
    (bind ?d (str-compare ?c1 ?a))

    (if (= ?d 0) then
        (printout t "k=" ?k crlf))))

error: pathspec 'ssu-ai-level-2/chapter7/task1.clp' did not match any file(s) known to git


Modified the stage template to require the at field to be set.

;------------------------------------------------------------------------------
;The Adventure Engine
;Copyright (c) 2013, Joshua Scoggins
;All rights reserved.
;
;Redistribution and use in source and binary forms, with or without
;modification, are permitted provided that the following conditions are met:
;    * Redistributions of source code must retain the above copyright
;      notice, this list of conditions and the following disclaimer.
;    * Redistributions in binary form must reproduce the above copyright
;      notice, this list of conditions and the following disclaimer in the
;      documentation and/or other materials provided with the distribution.
;    * Neither the name of Joshua Scoggins nor the
;      names of its contributors may be used to endorse or promote products
;      derived from this software without specific prior written permission.
;
;THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
;ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
;WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
;DISCLAIMED. IN NO EVENT SHALL Joshua Scoggins BE LIABLE FOR ANY
;DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
;(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
;LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
;ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
;(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
;SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;------------------------------------------------------------------------------
; Stage.clp - Standardized mechanism for providing stage control facts
;------------------------------------------------------------------------------
(deftemplate Runtime::stage
             "Standardized mechanism for providing stage control facts"
             (slot id
                   (type SYMBOL)
                   (default-dynamic (gensym*)))
             (slot at
                   (type SYMBOL)
                   (default ?NONE))
             (multislot rest
                        (type SYMBOL)))
;------------------------------------------------------------------------------

;------------------------------------------------------------------------------
;The Adventure Engine
;Copyright (c) 2013, Joshua Scoggins
;All rights reserved.
;
;Redistribution and use in source and binary forms, with or without
;modification, are permitted provided that the following conditions are met:
;    * Redistributions of source code must retain the above copyright
;      notice, this list of conditions and the following disclaimer.
;    * Redistributions in binary form must reproduce the above copyright
;      notice, this list of conditions and the following disclaimer in the
;      documentation and/or other materials provided with the distribution.
;    * Neither the name of Joshua Scoggins nor the
;      names of its contributors may be used to endorse or promote products
;      derived from this software without specific prior written permission.
;
;THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
;ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
;WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
;DISCLAIMED. IN NO EVENT SHALL Joshua Scoggins BE LIABLE FOR ANY
;DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
;(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
;LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
;ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
;(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
;SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;------------------------------------------------------------------------------
; Stage.clp - Standardized mechanism for providing stage control facts
;------------------------------------------------------------------------------
(deftemplate Runtime::stage
             "Standardized mechanism for providing stage control facts"
             (slot id (type SYMBOL) (default-dynamic (gensym*)))
             (slot at (type SYMBOL))
             (multislot rest (type SYMBOL)))
;------------------------------------------------------------------------------


src/lib/cortex/core/Object.clp: Added the parent slot

I have been debating having the parent slot be located in the base Object
class but I have decided to have it because it is super useful.

;------------------------------------------------------------------------------
;Copyright (c) 2013, Joshua Scoggins
;All rights reserved.
;
;Redistribution and use in source and binary forms, with or without
;modification, are permitted provided that the following conditions are met:
;    * Redistributions of source code must retain the above copyright
;      notice, this list of conditions and the following disclaimer.
;    * Redistributions in binary form must reproduce the above copyright
;      notice, this list of conditions and the following disclaimer in the
;      documentation and/or other materials provided with the distribution.
;    * Neither the name of Joshua Scoggins nor the
;      names of its contributors may be used to endorse or promote products
;      derived from this software without specific prior written permission.
;
;THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
;ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
;WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
;DISCLAIMED. IN NO EVENT SHALL Joshua Scoggins BE LIABLE FOR ANY
;DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
;(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
;LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
;ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
;(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
;SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;------------------------------------------------------------------------------
; Object.clp - Contains basic object classes
;------------------------------------------------------------------------------
(defclass cortex::Object
  "Base class of all objects"
  (is-a USER)
  (slot id (type SYMBOL) (visibility public) (access initialize-only))
  (slot class (type SYMBOL) (visibility public) (access initialize-only))
  (slot parent (type SYMBOL) (visibility public))
  (message-handler init around))
;------------------------------------------------------------------------------
(defmessage-handler cortex::Object init around
                    "Initializes the object, setting the id and class of the
                    object"
                    ()
                    (call-next-handler)
                    ;we want to set this information as the last thing before
                    ;we return
                    (bind ?self:id (instance-name-to-symbol
                                     (instance-name ?self)))
                    (bind ?self:class (class ?self)))
;------------------------------------------------------------------------------

;------------------------------------------------------------------------------
;Copyright (c) 2013, Joshua Scoggins
;All rights reserved.
;
;Redistribution and use in source and binary forms, with or without
;modification, are permitted provided that the following conditions are met:
;    * Redistributions of source code must retain the above copyright
;      notice, this list of conditions and the following disclaimer.
;    * Redistributions in binary form must reproduce the above copyright
;      notice, this list of conditions and the following disclaimer in the
;      documentation and/or other materials provided with the distribution.
;    * Neither the name of Joshua Scoggins nor the
;      names of its contributors may be used to endorse or promote products
;      derived from this software without specific prior written permission.
;
;THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
;ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
;WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
;DISCLAIMED. IN NO EVENT SHALL Joshua Scoggins BE LIABLE FOR ANY
;DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
;(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
;LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
;ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
;(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
;SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;------------------------------------------------------------------------------
; Object.clp - Contains basic object classes
;------------------------------------------------------------------------------
(defclass cortex::Object
  "Base class of all objects"
  (is-a USER)
  (slot id (type SYMBOL) (visibility public) (access initialize-only))
  (slot class (type SYMBOL) (visibility public) (access initialize-only))
  (message-handler init around))
;------------------------------------------------------------------------------
(defmessage-handler cortex::Object init around
                    "Initializes the object, setting the id and class of the
                    object"
                    ()
                    (call-next-handler)
                    ;we want to set this information as the last thing before
                    ;we return
                    (bind ?self:id (instance-name-to-symbol
                                     (instance-name ?self)))
                    (bind ?self:class (class ?self)))
;------------------------------------------------------------------------------


Partially implemented core course grade req.

;; Define templates for model classes
(import com.joshktan.advisor.model.*)
(deftemplate Course
  (declare (from-class Course)))
(deftemplate Record
  (declare (from-class Record)))
(deftemplate Advice
  (declare (from-class Advice)))

;; GLOBAL VARIABLES
(defglobal ?*total-credit-req* = (get-member com.joshktan.advisor.req.TotalCreditsRequirement TOTAL_CREDITS_REQUIRED))

;; GEN ED REQUIREMENTS

;; First Year Experience (F) Requirements
(defrule gen-ed-f
  "Advise student if Gen Ed First Year Experience requirements not satisfied."
  (not (Course {courseId == "UNIV 189"}))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed First Year Experience requirements not satisfied" "Skills for Academic Success (UNIV 189) is required, but is not listed among courses." "ISSUE")))

;; Communication (C) Requirements
(defrule gen-ed-c
  "Advise student if Gen Ed Communication requirements not satisfied."
  (not (exists (Course {courseId == "COMM 110"})))
  (not (exists (Course {courseId == "ENGL 110"})))
  (not (exists (Course {courseId == "ENGL 120"})))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Communication requirements not satisfied" "College Composition I (ENGL 110), College Composition II (ENGL 120), and Fundamentals of Public Speaking (COMM 110) are required." "ISSUE")))

;; Quantitative Reasoning (R) Requirements
(defrule gen-ed-r
  "Advise student if Gen Ed Quantitative Reasoning requirements not satisfied."
  (not (Course {courseId == "MATH 165"}))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Quantitative Reasoning requirements not satisfied" "Calculus I (MATH 165) is required, but is not listed among courses." "ISSUE")))

;; Science & Technology (S) Requirements
;; TODO - make sure all different
(defrule gen-ed-s
  "Advise student if Gen Ed Science & Technology requirements not satisfied."
  ?totalCredits <- (accumulate (bind ?count 0)                                                ;; initializer
			       (bind ?count (+ ?count ?credits))                              ;; action
			       ?count                                                         ;; result
			       (Course (credits ?credits) (courseId ?t&:(is-gen-ed ?t "S")))) ;; CE
  (test (< ?totalCredits 10))
  =>
;;  ((System.out) println (?totalCredits toString))
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Science & Technology requirements not satisfied" "At least 10 credits in the General Education Science and Technology area are required." "ISSUE")))

;; Humanities & Fine Arts (A) Requirements
;; TODO - make sure all different
(defrule gen-ed-a
  "Advise student if Gen Ed Humanities & Fine Arts requirements not satisfied."
  ?totalCredits <- (accumulate (bind ?count 0)                                                ;; initializer
			       (bind ?count (+ ?count ?credits))                              ;; action
			       ?count                                                         ;; result
			       (Course (credits ?credits) (courseId ?t&:(is-gen-ed ?t "A")))) ;; CE
  (test (< ?totalCredits 6))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Humanities & Fine Arts requirements not satisfied" "At least 6 credits in the General Education Humanities & Fine Arts area are required." "ISSUE")))

;; Social & Behavioral Sciences (B) Requirements
;; TODO - make sure all different
(defrule gen-ed-b
  "Advise student if Gen Ed Social & Behavioral Sciences requirements not satisfied."
  ?totalCredits <- (accumulate (bind ?count 0)                                                ;; initializer
			       (bind ?count (+ ?count ?credits))                              ;; action
			       ?count                                                         ;; result
			       (Course (credits ?credits) (courseId ?t&:(is-gen-ed ?t "B")))) ;; CE
  (test (< ?totalCredits 6))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Social & Behavioral Sciences requirements not satisfied" "At least 6 credits in the General Education Social & Behavioral Sciences area are required." "ISSUE")))

;; Wellness (W) Requirements
;; TODO - make sure all different
(defrule gen-ed-w
  "Advise student if Gen Ed Wellness requirements not satisfied."
  ?totalCredits <- (accumulate (bind ?count 0)                                                ;; initializer
			       (bind ?count (+ ?count ?credits))                              ;; action
			       ?count                                                         ;; result
			       (Course (credits ?credits) (courseId ?t&:(is-gen-ed ?t "W")))) ;; CE
  (test (< ?totalCredits 2))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Wellness requirements not satisfied" "At least 6 credits in the General Education Wellness area are required." "ISSUE")))

;; Cultural Diversity (D) Requirements
(defrule gen-ed-d
  "Advise student if Gen Ed Cultural Diversity requirements not satisfied."
  (not (exists (Course (courseId ?t&:(is-gen-ed ?t "D")))))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Cultural Diversity requirements not satisfied" "At least 1 course in the General Education Cultural Diversity area is required." "ISSUE")))

;; Global Perspectives (G) Requirements
(defrule gen-ed-g
  "Advise student if Gen Ed Global Perspectives requirements not satisfied."
  (not (exists (Course (courseId ?t&:(is-gen-ed ?t "G")))))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Global Perspectives requirements not satisfied" "At least 1 course in the General Education Global Perspectives area is required." "ISSUE")))

;; Gen Ed Lower Division Requirements
(defrule gen-ed-ld
  "Adivce student if Gen Ed lower division requirements are not satisfied."
  (exists (gen-ed-ld-not-satisfied))
  =>
  (assert (gen-ed-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed lower division requirements not satisfied" "See curriculum guide for details." "ISSUE")))

;; Gen Ed Upper Division Requirements
(defrule gen-ed-ud
  "Advise student if Gen Ed upper division requirements not satisfied."
  (not (exists (Course {courseId == "ENGL 321" || courseId == "ENGL 324"})))
  =>
  (assert (gen-ed-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed upper division requirements not satisfied" "Either Writing in the Technical Professions (ENGL 321) or Writing in the Sciences (ENGL 324) is required, but neither is listed among courses." "ISSUE")))

;; Gen Ed Requirements
(defrule gen-ed
  "Advise student if Gen Ed requirements not satisfied."
  (or (exists (gen-ed-ld-not-satisfied)) (exists (gen-ed-ud-not-satisfied)))
  =>
  (assert (deg-req-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed requirements not satisfied" "See curriculm guide for details." "ISSUE")))

;; One Year Lab Science Sequence Requirement
(defrule lab-sci-biol-126
  (not (exists (Course {courseId == "BIOL 126"})))
  (not (exists (Course {courseId == "BIOL 126L"})))
  (not (exists (Course {courseId == "BIOL 220"})))
  (not (exists (Course {courseId == "BIOL 220L"})))
  =>
  (assert (no-biol-126-seq)))

(defrule lab-sci-chem-121
  (not (exists (Course {courseId == "CHEM 121"})))
  (not (exists (Course {courseId == "CHEM 121L"})))
  (not (exists (Course {courseId == "CHEM 122"})))
  (not (exists (Course {courseId == "CHEM 122L"})))
  =>
  (assert (no-chem-121-seq)))

(defrule lab-sci-chem-150
  (not (exists (Course {courseId == "CHEM 150"})))
  (not (exists (Course {courseId == "CHEM 160"})))
  (not (exists (Course {courseId == "CHEM 151"})))
  (not (exists (Course {courseId == "CHEM 161"})))
  =>
  (assert (no-chem-150-seq)))

(defrule lab-sci-geol-105
  (not (exists (Course {courseId == "GEOL 105"})))
  (not (exists (Course {courseId == "GEOL 105L"})))
  (not (exists (Course {courseId == "GEOL 106"})))
  (not (exists (Course {courseId == "GEOL 106L"})))
  =>
  (assert (no-geol-105-seq)))

(defrule lab-sci-phys-211
  (not (exists (Course {courseId == "PHYS 211"})))
  (not (exists (Course {courseId == "PHYS 211L"})))
  (not (exists (Course {courseId == "PHYS 212"})))
  (not (exists (Course {courseId == "PHYS 212L"})))
  =>
  (assert (no-phys-211-seq)))

(defrule lab-sci-phys-251
  (not (exists (Course {courseId == "PHYS 251"})))
  (not (exists (Course {courseId == "PHYS 251L"})))
  (not (exists (Course {courseId == "PHYS 252"})))
  (not (exists (Course {courseId == "PHYS 252L"})))
  =>
  (assert (no-phys-251-seq)))

(defrule lab-sci-seq-req
  (no-biol-126-seq)
  (no-chem-121-seq)
  (no-chem-150-seq)
  (no-geol-105-seq)
  (no-phys-211-seq)
  (no-phys-251-seq)
  =>
  (add (new Advice "LabScienceRequirement" "Lab Science Sequence requirements not satisfied" "A one year sequence of lab science courses (with corresponding labs) is required." "ISSUE")))

;; B.S. COMPUTER SCIENCE REQUIREMENTS

;; core CS course requirements

(deffunction is-core-cs (?c)
  (return (?c == "CSCI 160" ||
	   ?c == "CSCI 161" ||
	   ?c == "CSCI 213" ||
	   ?c == "CSCI 222" ||
	   ?c == "CSCI 313" ||
	   ?c == "CSCI 336" ||
	   ?c == "CSCI 372" ||
	   ?c == "CSCI 374" ||
	   ?c == "CSCI 415" ||
	   ?c == "CSCI 445" ||
	   ?c == "CSCI 467" ||
	   ?c == "CSCI 474" ||
	   ?c == "CSCI 489"))

;; "C" or better required for all CSCI courses
(defrule c-in-cs-course
  "Advise that will have to retake a CS course if it's a degree requirement and a D or worse received."
  (Course (courseId ?c&:(is-core-cs ?c)) (grade ?g&:(g == "D" || g == "F")))
  =>
    (add (new Advice "LabScienceRequirement" "Lab Science Sequence requirements not satisfied" "A one year sequence of lab science courses (with corresponding labs) is required." "ISSUE")))

;; UNIVERSITY GRADUATION REQUIREMENTS
;; Total Degree Credits Requirement
(defrule total-credits
    "Advise to take more credits if total credit amount is less than the required amount."
    ?r <- (Record)
    =>
    (if (< ?r.totalCredits ?*total-credit-req*) then
    (assert (not-enough-credits))
    else
    (assert (enough-credits))))

(defrule not-enough-credits
    "Advise to take more credits if total credit amount is less than the required amount."
    (not-enough-credits)
    ?r <- (Record)
    =>
    (add (new Advice "TotalCreditsRequirement" "Too little credits" (str-cat "Have " ?r.totalCredits " credits, but need " ?*total-credit-req* ".") "ISSUE")))

;; CRITERA FOR GRADUATING WITH HONOR
(defrule graduate-with-honors
  ?record <- (Record {gpa >= 3.5})
  (not (exists (Course {grade == "NA"})))
  ;; TODO add other requirements here
  =>
   (assert (honors))
    (if (>= ?record.gpa 3.90) then
      (add (new Congrats "You will graduate summa cum laude."))
     elif (>= ?record.gpa 3.70) then
      (add (new Congrats "You will graduate magna cum laude."))
     else
      (add (new Congrats "You will graduate cum laude."))))

;; ---------------------------------------------------------------------- ;;

;; Just so you know how to do it
;; (defrule enough-credits-and-honors
;;   "enough credits and honors also"
;;   (and (honors) (enough-credits))
;;   =>
;;   ((System.out) println "Both enough credits and also honorable!"))

;; (# semesters left * 20 ) < (needed - already have) => advise warning: fill out form thing for +20 credits / semester (or summer school or postpone grad)

;; Graduating Honors (figure out how to chain rules: (if all courses have grades) && (all requirements fulfilled) => (add congrats)

;; COULD BE USEFUL:
;; The not CE can be used in arbitrary combination with the and and or CEs. You can define complex logical structures this way. For example, suppose you want a rule to fire once if for every fact (a ?x), there is a fact (b ?x). You could express that as
;; Jess> (defrule forall-example
;;   (not (and (a ?x) (not (b ?x))))
;;   =>)
;; i.e., "It is not true that for some ?x, there is an (a ?x) and no (b ?x)". This is actually how the the forall CE is implemented.

;; note: (instanceof <external-address> <class-name>)

;; COULD ALSO BE USEFUL
;; The logical conditional element lets you specify logical dependencies among facts. All the facts asserted on the RHS of a rule become dependent on the matches to the logical patterns on that rule's LHS. If any of the matches later become invalid, the dependent facts are retracted automatically.
;; (defrule rule-1
;;   (logical (faucet-open))
;;   =>
;;   (assert (water-flowing)))
;;   =>
;;   (assert (all-cour)))

;; Graduation with honor eligibility is determined in two steps:
;; Step One: Earn a minimum NDSU (institutional) GPA of 3.50
;; NDSU GPA's below 3.50 are not considered (and step two is not necessary)
;; Step Two: Earn an overall (cumulative) GPA of 3.50 or greater, which includes:
;; all credits and grades earned at NDSU
;; the inclusion of all transfer work and all attempts of repeated coursework
;;
;; Candidates who achieve an overall GPA of 3.50 or higher according to the criteria listed above will graduate:
;; Cum Laude — greater than or equal to 3.50 and less than 3.70
;; Magna Cum Laude — greater than or equal to 3.70 and less than 3.90
;; Summa Cum Laude — greater than or equal to 3.90 and up to 4.00
;; The complete Graduation with Honor policy may be reviewed in the online Undergraduate Bulletin
;; PLEASE BE AWARE grade-point averages are NOT rounded (for example, a GPA of 3.497 is not rounded to 3.5)
;; PLEASE BE AWARE graduation with honor levels are subject to change once final grades are determined and posted to the official academic record

;; ;; matches any
;; (defrule any
;;   (Record (studentId ?sId))
;;   =>
;;   ((System.out) println "Testing 1,2,3" ))

;; Old rule - University Graduation Requirements
;; (defrule total-credit-req
;;     "Advise to take more credits if total credit amount is less than the required amount."
;;     ?r <- (Record {totalCredits < ?*total-credit-req*})
;;     =>
;;    (assert (enough-credits))
;;     (add (new Advice "TotalCreditsRequirement" "Too little credits" (str-cat "Have " ?r.totalCredits " credits, but need " ?*total-credit-req* ".") "ISSUE")))

;; Define templates for model classes
(import com.joshktan.advisor.model.*)
(deftemplate Course
  (declare (from-class Course)))
(deftemplate Record
  (declare (from-class Record)))
(deftemplate Advice
  (declare (from-class Advice)))

;; GLOBAL VARIABLES
(defglobal ?*total-credit-req* = (get-member com.joshktan.advisor.req.TotalCreditsRequirement TOTAL_CREDITS_REQUIRED))

;; GEN ED REQUIREMENTS

;; First Year Experience (F) Requirements
(defrule gen-ed-f
  "Advise student if Gen Ed First Year Experience requirements not satisfied."
  (not (Course {courseId == "UNIV 189"}))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed First Year Experience requirements not satisfied" "Skills for Academic Success (UNIV 189) is required, but is not listed among courses." "ISSUE")))

;; Communication (C) Requirements
(defrule gen-ed-c
  "Advise student if Gen Ed Communication requirements not satisfied."
  (not (exists (Course {courseId == "COMM 110"})))
  (not (exists (Course {courseId == "ENGL 110"})))
  (not (exists (Course {courseId == "ENGL 120"})))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Communication requirements not satisfied" "College Composition I (ENGL 110), College Composition II (ENGL 120), and Fundamentals of Public Speaking (COMM 110) are required." "ISSUE")))

;; Quantitative Reasoning (R) Requirements
(defrule gen-ed-r
  "Advise student if Gen Ed Quantitative Reasoning requirements not satisfied."
  (not (Course {courseId == "MATH 165"}))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Quantitative Reasoning requirements not satisfied" "Calculus I (MATH 165) is required, but is not listed among courses." "ISSUE")))

;; Science & Technology (S) Requirements
;; TODO - make sure all different
(defrule gen-ed-s
  "Advise student if Gen Ed Science & Technology requirements not satisfied."
  ?totalCredits <- (accumulate (bind ?count 0)                                                ;; initializer
			       (bind ?count (+ ?count ?credits))                              ;; action
			       ?count                                                         ;; result
			       (Course (credits ?credits) (courseId ?t&:(is-gen-ed ?t "S")))) ;; CE
  (test (< ?totalCredits 10))
  =>
;;  ((System.out) println (?totalCredits toString))
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Science & Technology requirements not satisfied" "At least 10 credits in the General Education Science and Technology area are required." "ISSUE")))

;; Humanities & Fine Arts (A) Requirements
;; TODO - make sure all different
(defrule gen-ed-a
  "Advise student if Gen Ed Humanities & Fine Arts requirements not satisfied."
  ?totalCredits <- (accumulate (bind ?count 0)                                                ;; initializer
			       (bind ?count (+ ?count ?credits))                              ;; action
			       ?count                                                         ;; result
			       (Course (credits ?credits) (courseId ?t&:(is-gen-ed ?t "A")))) ;; CE
  (test (< ?totalCredits 6))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Humanities & Fine Arts requirements not satisfied" "At least 6 credits in the General Education Humanities & Fine Arts area are required." "ISSUE")))

;; Social & Behavioral Sciences (B) Requirements
;; TODO - make sure all different
(defrule gen-ed-b
  "Advise student if Gen Ed Social & Behavioral Sciences requirements not satisfied."
  ?totalCredits <- (accumulate (bind ?count 0)                                                ;; initializer
			       (bind ?count (+ ?count ?credits))                              ;; action
			       ?count                                                         ;; result
			       (Course (credits ?credits) (courseId ?t&:(is-gen-ed ?t "B")))) ;; CE
  (test (< ?totalCredits 6))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Social & Behavioral Sciences requirements not satisfied" "At least 6 credits in the General Education Social & Behavioral Sciences area are required." "ISSUE")))

;; Wellness (W) Requirements
;; TODO - make sure all different
(defrule gen-ed-w
  "Advise student if Gen Ed Wellness requirements not satisfied."
  ?totalCredits <- (accumulate (bind ?count 0)                                                ;; initializer
			       (bind ?count (+ ?count ?credits))                              ;; action
			       ?count                                                         ;; result
			       (Course (credits ?credits) (courseId ?t&:(is-gen-ed ?t "W")))) ;; CE
  (test (< ?totalCredits 2))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Wellness requirements not satisfied" "At least 6 credits in the General Education Wellness area are required." "ISSUE")))

;; Cultural Diversity (D) Requirements
(defrule gen-ed-d
  "Advise student if Gen Ed Cultural Diversity requirements not satisfied."
  (not (exists (Course (courseId ?t&:(is-gen-ed ?t "D")))))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Cultural Diversity requirements not satisfied" "At least 1 course in the General Education Cultural Diversity area is required." "ISSUE")))

;; Global Perspectives (G) Requirements
(defrule gen-ed-g
  "Advise student if Gen Ed Global Perspectives requirements not satisfied."
  (not (exists (Course (courseId ?t&:(is-gen-ed ?t "G")))))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Global Perspectives requirements not satisfied" "At least 1 course in the General Education Global Perspectives area is required." "ISSUE")))

;; Gen Ed Lower Division Requirements
(defrule gen-ed-ld
  "Adivce student if Gen Ed lower division requirements are not satisfied."
  (exists (gen-ed-ld-not-satisfied))
  =>
  (assert (gen-ed-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed lower division requirements not satisfied" "See curriculum guide for details." "ISSUE")))

;; Gen Ed Upper Division Requirements
(defrule gen-ed-ud
  "Advise student if Gen Ed upper division requirements not satisfied."
  (not (exists (Course {courseId == "ENGL 321" || courseId == "ENGL 324"})))
  =>
  (assert (gen-ed-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed upper division requirements not satisfied" "Either Writing in the Technical Professions (ENGL 321) or Writing in the Sciences (ENGL 324) is required, but neither is listed among courses." "ISSUE")))

;; Gen Ed Requirements
(defrule gen-ed
  "Advise student if Gen Ed requirements not satisfied."
  (or (exists (gen-ed-ld-not-satisfied)) (exists (gen-ed-ud-not-satisfied)))
  =>
  (assert (deg-req-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed requirements not satisfied" "See curriculm guide for details." "ISSUE")))

;; One Year Lab Science Sequence Requirement
(defrule lab-sci-biol-126
  (not (exists (Course {courseId == "BIOL 126"})))
  (not (exists (Course {courseId == "BIOL 126L"})))
  (not (exists (Course {courseId == "BIOL 220"})))
  (not (exists (Course {courseId == "BIOL 220L"})))
  =>
  (assert (no-biol-126-seq)))

(defrule lab-sci-chem-121
  (not (exists (Course {courseId == "CHEM 121"})))
  (not (exists (Course {courseId == "CHEM 121L"})))
  (not (exists (Course {courseId == "CHEM 122"})))
  (not (exists (Course {courseId == "CHEM 122L"})))
  =>
  (assert (no-chem-121-seq)))

(defrule lab-sci-chem-150
  (not (exists (Course {courseId == "CHEM 150"})))
  (not (exists (Course {courseId == "CHEM 160"})))
  (not (exists (Course {courseId == "CHEM 151"})))
  (not (exists (Course {courseId == "CHEM 161"})))
  =>
  (assert (no-chem-150-seq)))

(defrule lab-sci-geol-105
  (not (exists (Course {courseId == "GEOL 105"})))
  (not (exists (Course {courseId == "GEOL 105L"})))
  (not (exists (Course {courseId == "GEOL 106"})))
  (not (exists (Course {courseId == "GEOL 106L"})))
  =>
  (assert (no-geol-105-seq)))

(defrule lab-sci-phys-211
  (not (exists (Course {courseId == "PHYS 211"})))
  (not (exists (Course {courseId == "PHYS 211L"})))
  (not (exists (Course {courseId == "PHYS 212"})))
  (not (exists (Course {courseId == "PHYS 212L"})))
  =>
  (assert (no-phys-211-seq)))

(defrule lab-sci-phys-251
  (not (exists (Course {courseId == "PHYS 251"})))
  (not (exists (Course {courseId == "PHYS 251L"})))
  (not (exists (Course {courseId == "PHYS 252"})))
  (not (exists (Course {courseId == "PHYS 252L"})))
  =>
  (assert (no-phys-251-seq)))

(defrule lab-sci-seq-req
  (no-biol-126-seq)
  (no-chem-121-seq)
  (no-chem-150-seq)
  (no-geol-105-seq)
  (no-phys-211-seq)
  (no-phys-251-seq)
  =>
  (add (new Advice "LabScienceRequirement" "Lab Science Sequence requirements not satisfied" "A one year sequence of lab science courses (with corresponding labs) is required." "ISSUE")))

;; UNIVERSITY GRADUATION REQUIREMENTS
;; Total Degree Credits Requirement
(defrule total-credits
    "Advise to take more credits if total credit amount is less than the required amount."
    ?r <- (Record)
    =>
    (if (< ?r.totalCredits ?*total-credit-req*) then
    (assert (not-enough-credits))
    else
    (assert (enough-credits))))
(defrule not-enough-credits
    "Advise to take more credits if total credit amount is less than the required amount."
    (not-enough-credits)
    ?r <- (Record)
    =>
    (add (new Advice "TotalCreditsRequirement" "Too little credits" (str-cat "Have " ?r.totalCredits " credits, but need " ?*total-credit-req* ".") "ISSUE")))

;; CRITERA FOR GRADUATING WITH HONOR
(defrule graduate-with-honors
  ?record <- (Record {gpa >= 3.5})
  (not (exists (Course {grade == "NA"})))
  ;; TODO add other requirements here
  =>
   (assert (honors))
    (if (>= ?record.gpa 3.90) then
      (add (new Congrats "You will graduate summa cum laude."))
     elif (>= ?record.gpa 3.70) then
      (add (new Congrats "You will graduate magna cum laude."))
     else
      (add (new Congrats "You will graduate cum laude."))))

;; ---------------------------------------------------------------------- ;;

;; Just so you know how to do it
;; (defrule enough-credits-and-honors
;;   "enough credits and honors also"
;;   (and (honors) (enough-credits))
;;   =>
;;   ((System.out) println "Both enough credits and also honorable!"))

;; (# semesters left * 20 ) < (needed - already have) => advise warning: fill out form thing for +20 credits / semester (or summer school or postpone grad)

;; Graduating Honors (figure out how to chain rules: (if all courses have grades) && (all requirements fulfilled) => (add congrats)

;; COULD BE USEFUL:
;; The not CE can be used in arbitrary combination with the and and or CEs. You can define complex logical structures this way. For example, suppose you want a rule to fire once if for every fact (a ?x), there is a fact (b ?x). You could express that as
;; Jess> (defrule forall-example
;;   (not (and (a ?x) (not (b ?x))))
;;   =>)
;; i.e., "It is not true that for some ?x, there is an (a ?x) and no (b ?x)". This is actually how the the forall CE is implemented.

;; note: (instanceof <external-address> <class-name>)

;; COULD ALSO BE USEFUL
;; The logical conditional element lets you specify logical dependencies among facts. All the facts asserted on the RHS of a rule become dependent on the matches to the logical patterns on that rule's LHS. If any of the matches later become invalid, the dependent facts are retracted automatically.
;; (defrule rule-1
;;   (logical (faucet-open))
;;   =>
;;   (assert (water-flowing)))
;;   =>
;;   (assert (all-cour)))

;; Graduation with honor eligibility is determined in two steps:
;; Step One: Earn a minimum NDSU (institutional) GPA of 3.50
;; NDSU GPA's below 3.50 are not considered (and step two is not necessary)
;; Step Two: Earn an overall (cumulative) GPA of 3.50 or greater, which includes:
;; all credits and grades earned at NDSU
;; the inclusion of all transfer work and all attempts of repeated coursework
;;
;; Candidates who achieve an overall GPA of 3.50 or higher according to the criteria listed above will graduate:
;; Cum Laude — greater than or equal to 3.50 and less than 3.70
;; Magna Cum Laude — greater than or equal to 3.70 and less than 3.90
;; Summa Cum Laude — greater than or equal to 3.90 and up to 4.00
;; The complete Graduation with Honor policy may be reviewed in the online Undergraduate Bulletin
;; PLEASE BE AWARE grade-point averages are NOT rounded (for example, a GPA of 3.497 is not rounded to 3.5)
;; PLEASE BE AWARE graduation with honor levels are subject to change once final grades are determined and posted to the official academic record

;; ;; matches any
;; (defrule any
;;   (Record (studentId ?sId))
;;   =>
;;   ((System.out) println "Testing 1,2,3" ))

;; Old rule - University Graduation Requirements
;; (defrule total-credit-req
;;     "Advise to take more credits if total credit amount is less than the required amount."
;;     ?r <- (Record {totalCredits < ?*total-credit-req*})
;;     =>
;;    (assert (enough-credits))
;;     (add (new Advice "TotalCreditsRequirement" "Too little credits" (str-cat "Have " ?r.totalCredits " credits, but need " ?*total-credit-req* ".") "ISSUE")))


Removed the defmodule MAIN definition from Init.clp

;------------------------------------------------------------------------------
;Copyright (c) 2012, Joshua Scoggins
;All rights reserved.
;
;Redistribution and use in source and binary forms, with or without
;modification, are permitted provided that the following conditions are met:
;    * Redistributions of source code must retain the above copyright
;      notice, this list of conditions and the following disclaimer.
;    * Redistributions in binary form must reproduce the above copyright
;      notice, this list of conditions and the following disclaimer in the
;      documentation and/or other materials provided with the distribution.
;    * Neither the name of Joshua Scoggins nor the
;      names of its contributors may be used to endorse or promote products
;      derived from this software without specific prior written permission.
;
;THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
;ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
;WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
;DISCLAIMED. IN NO EVENT SHALL Joshua Scoggins BE LIABLE FOR ANY
;DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
;(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
;LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
;ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
;(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
;SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;------------------------------------------------------------------------------
; Init.clp - Default Entry Point for a expert system optimization
;------------------------------------------------------------------------------
; Usually this only contains elements necessary to start the load process
; With the modifications I made to CLIPS for LLVM this usually manifests
; itself as being a batch-load command which allows multiple loads to occur as
; a single command
;------------------------------------------------------------------------------
(batch-load
  (create$ "modules/core/ModuleHeader.clp"
	        "modules/llvm/ModuleHeader.clp"
			  "modules/scheduler/ModuleHeader.clp"
			  ; Add entries to other modules here
			  ))
;(defmodule MAIN (import core ?ALL) (import llvm ?ALL))

;------------------------------------------------------------------------------
;Copyright (c) 2012, Joshua Scoggins
;All rights reserved.
;
;Redistribution and use in source and binary forms, with or without
;modification, are permitted provided that the following conditions are met:
;    * Redistributions of source code must retain the above copyright
;      notice, this list of conditions and the following disclaimer.
;    * Redistributions in binary form must reproduce the above copyright
;      notice, this list of conditions and the following disclaimer in the
;      documentation and/or other materials provided with the distribution.
;    * Neither the name of Joshua Scoggins nor the
;      names of its contributors may be used to endorse or promote products
;      derived from this software without specific prior written permission.
;
;THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
;ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
;WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
;DISCLAIMED. IN NO EVENT SHALL Joshua Scoggins BE LIABLE FOR ANY
;DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
;(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
;LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
;ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
;(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
;SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;------------------------------------------------------------------------------
; Init.clp - Default Entry Point for a expert system optimization
;------------------------------------------------------------------------------
; Usually this only contains elements necessary to start the load process
; With the modifications I made to CLIPS for LLVM this usually manifests
; itself as being a batch-load command which allows multiple loads to occur as
; a single command
;------------------------------------------------------------------------------
(batch-load
  (create$ "modules/core/ModuleHeader.clp"
	        "modules/llvm/ModuleHeader.clp"
			  "modules/scheduler/ModuleHeader.clp"
			  ; Add entries to other modules here
			  ))
(defmodule MAIN (import core ?ALL) (import llvm ?ALL))