; Blocks World from Winston&Horn
#-:classes (load "classes")
; abstract classes for ball types
; basic blocks support nothing
(defclass basic-block (name width height position supported-by))
(defmethod basic-block :support-for () nil)
(defmethod basic-block :top-location ()
(list (+ (first position) (/ width 2))
(+ (second position) height)))
; movable-blocks can be moved
(defclass movable-block () () basic-block)
; load-bearing blocks can support other blocks, and can be moved
(defclass load-bearing-block (support-for) () movable-block)
; we can't have multiple inheritance, so we need a separate class for table
; table blocks can support other blocks but cannot be moved.
(defclass table-block (support-for) () basic-block)
; Specific classes for table brick wedge and ball
(defclass brick () () load-bearing-block)
(defclass wedge () () movable-block)
(defclass ball () () movable-block)
(defclass hand (name position grasping))
; define all the individual blocks
(setf *blocks*
(list
(send table-block :new :name 'table :width 20 :height 0 :position '(0 0))
(send brick :new :name 'b1 :width 2 :height 2 :position '(0 0))
(send brick :new :name 'b2 :width 2 :height 2 :position '(2 0))
(send brick :new :name 'b3 :width 4 :height 4 :position '(4 0))
(send brick :new :name 'b4 :width 2 :height 2 :position '(8 0))
(send wedge :new :name 'w5 :width 2 :height 4 :position '(10 0))
(send brick :new :name 'b6 :width 4 :height 2 :position '(12 0))
(send wedge :new :name 'w7 :width 2 :height 2 :position '(16 0))
(send ball :new :name 'l8 :width 2 :height 2 :position '(18 0))
))
(dolist (l *blocks*) (set (send l :name) l))
(dolist (l (cdr *blocks*)) ; all but table block
(setf (send table :support-for)
(cons l (send table :support-for))
(send l :supported-by)
table))
(definst hand *hand* :name '*hand* :position '(0 6))
(defmethod movable-block :put-on (support)
(if (send self :get-space support)
(and (send *hand* :grasp self)
(send *hand* :move self support)
(send *hand* :ungrasp self))
(format t
"Sorry, there is no room for ~a on ~a.~%"
name
(send support :name))))
(defmethod movable-block :get-space (support)
(or (send self :find-space support)
(send self :make-space support)))
(defmethod hand :grasp (obj)
(unless (eq grasping obj)
(when (send obj :support-for)
(send obj :clear-top))
(when grasping
(send grasping :rid-of))
(setf position (send obj :top-location))
(format t
"Move hand to pick up ~a at location ~a.~%"
(send obj :name)
position)
(format t
"Grasp ~a.~%"
(send obj :name))
(setf grasping obj))
t)
(defmethod hand :ungrasp (obj)
(when (send obj :supported-by)
(format t
"Ungrasp ~a~%"
(send obj :name))
(setf grasping nil)
t))
(defmethod movable-block :rid-of ()
(send self :put-on table))
(defmethod movable-block :make-space (support)
(dolist (obstruction (send support :support-for))
(send obstruction :rid-of)
(let ((space (send self :find-space support)))
(when space (return space)))))
(defmethod load-bearing-block :clear-top ()
(dolist (obstacle support-for) (send obstacle :rid-of))
t)
(defmethod hand :move (obj support)
(send obj :remove-support)
(let ((newplace (send obj :get-space support)))
(format t
"Move ~a to top of ~a at location ~a.~%"
(send obj :name)
(send support :name)
newplace)
(setf (send obj :position) newplace)
(setf position (send obj :top-location)))
(send support :add-support obj)
t)
; remove-support-for is defined twice, for each load bearing class
(defmethod load-bearing-block :remove-support-for (obj)
(setf support-for (remove obj support-for))
t)
(defmethod table-block :remove-support-for (obj)
(setf support-for (remove obj support-for))
t)
(defmethod movable-block :remove-support ()
(when supported-by
(format t
"Removing support relations between ~a and ~a.~%"
(send supported-by :name)
name)
(send supported-by :remove-support-for self)
(setf supported-by nil))
t)
(defmethod load-bearing-block :add-support (obj)
(format t
"Adding support relations between ~a and ~a.~%"
(send obj :name)
name)
(setf support-for
(cons obj support-for)
(send obj :supported-by)
self)
t)
(defmethod table-block :add-support (obj)
(format t
"Adding support relations between ~a and ~a.~%"
(send obj :name)
name)
(setf support-for
(cons obj support-for)
(send obj :supported-by)
self)
t)
(defmethod basic-block :add-support (obj)
t)
(defmethod movable-block :find-space (support)
(dotimes (offset (1+ (- (send support :width) width)))
(unless (intersections-p self offset
(first (send support :position))
(send support :support-for))
(return (list (+ offset (first (send support
:position)))
(+ (second (send support :position))
(send support :height)))))))
(defun intersections-p (obj offset base obstacles)
(dolist (obstacle obstacles)
(let* ((ls-proposed (+ offset base))
(rs-proposed (+ ls-proposed (send obj :width)))
(ls-obstacle (first (send obstacle :position)))
(rs-obstacle (+ ls-obstacle (send obstacle :width))))
(unless (or (>= ls-proposed rs-obstacle)
(<= rs-proposed ls-obstacle))
(return t)))))
syntax highlighted by Code2HTML, v. 0.9.1