|
Objectius de la pràctica:
Jess és un tipus de llenguatge dissenyat per a escriure aplicacions anomenades sistemes experts (programes destinats a modelar la experiència o el coneixement humà). Jess està escrit completament en Java i suporta el desenvolupament de sistemes experts basats en regles, els quals poden estar estretament acoblats al codi escrit en el potent i portable llenguatge Java. Jess és un clònic de Clips.
Existeixen dues maneres de treballar amb Jess:
Important: Els programes en Jess s’han d’acabar amb els comandaments
(reset) i (run) o cap cosa succeirà.
Es necessari aclarir que les variables en Jess existeixen, només dintre de las regles, és a dir, que totes desapareixeran un cop les regles s’hagin disparat, excepte els valors i les variables que s’hagin introduït a la base de fets o que s’hagin definit com a variables globals.
En Jess hi ha dues formes de representar el coneixement:
1.1 Llenguatge Jess
Com que Jess és un llenguatge heretat de Clips, és bàsicament
petit. En Jess existeixen:
Exemples: (bind ?x "El valor") (bind $?llista-compres (create$ ous pa llet))
Els fets no ordenats són una estructura. Contenen un conjunt de slots determinats els que poden ésser accedits per el seu nom.
Mentre que els fets ordenats poden utilitzar-se sense definició prèvia, els no ordenats s’han de definir emprant el constructor deftemplate.
Els fets es col·loquen en la llista de fets fent servir la funció assert y s’eliminen amb la funció retract.
On les cadenes que són dintre de < > especifiquen un tipus
de data que s’ha de donar; les que són dintre de [ ] són
opcionals i les que tenen * al seu costat, indiquen que poden aparèixer
zero o més vegades.
El <nom-funció> ha de ser un àtom; Cada < paràmetre> ha de ser un nom de variable. La cadena opcional <comentari> és una cadena que comença i acaba per " i que descriu el propòsit de la funció. Pot haver-hi un nombre arbitrari de expressions <expr>. L’especificador opcional <retorn-especificador> dona un valor de retorn de la funció.
Exemple: (deffunction max (?a ?b)
Exemple: (deftemplate cotxes
Exemple:
Exemple:
Nota: Per a definir una variable global cal posar asteriscs abans
y després del nom de la variable i també, sempre que es refereixi
a la mateixa.
Aquest programa consisteix en treure bastonets d’una pila. El que agafa l’últim perd. Com a variables que s’han d’introduir per teclat, es tenen la quantitat de bastonets que hi ha i qui, ordinador o humà, els agafa primer. Com a màxim es poden treure 3 bastonets y com a mínim 1.
L’algoritme utilitzat pel ordinador per a determinar quina quantitat de bastonets agafa, consisteix en dividir el nombre de bastonets que són a la pila per quatre i treure’ls d’acord amb la resta. Per això, primer es defineix un fet no ordenat, utilitzant el constructor deftemplate. Aquest serveix per a definir la llista de fets que seran vertaders quan el sistema Jess s’iniciï, es a dir, que estaran a la base de fets des del començament . Quan arribi el torn del ordinador, consultarà aquesta llista per a determinar la quantitat de bastonets a agafar. També, s’ha definit un fet per defecte que és el que comença l’execució de les regles.
Les regles es defineixen de la mateixa manera que la vista abans. Per
exemple la regla:
El nom de la regla és "good-player-choice" i es dispararà
quan a la base de fets estiguin els fets (phase choose-player) i (player-select
?player&:(or (eq ?player c) (eq ?player h))). El segon s’acomplirà
quan la variable player sigui o c o h. L’operador &:
anomenat "predicate constraint" s’utilitza per condicionar el fet.
Els fets quan són introduïts a la base de fets tenen un número d’identificació, el qual és necessari per extreure’ls. La manera de manejar-los és fer una assignació a una variable. Per exemple el cas, ?phase <- (phase choose-player) i així, fent un retract es pot extreure de la base de fets.
Per a poder executar aquesta aplicació, és necessari introduir
la sentència java jess.Main examples\sticks.clp.
; **************
; FACT TEMPLATES
; **************
; The phase fact indicates the current action to be undertaken
before the game can begin
; (phase
; <action>) ; Either choose-player or select-pile-size
; The player-select fact contains the human's response
to the "Who moves first?" question.0
; (player-select0
; <choice>) ; Valid responses are c (for computer)
and h (for human).
; The pile-select fact contains the human's response
to the "How many sticks in the pile?" question.0
; (pile-select
; <choice>) ; Valid responses are integers greater
than zero.
; The pile-size fact contains the current number of sticks
in the stack.
; (pile-size
; <sticks>) ; An integer greater than zero.
; The player-move fact indicates whose turn it is.
; (player-move
; <player) ; Either c (for computer) or h (for human).
; The human-takes fact contains the human's response
to the "How many sticks do you wish to take?" question.
; (human-takes
; <choice>) ; Valid responses are 1, 2, and 3.
; The take-sticks facts indicate how many sticks the
computer should take based on the remainder when the stack
; size is divided by 4.
(deftemplate take-sticks
(slot how-many) ; Number of sticks to take.
(slot for-remainder)) ; Remainder when stack is divided
by 4.
; ********
; DEFFACTS
; ********
(deffacts initial-phase
(phase choose-player))
(deffacts take-sticks-information
(take-sticks (how-many 1) (for-remainder 1)) ; si el
reste de ( N° sticks / 4) es 1 llavors agafar 1 stick
(take-sticks (how-many 1) (for-remainder 2)) ; si el
reste de ( N° sticks / 4) es 2 llavors agafar 1 stick
(take-sticks (how-many 2) (for-remainder 3)) ; si el
reste de ( N° sticks / 4) es 3 llavors agafar 2 stick
(take-sticks (how-many 3) (for-remainder 0))) ; si el
reste de ( N° sticks / 4) es 0 llavors agafar 3 stick
; ********
; DEFFUNCTIONS
; ********
(deffunction ask-start-again ()
(printout t "Play again? (y/n) ")
(if (eq (read) y) then
(assert (phase choose-player))))
; *****
; RULES
; *****
; RULE player-select
; IF
; The phase is to choose the first player
; THEN
; Ask who should move first, and Get the human's response
(defrule player-select
(phase choose-player)
=>
(printout t "Who moves first (Computer: c " "Human: h)?
")
(assert (player-select (read))))
; RULE good-player-choice
; IF
; The phase is to choose the first player, and The human
has given a valid response
; THEN
; Remove unneeded information, and Indicate whose turn
it is, and Indicate that the pile size should be chosen
(defrule good-player-choice
?phase <- (phase choose-player)
?choice <- (player-select ?player&:(or (eq ?player
c) (eq ?player h)))
=>
(retract ?phase ?choice)
(assert (player-move ?player))
(assert (phase select-pile-size)))
; RULE bad-player-choice
; IF
; The phase is to choose the first player, and The human
has given a invalid response
; THEN
; Remove unneeded information, and Indicate that the
first player should be chosen again, and Print the valid
; choices
(defrule bad-player-choice
?phase <- (phase choose-player)
?choice <- (player-select ?player&~c&~h)
=>
(retract ?phase ?choice)
(assert (phase choose-player))
(printout t "Choose c or h." crlf))
; RULE pile-select
; IF
; The phase is to choose the pile size
; THEN
; Ask what the pile size should be, and Get the human's
response
(defrule pile-select
(phase select-pile-size)
=>
(printout t "How many sticks in the pile? ")
(assert (pile-select (read))))
; RULE good-pile-choice
; IF
; The phase is to choose the pile size, and The human
has given a valid response
; THEN
; Remove unneeded information, and Store the pile size
(defrule good-pile-choice
?phase <- (phase select-pile-size)
?choice <- (pile-select ?size&:(integerp ?size)
&:(> ?size 0))
=>
(retract ?phase ?choice)
(assert (pile-size ?size)))
; RULE bad-pile-choice
; IF
; The phase is to choose the pile size, and The human
has given a invalid response
; THEN
; Remove unneeded information, and Indicate that the
pile size should be chosen again, and Print the valid
; choices
(defrule bad-pile-choice
?phase <- (phase select-pile-size)
?choice <- (pile-select ?size&:(or (not (integerp
?size)) (<= ?size 0)))
=>
(retract ?phase ?choice)
(assert (phase select-pile-size))
(printout t "Choose an integer greater than zero." crlf))
; RULE computer-loses
; IF
; The pile size is 1, and It is the computer's move
; THEN
; Print that the computer has lost the game
(defrule computer-loses
?pile <- (pile-size 1)
?move <- (player-move c)
=>
(printout t "Computer must take the last stick!" crlf)
(printout t "I lose!" crlf)
(retract ?pile)
(retract ?move)
(ask-start-again))
; RULE human-loses
; IF
; The pile size is 1, and It is the human's move
; THEN
; Print that the human has lost the game
(defrule human-loses
?pile <- (pile-size 1)
?move <- (player-move h)
=>
(printout t "You must take the last stick!" crlf)
(printout t "You lose!" crlf)
(retract ?pile)
(retract ?move)
(ask-start-again))
; RULE get-human-move
; IF
; The pile size is greater than 1, and It is the human's
move
; THEN
; Ask how many sticks to take, and Get the human's response
(defrule get-human-move
(pile-size ?size&:(> ?size 1))
(player-move h)
=>
(printout t "How many sticks do you wish to take? ")
(assert (human-takes (read))))
; RULE good-human-move
; IF
; There is a pile of sticks, and The human has chosen
how many sticks to take, and It is the human's move, and
; The human's choice is valid
; THEN
; Remove unneeded information, and Compute the new pile
size, and Update the pile size, and Print the number
; of sticks left in the stack, and Trigger the computer
player's turn
(defrule good-human-move
?pile <- (pile-size ?size)
?move <- (human-takes ?choice)
?whose-turn <- (player-move h)
(test (and (integerp ?choice)
(>= ?choice 1)
(<= ?choice 3)
(< ?choice ?size)))
=>
(retract ?pile ?move ?whose-turn)
(bind ?new-size (- ?size ?choice))
(assert (pile-size ?new-size))
(printout t ?new-size " stick() left in the pile." crlf)
(assert (player-move c)))
; RULE bad-human-move
; IF
; There is a pile of sticks, and The human has chosen
how many sticks to take, and It is the human's move, and
; The human's choice is invalid
; THEN
; Print the valid choices, and Remove unneeded information,
and Retrigger the human player's move
(defrule bad-human-move
(pile-size ?size)
?move <- (human-takes ?choice)
?whose-turn <- (player-move h)
(test (or (not (integerp ?choice))
(< ?choice 1)
(> ?choice 3)
(>= ?choice ?size)))
=>
(printout t "Number of sticks must be between 1 and 3,"
crlf "and you must be forced to take the last "
"stick." crlf)
(retract ?move ?whose-turn)
(assert (player-move h)))
; RULE computer-move
; IF
; It is the computers's move, and The pile size is greater
than 1, and The computer's response is available
; THEN
; Remove unneeded information, and Compute the new pile
size, and Print the number of sticks left in the
; stack, and Update the pile size, and Trigger the human
players move
(defrule computer-move
?whose-turn <- (player-move c)
?pile <- (pile-size ?size&:(> ?size 1))
(take-sticks (how-many ?number) (for-remainder ?X&:(=
?X (mod ?size 4))))
=>
(retract ?whose-turn ?pile)
(bind ?new-size (- ?size ?number))
(printout t "Computer takes " ?number " stick(s)." crlf)
(printout t ?new-size " stick(s) left in the pile." crlf)
(assert (pile-size ?new-size))
(assert (player-move h)))
(reset)
(run)
Una vegada que el jugador ha decidit xutar, es tindrà en compta la distància de la pilota a la porteria per a determinar si es gol o no. Si aquesta és menor a 20 unitats es considerarà gol; en cas contrari surt fora dels límits de la porteria.
Seria convenient anar visualitzant per pantalla un missatge que indiqui
l’acció presa (xutar o no xutar) i si la pilota ha entrat a porteria
(gol o fora).