1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
|
;;;======================================================
;;; Farmer's Dilemma Problem
;;;
;;; Another classic AI problem (cannibals and the
;;; missionary) in agricultural terms. The point is
;;; to get the farmer, the fox the cabbage and the
;;; goat across a stream.
;;; But the boat only holds 2 items. If left
;;; alone with the goat, the fox will eat it. If
;;; left alone with the cabbage, the goat will eat
;;; it.
;;; This example uses rules and object pattern
;;; matching to solve the problem.
;;;
;;; CLIPS Version 6.0 Example
;;;
;;; To execute, merely load, reset and run.
;;;======================================================
;;;***********
;;;* CLASSES *
;;;***********
;;; The status instances hold the state
;;; information of the search tree.
(defclass status (is-a USER)
(role concrete)
(pattern-match reactive)
(slot search-depth
(create-accessor write)
(type INTEGER) (range 1 ?VARIABLE) (default 1))
(slot parent
(create-accessor write)
(type INSTANCE-ADDRESS) (default ?DERIVE))
(slot farmer-location
(create-accessor write)
(type SYMBOL) (allowed-symbols shore-1 shore-2) (default shore-1))
(slot fox-location
(create-accessor write)
(type SYMBOL) (allowed-symbols shore-1 shore-2) (default shore-1))
(slot goat-location
(create-accessor write)
(type SYMBOL) (allowed-symbols shore-1 shore-2) (default shore-1))
(slot cabbage-location
(create-accessor write)
(type SYMBOL) (allowed-symbols shore-1 shore-2) (default shore-1))
(slot last-move
(create-accessor write)
(type SYMBOL) (allowed-symbols no-move alone fox goat cabbage)
(default no-move)))
;;; The moves instances hold the information of all the moves
;;; made to reach a given state.
(defclass moves (is-a USER)
(role concrete)
(pattern-match reactive)
(slot id
(create-accessor write)
(type INSTANCE))
(multislot moves-list
(create-accessor write)
(type SYMBOL)
(allowed-symbols no-move alone fox goat cabbage)))
(defclass opposite-of
(is-a USER)
(role concrete)
(pattern-match reactive)
(slot value (create-accessor write))
(slot opposite-value (create-accessor write)))
;;;*****************
;;;* INITIAL STATE *
;;;*****************
(definstances startups
(of status)
(of opposite-of (value shore-1) (opposite-value shore-2))
(of opposite-of (value shore-2) (opposite-value shore-1)))
;;;***********************
;;;* GENERATE PATH RULES *
;;;***********************
(defrule move-alone
?node <- (object (is-a status)
(search-depth ?num)
(farmer-location ?fs))
(object (is-a opposite-of) (value ?fs) (opposite-value ?ns))
=>
(duplicate-instance ?node
(search-depth (+ 1 ?num))
(parent ?node)
(farmer-location ?ns)
(last-move alone)))
(defrule move-with-fox
?node <- (object (is-a status)
(search-depth ?num)
(farmer-location ?fs)
(fox-location ?fs))
(object (is-a opposite-of) (value ?fs) (opposite-value ?ns))
=>
(duplicate-instance ?node
(search-depth (+ 1 ?num))
(parent ?node)
(farmer-location ?ns)
(last-move fox)
(fox-location ?ns)))
(defrule move-with-goat
?node <- (object (is-a status)
(search-depth ?num)
(farmer-location ?fs)
(goat-location ?fs))
(object (is-a opposite-of) (value ?fs) (opposite-value ?ns))
=>
(duplicate-instance ?node
(search-depth (+ 1 ?num))
(parent ?node)
(farmer-location ?ns)
(last-move goat)
(goat-location ?ns)))
(defrule move-with-cabbage
?node <- (object (is-a status)
(search-depth ?num)
(farmer-location ?fs)
(cabbage-location ?fs))
(object (is-a opposite-of) (value ?fs) (opposite-value ?ns))
=>
(duplicate-instance ?node
(search-depth (+ 1 ?num))
(parent ?node)
(farmer-location ?ns)
(last-move cabbage)
(cabbage-location ?ns)))
;;;******************************
;;;* CONSTRAINT VIOLATION RULES *
;;;******************************
(defrule fox-eats-goat
(declare (salience 200))
?node <- (object (is-a status)
(farmer-location ?s1)
(fox-location ?s2&~?s1)
(goat-location ?s2))
=>
(unmake-instance ?node))
(defrule goat-eats-cabbage
(declare (salience 200))
?node <- (object (is-a status)
(farmer-location ?s1)
(goat-location ?s2&~?s1)
(cabbage-location ?s2))
=>
(unmake-instance ?node))
(defrule circular-path
(declare (salience 200))
(object (is-a status)
(search-depth ?sd1)
(farmer-location ?fs)
(fox-location ?xs)
(goat-location ?gs)
(cabbage-location ?cs))
?node <- (object (is-a status)
(search-depth ?sd2&:(< ?sd1 ?sd2))
(farmer-location ?fs)
(fox-location ?xs)
(goat-location ?gs)
(cabbage-location ?cs))
=>
(unmake-instance ?node))
;;;*********************************
;;;* FIND AND PRINT SOLUTION RULES *
;;;*********************************
(defrule recognize-solution
(declare (salience 100))
?node <- (object (is-a status)
(parent ?parent)
(farmer-location shore-2)
(fox-location shore-2)
(goat-location shore-2)
(cabbage-location shore-2)
(last-move ?move))
=>
(unmake-instance ?node)
(make-instance of moves
(id ?parent) (moves-list ?move)))
(defrule further-solution
(declare (salience 100))
?state <- (object (is-a status)
(parent ?parent)
(last-move ?move))
?mv <- (object (is-a moves)
(id ?state)
(moves-list $?rest))
=>
(modify-instance ?mv (id ?parent) (moves-list ?move ?rest)))
(defrule print-solution
(declare (salience 100))
?mv <- (object (is-a moves)
;(id [no-parent])
(moves-list no-move $?m))
=>
(unmake-instance ?mv)
;(printout t crlf "Solution found: " crlf crlf)
(bind ?length (length ?m))
(bind ?i 1)
(bind ?shore shore-2)
(while (<= ?i ?length)
(bind ?thing (nth$ ?i ?m))
(if (eq ?thing alone)
then (printout t "Farmer moves alone to " ?shore "." crlf)
else (printout t "Farmer moves with " ?thing " to " ?shore "." crlf))
(if (eq ?shore shore-1)
then (bind ?shore shore-2)
else (bind ?shore shore-1))
(bind ?i (+ 1 ?i))))
|