Использование существует в инструкции if

#clips #conways-game-of-life

#клипы #конвей-игра жизни

Вопрос:

Я пытаюсь реализовать game of life в CLIPS, и я столкнулся с проблемой (отсутствует объявление функции для ‘exists’) с инструкцией exists при попытке подсчитать соседей для каждой ячейки. Нельзя ли использовать инструкцию exists в инструкции if? Как мне следует подойти к задаче подсчета соседей?

Это шаблон ячейки:

 (deftemplate cell
    (slot iteration)
    (slot x)
    (slot y)
)
  

Это функция:

 (deffunction countneighbors (?i ?j ?c)
    (bind ?*neighbors* 0)
    (if (exists (cell (iteration ?c) (x (- ?i 1)) (y (- ?j 1)))) then
        (bind ?*neighbors* (  0 1 ?*neighbors*))
    )
    (if (exists (cell (iteration ?c) (x (- ?i 1)) (y ?j))) then
        (bind ?*neighbors* (  0 1 ?*neighbors*))
    )
.
.
.
)
  

Ответ №1:

Условный элемент exists не является функцией, поэтому вы не можете вызывать его как таковой. Оно может быть использовано только в условиях правила. Вы можете использовать функции запроса фактов, если хотите выполнить итерацию по группе фактов вне условий правила:

          CLIPS (6.31 2/3/18)
CLIPS> 
(deftemplate cell
   (slot iteration (default 0))
   (slot x)
   (slot y))
CLIPS> 
(deffacts cells
   (cell (x 1) (y 1))  
   (cell (x 1) (y 2))  ;;; - * *
   (cell (x 2) (y 3))  ;;; * - -
   (cell (x 3) (y 3))) ;;; * - -
CLIPS>    
(deffunction count-neighbors (?i ?j ?c)
   (bind ?neighbors 0)
   (do-for-all-facts ((?cell cell)) 
                     (and (= ?cell:iteration ?c)
                          (<= (abs (- ?i ?cell:x)) 1)
                          (<= (abs (- ?j ?cell:y)) 1)
                          (or (!= ?i ?cell:x) (!= ?j ?cell:y)))
      (bind ?neighbors (  1 ?neighbors)))
   ?neighbors)

CLIPS> (reset)
CLIPS> (count-neighbors 1 1 0)
1
CLIPS> (count-neighbors 2 2 0)
4
CLIPS> (count-neighbors 2 1 0)
2
CLIPS> 
  

Вот метод определения соседей с использованием правил:

 CLIPS> (clear)
CLIPS> 
(deftemplate cell
   (slot iteration (default 0))
   (slot x)
   (slot y)
   (slot alive (default 0))
   (multislot neighbors))
CLIPS>    
(deftemplate direction
   (slot d)
   (slot dx)
   (slot dy))
CLIPS> 
(deffacts cells
   (cell (x 1) (y 1) (alive 1))  
   (cell (x 1) (y 2) (alive 1))
   (cell (x 1) (y 3))
   (cell (x 2) (y 1))
   (cell (x 2) (y 2))  
   (cell (x 2) (y 3) (alive 1))
   (cell (x 3) (y 1))
   (cell (x 3) (y 2))  
   (cell (x 3) (y 3) (alive 1)))
CLIPS> 
(deffacts directions
   (direction (d n)  (dx 0)  (dy 1))
   (direction (d ne) (dx 1)  (dy 1))
   (direction (d e)  (dx 1)  (dy 0))
   (direction (d se) (dx 1)  (dy -1))
   (direction (d s)  (dx 0)  (dy -1))
   (direction (d sw) (dx -1) (dy -1))
   (direction (d w)  (dx -1) (dy 0))
   (direction (d nw) (dx -1) (dy 1))) 
CLIPS>               
(defrule add-neighbor
   ?c <- (cell (x ?x) (y ?y) (neighbors $?n))
   (direction (d ?d) (dx ?dx) (dy ?dy))
   (cell (x =(  ?x ?dx)) (y =(  ?y ?dy)) (alive 1))
   (test (not (member$ ?d ?n)))
   =>
   (modify ?c (neighbors $?n ?d))) 
