examples/ggp-wam.lisp @ ec2fab887b0f

Constant can just use the functor symbol directly
author Steve Losh <steve@stevelosh.com>
date Fri, 15 Jul 2016 23:12:18 +0000
parents 5edeeac89e03
children (none)
(in-package #:bones.wam)

;;;; Rules
(setf *database* (make-database))

(push-logic-frame)

(fact (role robot))

(facts (init (off p))
       (init (off q))
       (init (off r))
       (init (off s))
       (init (step 1)))


(rule (next (on p))
  (does robot a)
  (true (off p)))
(rule (next (on q))
  (does robot a)
  (true (on q)))
(rule (next (on r))
  (does robot a)
  (true (on r)))
(rule (next (off p))
  (does robot a)
  (true (on p)))
(rule (next (off q))
  (does robot a)
  (true (off q)))
(rule (next (off r))
  (does robot a)
  (true (off r)))

(rule (next (on p))
  (does robot b)
  (true (on q)))
(rule (next (on q))
  (does robot b)
  (true (on p)))
(rule (next (on r))
  (does robot b)
  (true (on r)))
(rule (next (off p))
  (does robot b)
  (true (off q)))
(rule (next (off q))
  (does robot b)
  (true (off p)))
(rule (next (off r))
  (does robot b)
  (true (off r)))

(rule (next (on p))
  (does robot c)
  (true (on p)))
(rule (next (on q))
  (does robot c)
  (true (on r)))
(rule (next (on r))
  (does robot c)
  (true (on q)))
(rule (next (off p))
  (does robot c)
  (true (off p)))
(rule (next (off q))
  (does robot c)
  (true (off r)))
(rule (next (off r))
  (does robot c)
  (true (off q)))

(rule (next (off s))
  (does robot a)
  (true (off s)))
(rule (next (off s))
  (does robot b)
  (true (off s)))
(rule (next (off s))
  (does robot c)
  (true (off s)))
(rule (next (on s))
  (does robot a)
  (true (on s)))
(rule (next (on s))
  (does robot b)
  (true (on s)))
(rule (next (on s))
  (does robot c)
  (true (on s)))
(rule (next (off s))
  (does robot d)
  (true (on s)))
(rule (next (on s))
  (does robot d)
  (true (off s)))

(rule (next (on p))
  (does robot d)
  (true (on p)))
(rule (next (off p))
  (does robot d)
  (true (off p)))

(rule (next (on q))
  (does robot d)
  (true (on q)))
(rule (next (off q))
  (does robot d)
  (true (off q)))

(rule (next (on r))
  (does robot d)
  (true (on r)))
(rule (next (off r))
  (does robot d)
  (true (off r)))

(rule (next (step ?y))
  (true (step ?x))
  (succ ?x ?y))


(facts (succ 1 2)
       (succ 2 3)
       (succ 3 4)
       (succ 4 5)
       (succ 5 6)
       (succ 6 7)
       (succ 7 8))

(facts (legal robot a)
       (legal robot b)
       (legal robot c)
       (legal robot d))


(rule (goal robot 100)
  (true (on p))
  (true (on q))
  (true (on r))
  (true (on s)))
(rule (goal robot 0)
  (true (off p)))
(rule (goal robot 0)
  (true (off q)))
(rule (goal robot 0)
  (true (off r)))
(rule (goal robot 0)
  (true (off s)))


(rule (terminal)
  (true (step 8)))
(rule (terminal)
  (true (on p))
  (true (on q))
  (true (on r))
  (true (on s)))

(finalize-logic-frame)


(defun extract (key results)
  (mapcar (lambda (result) (getf result key)) results))


(defun initial-state ()
  (extract '?what (query-all (init ?what))))

(defun terminalp ()
  (prove (terminal)))


(defun equiv-roles (move1 move2)
  (eq (car move1) (car move2)))

(defun legal-moves ()
  (let* ((individual-moves
           (query-map (lambda (move)
                        (cons (getf move '?role)
                              (getf move '?action)))
                      (legal ?role ?action)))
         (joint-moves
           (apply #'map-product #'list
                  (equivalence-classes #'equiv-roles individual-moves))))
    joint-moves))

(defun roles ()
  (extract '?role (query-all (role ?role))))

(defun goal-value (role)
  (getf (invoke-query `(goal ,role ?goal))
        '?goal))

(defun goal-values ()
  (invoke-query-all `(goal ?role ?goal)))

(defun next-state ()
  (extract '?what (query-all (next ?what))))


(defun apply-state (state)
  (push-logic-frame)
  (loop :for fact :in state
        :do (invoke-fact `(true ,fact)))
  (finalize-logic-frame))

(defun apply-moves (moves)
  (push-logic-frame)
  (loop :for (role . action) :in moves
        :do (invoke-fact `(does ,role ,action)))
  (finalize-logic-frame))


(defun clear-state ()
  (pop-logic-frame))

(defun clear-moves ()
  (pop-logic-frame))


(defun perform-move (joint-move)
  (prog2
    (apply-moves joint-move)
    (next-state)
    (clear-moves)))


(defvar *count* 0)
(defvar *role* nil)


;; nodes: (state . path)
(defun depth-first-search (&key exhaust)
  (let ((*count* 0)
        (*role* (first (roles)))
        (nodes (make-queue)))
    (enqueue (cons (initial-state) nil) nodes)
    (pprint
      (while (not (queue-empty-p nodes))
        (incf *count*)
        (destructuring-bind (state . path)
            (dequeue nodes)
          (apply-state state)
          ; (format t "Searching: ~S (~D remaining)~%" state (length remaining))
          (if (terminalp)
            (prog1
                (if (and (not exhaust) (= 100 (goal-value *role*)))
                  (list state (reverse path))
                  nil)
              (clear-state))
            (let ((children
                    (loop :for joint-move :in (legal-moves)
                          :collect (cons (perform-move joint-move)
                                         (cons joint-move path)))))
              (clear-state)
              (queue-append nodes children))))))
    (format t "~%Searched ~D nodes.~%" *count*)))