Объектно-ориентированные средства в CLIPS
Следующие три правила будут проверять, правильно ли снаряжен пистолет.
(defrule check (object (name [PPK]) (safety on) (magazine out) ?T ← (range-test (check no)) › (send [PPK] clear) (modify?T (check yes))
Правило check заключается в том, что если пистолет стоит на предохранителе (safety on), обойма вынута (magazine out) и пистолет не был проверен, то нужно очистить патронник и проверить, нет ли в нем патрона. Обработчик сообщения clear для класса pistol будет выглядеть следующим образом:
(defmessage-handler pistol clear () (dynamic-put chamber 0) (ppinstance))
В первой строке объявляется, что clear является обработчиком сообщения для класса pistol, причем этот обработчик не требует передачи аргументов. Оператор во второй строке "очищает" патронник. Присвоение выполняется независимо от того, какое текущее значение имеет слот chamber, – 0 или 1. Оператор в третьей строке требует, чтобы экземпляр распечатал информацию о текущем состоянии своих слотов.
В следующих двух правилах обрабатываются ситуации, когда пистолет снаряжен неправильно, – не установлен на предохранитель или в него вставлена обойма. Правило correct1 устанавливает пистолет на предохранитель, а правило correct2 извлекает из него обойму.
(defrule correctl (object (name [PPK]) (safety off)) (range-test (check no)) › (send [PPK] safety on) ) (defrule correct2 (object (name [PPK]) (safety on) (magazine in)) (range-test (check no)) › (send [PPK] drop))
Как и при разработке предыдущего правила, нам понадобятся обработчики сообщений safety и drop.
(defmessage-handler pistol safety (?on-off) (dynamic-put safety?on-off) (if (eq?on-off on) then (dynamic-put hammer down) ))
Обработчик сообщения safety принимает единственный аргумент, который может иметь только два символических значения on или off. В противном случае нам пришлось бы разработать два обработчика: один для сообщения safety-on, а другой – для сообщения safety-off. Учтите, что в некоторых моделях, например в Walther PPK, при установке пистолета на предохранитель патронник очищается автоматически.
Обработчик сообщения drop просто извлекает обойму из пистолета.
(defmessage-handler pistol drop () (dynamic-put magazine out))
Теперь, когда обеспечено правильное исходное снаряжение пистолета, можно приступить к стрельбе. Следующее правило обеспечивает вставку обоймы в пистолет перед стрельбой:
(defrule mag-in (object (name [PPK]) (safety on) (magazine out)) (range-test (fired no) (check yes)) › (send [PPK] seat))
Обработчик сообщения seat выполняет действия, противоположные тем, которые выполняет обработчик drop.
(defmessage-handler pistol seat () (dynamic-put magazine in))
Можно было бы, конечно, включить в программу и следующее правило mag-in:
(defrule mag-in ?gun ← (object (name [PPK]) (safety on) (magazine out)) (range-test (fired no) (check yes)) › (modify?gun (magazine in))
Но это противоречит одному из принципов объектно-ориентированного программирования, который гласит, что объект должен самостоятельно обрабатывать содержащиеся в нем данные. Следующее правило обеспечивает снаряжение обоймы патронами:
(defrule load (object (name [PPK]) (magazine in) (chamber 0)) › (send [PPK] rack))