1 ; Blocks World from Winston&Horn
2 ; modified for XLISP and graphics by Tom Almy
5 #-
:classes
(load "classes")
8 ; Functions for graphic assistance
10 (defvar *bx
* 0) ; text communication region
12 (defvar *gx
* 50) ; Graphic region origin
14 (defvar *ymax
* 349) ; height of display
15 (defvar *char-width
* 8) ; width of characters
16 (defvar *char-height
* 14) ; height of characters
17 (defvar *step-size
* 10) ; lcd of block widths
18 (defvar *delay-time
* 0.3) ; delay time in seconds
21 ; Move the cursor to nearest position to graphic coordiates
22 #+:math
(defun setgpos (x y
)
23 (goto-xy (round (+ x
*gx
*) *char-width
*)
24 (round (- *ymax
* y
*gy
*) *char-height
*)))
25 #-
:math
(defun setgpos (x y
)
26 (goto-xy (truncate (/ (+ x
*gx
*) *char-width
*))
27 (truncate (/ (+ (/ *char-height
* 2) (- *ymax
* y
*gy
*))
30 ; Move the cursor to the currently set bottom position and clear the line
33 (goto-xy *bx
* (+ *by
* 1))
37 (goto-xy *bx
* (- *by
* 1))
39 (color 15) ; Force color to white
42 ; Clear the screen and go to the bottom
52 (setq *ymax
* 349) ; reset defaults
53 (setq *char-height
* 14))
55 (defun gmode480 () ; this is for GENOA SuperEGA HiRes+
56 (mode 115 115 640 480)
59 (setq *char-height
* 8))
61 (defun gmode600 () ; this is for GENOA SuperEGA HiRes+
62 (mode 121 121 800 600)
65 (setq *char-height
* 8))
67 (defun gmodev () ; EVEREX 640x480 mode
71 (setq *char-height
* 14)
74 (defun gmodeVGA800 () ; this is for Video 7 FastWrite/VRAM VGA
75 (mode 28421 98 800 600)
78 (setq *char-height
* 8)
81 (defun gmodeVGA (&aux dims
) ; standard 640x480 VGA
82 ; Modified so it will work in Windows as well
84 (setq *ymax
* (1+ (fourth dims
)))
86 #+:math
(setq *char-height
* (truncate (1+ (fourth dims
)) (second dims
)))
87 #+:math
(setq *char-width
* (truncate (1+ (third dims
)) (first dims
)))
88 #-
:math
(setq *char-height
* (truncate (/ (1+ (fourth dims
)) (second dims
))))
89 #-
:math
(setq *char-width
* (truncate (/ (1+ (third dims
)) (first dims
))))
90 (setq *gy
* (truncate (* 2.5 *char-height
*)))
93 ; abstract classes for ball types
95 ; basic blocks support nothing
96 (defclass basic-block
(name color width height position supported-by
))
98 (defmethod basic-block :support-for
() nil
)
100 (defmethod basic-block :top-location
()
101 (list (+ (first position
) (/ width
2))
102 (+ (second position
) height
)))
104 (defmethod basic-block :drawname
()
105 (setgpos (+ (first position
)
106 (/ (- width
(* *char-width
* (flatc name
))) 2))
107 (+ (second position
) (/ height
2)))
108 (color color
) ; For Windows, which does color text
111 (defmethod basic-block :undrawname
()
112 (setgpos (+ (first position
)
113 (/ (- width
(* *char-width
* (flatc name
))) 2))
114 (+ (second position
) (/ height
2)))
115 (dotimes (i (flatc name
)) (princ " ")))
117 (defmethod basic-block :draw
()
118 (color (+ color
128))
119 (move (+ *gx
* (first position
)) (+ *gy
* (second position
)))
120 (drawrel (1- width
) 0
125 ; movable-blocks can be moved
126 (defclass movable-block
() () basic-block
)
128 (defmethod movable-block :new-position
(newpos)
130 (send self
:undrawname
)
131 (setf position newpos
)
132 (send self
:drawname
)
135 ; load-bearing blocks can support other blocks, and can be moved
136 (defclass load-bearing-block
(support-for) () movable-block
)
138 ; we can't have multiple inheritance, so we need a separate class for table
139 ; table blocks can support other blocks but cannot be moved.
141 (defclass table-block
(support-for) () basic-block
)
143 ; Specific classes for table brick wedge and ball
145 (defclass brick
() () load-bearing-block
)
147 (defclass wedge
() () movable-block
)
149 (defmethod wedge :draw
()
150 (color (+ color
128))
151 (move (+ *gx
* (first position
)) (+ *gy
* (second position
)))
152 (drawrel (1- width
) 0
153 (- 1 (/ width
2)) (1- height
)
154 (- (/ width
2) width
1) (- 1 height
)))
156 (defclass ball
() () movable-block
)
158 (defmethod ball :draw
()
159 (color (+ color
128))
160 (let ((cx (+ (first position
) (/ width
2) -
1 *gx
*))
161 (cy (+ (second position
) (/ height
2) -
1 *gy
*))
162 (fstep (/ 3.14159 18))
163 (radius (1- (/ (min width height
) 2))))
164 (move (+ cx radius
) cy
)
166 (draw (truncate (+ cx
(* radius
(cos (* (1+ i
) fstep
)))))
167 (truncate (+ cy
(* radius
(sin (* (1+ i
) fstep
)))))))))
169 (defclass hand
(name position grasping
))
171 (defmethod hand :top-location
() position
)
173 (defmethod hand :draw
()
174 (color (if grasping
143 136))
175 (move (+ *gx
* -
7 (first position
)) (+ *gy
* (second position
)))
176 (drawrel 5 0 0 10 5 0 0 -
10 5 0 0 20 -
15 0 0 -
20))
178 (defmethod hand :new-position
(newpos)
180 (setf position newpos
)
183 ; define all the individual blocks
187 (send table-block
:new
:name
'table
:width
430 :height
10
188 :position
'(0 0) :color
7)
189 (send brick
:new
:name
'b1
:width
40 :height
40
190 :position
'(0 10) :color
1)
191 (send brick
:new
:name
'b2
:width
40 :height
40
192 :position
'(40 10) :color
2)
193 (send brick
:new
:name
'b3
:width
80 :height
80
194 :position
'(80 10) :color
3)
195 (send brick
:new
:name
'b4
:width
40 :height
40
196 :position
'(160 10) :color
4)
197 (send wedge
:new
:name
'w5
:width
40 :height
80
198 :position
'(200 10) :color
5)
199 (send brick
:new
:name
'b6
:width
80 :height
40
200 :position
'(240 10) :color
6)
201 (send wedge
:new
:name
'w7
:width
40 :height
40
202 :position
'(320 10) :color
9)
203 (send ball
:new
:name
'l8
:width
40 :height
40
204 :position
'(360 10) :color
10)
205 (send brick
:new
:name
'b9
:width
30 :height
30
206 :position
'(400 10) :color
12)
209 (dolist (l *blocks
*) (set (send l
:name
) l
))
211 (dolist (l (rest *blocks
*)) ; all blocks but the table
212 (setf (send table
:support-for
)
213 (cons l
(send table
:support-for
))
214 (send l
:supported-by
)
217 (definst hand
*hand
* :name
'*hand
* :position
'(0 120))
219 (defun display-blocks ()
221 (dolist (l *blocks
*) (send l
:drawname
)(send l
:draw
))
226 (defmethod basic-block :put-on
(support) ; default case is bad
228 "Sorry, the ~a cannot be moved.~%"
231 (defmethod movable-block :put-on
(support)
232 (if (send self
:get-space support
)
233 (and (send *hand
* :grasp self
)
234 (send *hand
* :move self support
)
235 (send *hand
* :ungrasp self
))
237 "Sorry, there is no room for ~a on ~a.~%"
239 (send support
:name
))))
241 (defmethod movable-block :get-space
(support)
242 (or (send self
:find-space support
)
243 (send self
:make-space support
)))
245 (defmethod hand :grasp
(obj)
246 (unless (eq grasping obj
)
247 (when (send obj
:support-for
)
248 (send obj
:clear-top
))
250 (send grasping
:rid-of
))
251 (let ((lift (max-height self obj
)))
252 (send self
:new-position lift
)
254 (send self
:new-position
255 (list (first (send obj
:top-location
)) (second lift
)))
257 (send self
:new-position
(send obj
:top-location
))
258 (pause *delay-time
*))
264 (defmethod hand :ungrasp
(obj)
265 (when (send obj
:supported-by
)
272 (defmethod movable-block :rid-of
()
273 (send self
:put-on table
))
275 (defmethod movable-block :make-space
(support)
276 (dolist (obstruction (send support
:support-for
))
277 (send obstruction
:rid-of
)
278 (let ((space (send self
:find-space support
)))
279 (when space
(return space
)))))
281 (defmethod load-bearing-block :clear-top
()
282 (dolist (obstacle support-for
) (send obstacle
:rid-of
))
286 (defmethod hand :move
(obj support
)
287 (send obj
:remove-support
)
288 (let ((newplace (send obj
:get-space support
)))
289 (let ((lift (max-height obj support
)))
290 (send obj
:new-position lift
)
291 (send self
:new-position
(send obj
:top-location
))
293 (send obj
:new-position
(list (first newplace
) (second lift
)))
294 (send self
:new-position
(send obj
:top-location
))
296 (send obj
:new-position newplace
)
297 (send self
:new-position
(send obj
:top-location
))
298 (pause *delay-time
*)))
299 (send support
:add-support obj
)
303 ; helper function to find height necessary to move object
305 (defun max-height (obj1 obj2
)
306 (let ((source (first (send obj1
:top-location
)))
307 (dest (first (send obj2
:top-location
))))
308 (let ((roof 0) (min (min source dest
)) (max (max source dest
)) )
309 (dolist (obstacle *blocks
*)
310 (let ((x (send obstacle
:top-location
)))
311 (when (and (>= (first x
) min
)
314 (setf roof
(second x
)))))
315 (list (first (send obj1
:position
)) (+ 20 roof
)))))
317 #+:times
(defun pause (time)
318 (let ((fintime (+ (* time internal-time-units-per-second
)
319 (get-internal-run-time))))
320 (loop (when (> (get-internal-run-time) fintime
)
321 (return-from pause
)))))
322 #-
:times
(defun pause () (dotimes (x (* time
1000))))
325 ; remove-support-for is defined twice, for each load bearing class
327 (defmethod load-bearing-block :remove-support-for
(obj)
328 (setf support-for
(remove obj support-for
))
331 (defmethod table-block :remove-support-for
(obj)
332 (setf support-for
(remove obj support-for
))
335 (defmethod movable-block :remove-support
()
337 (send supported-by
:remove-support-for self
)
338 (setf supported-by nil
))
343 (defmethod load-bearing-block :add-support
(obj)
345 (cons obj support-for
)
346 (send obj
:supported-by
)
350 (defmethod table-block :add-support
(obj)
352 (cons obj support-for
)
353 (send obj
:supported-by
)
357 (defmethod basic-block :add-support
(obj)
360 (defmethod movable-block :find-space
(support)
361 (do ((offset (- (send support
:width
) width
)
362 (- offset
*step-size
*)))
364 (unless (intersections-p self offset
365 (first (send support
:position
))
366 (send support
:support-for
))
367 (return (list (+ offset
(first (send support
369 (+ (second (send support
:position
))
370 (send support
:height
)))))))
372 (defun intersections-p (obj offset base obstacles
)
373 (dolist (obstacle obstacles
)
374 (let* ((ls-proposed (+ offset base
))
375 (rs-proposed (+ ls-proposed
(send obj
:width
)))
376 (ls-obstacle (first (send obstacle
:position
)))
377 (rs-obstacle (+ ls-obstacle
(send obstacle
:width
))))
378 (unless (or (>= ls-proposed rs-obstacle
)
379 (<= rs-proposed ls-obstacle
))
383 (defun m (a b
) (send a
:put-on b
) (bottom))
384 (defun d () (display-blocks))