CLIPS defrule checking if multiple sides of a box are taken

212 views Asked by At

I am working on a program that will tell me which moves to make in a dots-and-boxes game. I am trying to implement a defrule that will check to see if a box already has 2 of the possible 4 sides taken. If this is the case then I don't want to take one of the remaining two lines, as that will give the opponent a free point.

(defrule Player_Move_No_Box_1_1
(next_turn p)
(turn_num ?t_num)
(test(> ?t_num 3))
(line ?l1&~1)
(not(line 1))
=>
(if
   (not(or(and(any-factp ((?l line)) (member$ (+ ?l1 3) ?l:implied))(any-factp ((?l line)) (member$ (+ ?l1 4) ?l:implied)))
       (and(any-factp ((?l line)) (member$ (+ ?l1 3) ?l:implied))(any-factp ((?l line)) (member$ (+ ?l1 7) ?l:implied)))
       (and(any-factp ((?l line)) (member$ (+ ?l1 4) ?l:implied))(any-factp ((?l line)) (member$ (+ ?l1 7) ?l:implied)))))
then
   (printout t "Take line #1" crlf)
   (assert(line 1))
   (assert(next_turn c))))

I've been trying a lot of different things, but this is the last code I tried to use, but with no success. For this piece of code I'm looking at line 1 (clockwise starting from the top of a box the boxes are numbered: x, x+4, x+7, x+3). Is there a simpler way of making this check, or will this way work and I've just messed the code up somewhere?

1

There are 1 answers

0
Gary Riley On BEST ANSWER

I would suggest explicitly representing each possible line as a fact and denote in the fact whether the line has been taken. Also do the pattern matching in the conditions of the rules rather than the actions.

CLIPS>  
(deftemplate line
   (slot id)
   (slot taken (default no)))     
CLIPS>       
(defrule Player_Move_Top_Line
   ?take <- (line (id ?l1) (taken no))
   (line (id =(+ ?l1 3)) (taken ?t3))
   (line (id =(+ ?l1 4)) (taken ?t4))
   (line (id =(+ ?l1 7)) (taken ?t7))
   (test (not (or (and (eq ?t3 yes) (eq ?t4 yes) (eq ?t7 no))
                  (and (eq ?t3 yes) (eq ?t4 no) (eq ?t7 yes))
                  (and (eq ?t3 no) (eq ?t4 yes) (eq ?t7 yes)))))
   =>
   (printout t "Take line #" ?l1 crlf)
   (modify ?take (taken yes)))
CLIPS>

I've stripped out the turn information from your original rule just to make it easier to test it.

CLIPS> (assert (line (id 0)) (line (id 3)) (line (id 4)) (line (id 7)))
<Fact-4>
CLIPS> (agenda)
0      Player_Move_Top_Line: f-1,f-2,f-3,f-4
For a total of 1 activation.
CLIPS> (reset)
CLIPS> (assert (line (id 0)) (line (id 3)) (line (id 4)) (line (id 7) (taken yes)))
<Fact-4>
CLIPS> (agenda)
0      Player_Move_Top_Line: f-1,f-2,f-3,f-4
For a total of 1 activation.
CLIPS> (reset)
CLIPS> (assert (line (id 0)) (line (id 3)) (line (id 4) (taken yes)) (line (id 7)))
<Fact-4>
CLIPS> (agenda)
0      Player_Move_Top_Line: f-1,f-2,f-3,f-4
For a total of 1 activation.
CLIPS> (reset)
CLIPS> (assert (line (id 0)) (line (id 3) (taken yes)) (line (id 4)) (line (id 7)))
<Fact-4>
CLIPS> (agenda)
0      Player_Move_Top_Line: f-1,f-2,f-3,f-4
For a total of 1 activation.
CLIPS> (reset)
CLIPS> (assert (line (id 0)) (line (id 3) (taken yes)) (line (id 4) (taken yes)) (line (id 7)))
<Fact-4>
CLIPS> (agenda)
CLIPS> (reset)
CLIPS> (assert (line (id 0)) (line (id 3) (taken yes)) (line (id 4)) (line (id 7) (taken yes)))
<Fact-4>
CLIPS> (agenda)
CLIPS> (reset)
CLIPS> (assert (line (id 0)) (line (id 3)) (line (id 4) (taken yes)) (line (id 7) (taken yes)))
<Fact-4>
CLIPS> (agenda)
CLIPS> (reset)
CLIPS> (assert (line (id 0)) (line (id 3) (taken yes)) (line (id 4) (taken yes)) (line (id 7) (taken yes)))
<Fact-4>
CLIPS> (agenda)
0      Player_Move_Top_Line: f-1,f-2,f-3,f-4
For a total of 1 activation.
CLIPS>