CLIPS> (reset)
CLIPS> (run)
CLIPS> (facts)
f-0     (initial-fact)
f-7     (cell (iteration 0) (x 3) (y 1) (alive 0) (neighbors))
f-10    (direction (d n) (dx 0) (dy 1))
f-11    (direction (d ne) (dx 1) (dy 1))
f-12    (direction (d e) (dx 1) (dy 0))
f-13    (direction (d se) (dx 1) (dy -1))
f-14    (direction (d s) (dx 0) (dy -1))
f-15    (direction (d sw) (dx -1) (dy -1))
f-16    (direction (d w) (dx -1) (dy 0))
f-17    (direction (d nw) (dx -1) (dy 1))
f-19    (cell (iteration 0) (x 2) (y 1) (alive 0) (neighbors nw w))
f-21    (cell (iteration 0) (x 3) (y 2) (alive 0) (neighbors nw n))
f-25    (cell (iteration 0) (x 2) (y 2) (alive 0) (neighbors w sw ne n))
f-26    (cell (iteration 0) (x 3) (y 3) (alive 1) (neighbors w))
f-28    (cell (iteration 0) (x 2) (y 3) (alive 1) (neighbors e sw))
f-30    (cell (iteration 0) (x 1) (y 2) (alive 1) (neighbors ne s))
f-31    (cell (iteration 0) (x 1) (y 1) (alive 1) (neighbors n))
f-33    (cell (iteration 0) (x 1) (y 3) (alive 0) (neighbors s e))
For a total of 18 facts.
CLIPS> 
  

Вот полная реализация, которая сохраняет только факты, представляющие активные ячейки.

 (deffacts start-phase
   (phase neighbors))

(deftemplate cell
   (slot x)
   (slot y)
   (slot alive (default no))
   (multislot neighbors))

(deffacts glider
   (cell (x 1) (y 2) (alive yes))
   (cell (x 2) (y 3) (alive yes))
   (cell (x 3) (y 1) (alive yes))
   (cell (x 3) (y 2) (alive yes))
   (cell (x 3) (y 3) (alive yes)))

(deftemplate direction
   (slot tag)
   (slot dx (default 0))
   (slot dy (default 0)))

(deffacts directions
   (direction (tag n) (dy 1))
   (direction (tag ne) (dx 1) (dy 1))
   (direction (tag e) (dx 1))
   (direction (tag se) (dx 1) (dy -1))
   (direction (tag s) (dy -1))
   (direction (tag sw) (dx -1) (dy -1))
   (direction (tag w) (dx -1))
   (direction (tag nw) (dx -1) (dy 1)))

(defrule check-for-life
   (phase neighbors)
   (cell (x ?x) (y ?y) (alive yes))
   (direction (tag ?tag) (dx ?dx) (dy ?dy))
   (not (cell (x =(  ?x ?dx)) (y =(  ?y ?dy))))
   =>
   (assert (cell (x (  ?x ?dx)) (y (  ?y ?dy)))))

(defrule add-neighbor
   (phase neighbors)
   ?c <- (cell (x ?x) (y ?y) (neighbors $?n))
   (direction (tag ?t) (dx ?dx) (dy ?dy))
   (cell (x =(  ?x ?dx)) (y =(  ?y ?dy)) (alive yes))
   (test (not (member$ ?t ?n)))
   =>
   (modify ?c (neighbors ?t ?n)))

(defrule remove-neighbor
   (phase neighbors)
   ?c <- (cell (x ?x) (y ?y) (neighbors $?b ?t $?e))
   (direction (tag ?t) (dx ?dx) (dy ?dy))
   (not (cell (x =(  ?x ?dx)) (y =(  ?y ?dy)) (alive yes)))
   =>
   (modify ?c (neighbors ?b ?e)))

(defrule life-to-death
   (phase life)
   ?c <- (cell (alive yes) (neighbors $?n))
   (test (not (= (length$ ?n) 2)))
   (test (not (= (length$ ?n) 3)))
   =>
   (retract ?c)) 

(defrule death-to-life
   (phase life)
   ?c <- (cell (alive no) (neighbors $?n))
   (test (= (length$ ?n) 3))
   =>
   (modify ?c (alive yes))) 

(defrule death-to-death
   (phase life)
   ?c <- (cell (alive no) (neighbors $?n))
   (test (!= (length$ ?n) 3))
   =>
   (retract ?c)) 

(defrule neighbors-to-life
   (declare (salience -10))
   ?p <- (phase neighbors)
   =>
   (retract ?p)
   (assert (phase life)))

(defrule life-to-neighbors
   (declare (salience -10))
   ?p <- (phase life)
   =>
   (retract ?p)
   (assert (phase neighbors)))
  

Комментарии:

1. Спасибо за ваш ответ! Я только что понял, что в моем первоначальном сообщении я забыл упомянуть, что ?c — это счетчик того, сколько итераций game of life прошло. Я не уверен, что вы подумали?c, но я почти уверен, что это отличается от того, что я имел в виду. Можете ли вы предоставить определение для функции «делать для всех фактов»?

2. Обновленный ответ, чтобы включить проверку итерации в функцию count-neighbors, где параметр ?c был затенен переменной do-for-all-facts ?c. Функции запроса фактов описаны в руководстве по базовому программированию ( clipsrules.sourceforge.net/documentation/v630/bpg.pdf ).