(defpackage "ANTS" (:use "COMMON-LISP" "CAPI"))

(in-package "ANTS")

 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;; Define the world objects

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(setq node-proto '(

(name . node)

(obj-shape . circle)

(size . 5)

(xpos . 0)

(ypos . 0)

(color . :red)

(lineage . nil)

))

(setq square-proto '(

(name . obstacle )

(obj-type . stationary)

(obj-shape . rectangle)

(xpos . 310)

(ypos . 350)

(x2pos . 410)

(y2pos . 410)

(length . 20 )

(width . 15)

(size . 20)

(color . :black)

))

 

 

(setq goal '(

(name . goal )

(obj-type . stationary)

(obj-shape . circle)

(xpos . 350)

(ypos . 350)

(length . 20 )

(width . 15)

(size . 10)

(color . :green)

))

(setq starting-location '(

(name . start )

(obj-type . stationary)

(obj-shape . circle)

(xpos . 10)

(ypos . 10)

(size . 10)

(lineage . nil)

(color . :blue)

))

 

 

(setq ping-proto '(

(name . ping-object)

(obj-shape . circle)

(speed . 1)

(xpos . 10)

(ypos . 10)

(orientation . 1.2 )

(size . 2)

))

 

(setq walls '(

(name . Walls )

(obj-type . stationary )

(obj-shape . wall )

(xsize . 500 )

(ysize . 500 )

(color . blue )))

 

 

(setq best-trip nil)

(setq shortest-distance 10000)

 

 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;; World definition and execution loops

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

 

 

(defun run ()

(progn

;Initialize the world to contain the walls and the start

(setq world-objects (list walls starting-location))

 

;Initialize the list of nodes to contain the start

(setq node-list (list starting-location))

;kick off the graphics portion of the program

(init-graphics-pane)

;;Wait right here until the user releases the pause button from the GUI

(loop while (simulation-stopped) do (+ 2 2))

;;Display all of the nodes and obstacles

(mapcar #'show-obj world-objects)

;;Expand the nodes using a breadth first search for the goal

;;(setf node-list (list starting-location))

;;(expand-node node-list)

 

))

 

(defun expand-node (nlist)

(if nlist

(let ((node (car nlist))

(children-node (get-visible-nodes (car nlist) nlist world-objects)))

(cond

((if (line-of-sight? node goal)

(found-goal

(add-node-lineage goal node))))

((if children-node

(expand-node (append children-node nlist))))))))

 

(defun get-trip-distance (list-of-nodes)

(if (and (car list-of-nodes) (cadr list-of-nodes))

(+ (distance-obj (car list-of-nodes) (cadr list-of-nodes))

(get-trip-distance (car list-of-nodes)))

0))

 

(defun get-visible-nodes (parent-node list-of-nodes list-of-objects)

;;node is the vertex that we want to expand

;;list-of-nodes is a list of already traversed nodes

;;list-of-objects is a list of world objects -- the recursion

;; will stop when there are no more objects in the list-of-objects

(if list-of-objects

(if (eq 'node (get-value 'name (car list-of-objects)))

(let ((child-node (car list-of-objects)))

(if (and (line-of-sight? child-node parent-node)

(not (duplicated? child-node list-of-nodes)))

(cons (add-node-lineage child-node parent-node)

(get-visible-nodes parent-node list-of-nodes

(cdr list-of-objects)))

(get-visible-nodes parent-node list-of-nodes

(cdr list-of-objects)))))))

(defun found-goal (node)

(let

((distance (get-trip-distance (get-value 'lineage node))))

(if (< distance shortest-distance)

(progn

(setq shortest-distance distance)

(describe distance)

(setq best-trip (get-value 'lineage node))))))

 

(defun duplicated? (node list-of-nodes)

(if list-of-nodes

(if (and

(= (get-value 'xpos node) (get-value 'xpos (car list-of-nodes)))

(= (get-value 'ypos node) (get-value 'ypos (car list-of-nodes))))

t (duplicated? node (car list-of-nodes)))

nil ))

 

 

(defun add-node-lineage (child-node parent-node)

(progn

(gp:draw-rectangle display-pane

(get-value 'xpos child-node)

(get-value 'ypos child-node)

(get-value 'xpos parent-node)

(get-value 'ypos parent-node))

(set-value

'lineage

child-node

(append parent-node (get-value 'lineage parent-node)))

))

 

(defun gxv (object)

(get-value 'xpos object))

(defun gyv (object)

(get-value 'ypos object))

(defun sxv (object value)

(set-value 'xpos object value))

(defun syv (object value)

(set-value 'xpos object value))

 

 

 

 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;; Collision Detection Utilities

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun detect-collision (object list_of_objects)

(cond

((eq list_of_objects NIL) NIL)

((eq (get-value 'obj-shape (car list_of_objects)) 'wall)

(if (collided-walls? object (car list_of_objects))

(cons (car list_of_objects) (detect-collision object (cdr list_of_objects))) ;;; collisiion

(detect-collision object (cdr list_of_objects)))) ;;; no collision this time

((and (= (get-value 'xpos object) (get-value 'xpos (car list_of_objects)))

(= (get-value 'ypos object) (get-value 'ypos (car list_of_objects))))

(detect-collision object (cdr list_of_objects))) ;;; don't detect yourself

((and (eq (get-value 'obj-shape (car list_of_objects)) 'circle)

(eq (get-value 'obj-shape object) 'circle))

(if (collided-circles? object (car list_of_objects))

(cons (car list_of_objects) (detect-collision object (cdr list_of_objects))) ;;; collisiion

(detect-collision object (cdr list_of_objects)))) ;;; no collision this time

((and (eq (get-value 'obj-shape (car list_of_objects)) 'rectangle)

(eq (get-value 'obj-shape object) 'circle) )

(if (collided-rectangle? object (car list_of_objects))

(cons (car list_of_objects) (detect-collision object (cdr list_of_objects))) ;;; collisiion

(detect-collision object (cdr list_of_objects)))) ;;; no collision this time

(t (detect-collision object (cdr list_of_objects)))))

(defun collided-circles? (obj1 obj2)

(< (distance-obj obj1 obj2) (+ (get-value 'size obj1) (get-value 'size obj2))))

(defun collided-walls? (object walls)

(or

(< (get-value 'xpos object) 0)

(< (get-value 'ypos object) 0)

(> (get-value 'xpos object) (get-value 'xsize walls))

(> (get-value 'ypos object) (get-value 'ysize walls))))

(defun collided-rectangle? (object rect)

(and

(> (+ (get-value 'xpos object) 0) (get-value 'xpos rect))

(> (+ (get-value 'ypos object) 0) (get-value 'ypos rect))

(< (- (get-value 'xpos object) 0) (get-value 'x2pos rect))

(< (- (get-value 'ypos object) 0) (get-value 'y2pos rect))))

;;; square root of the squares

(defun distance-obj (obj1 obj2)

(sqrt (+

(* (- (cdr (assoc 'xpos obj1)) (cdr (assoc 'xpos obj2)))

(- (cdr (assoc 'xpos obj1)) (cdr (assoc 'xpos obj2))))

(* (- (cdr (assoc 'ypos obj1)) (cdr (assoc 'ypos obj2)))

(- (cdr (assoc 'ypos obj1)) (cdr (assoc 'ypos obj2)))))))

 

 

 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;; Sensor utilities

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

 

(defun line-of-sight? (objectA objectZ)

;;Determine if the two objects can see each other

;;if a ping-object moves from objectA to objectZ without

;;hitting anything else then the two objects can see each other

(progn

(setq ping-object (copy-alist ping-proto))

(set-value 'xpos ping-object (get-value 'xpos objectA))

(set-value 'ypos ping-object (get-value 'ypos objectA))

(set-value 'orientation ping-object

(get-orientation-towards-object objectA objectZ))

;;This "if" statement is a very big kludge. The get-first-object-in-direction

;;function will not detect objects which are on the same x or y

;;values. There is a hard check placed here to capture these

(if

(or (= (get-value 'xpos objectZ) (get-value 'xpos objectA))

(= (get-value 'ypos objectZ) (get-value 'ypos objectA)))

(if t t)

(let ((collided-object (get-first-object-in-direction ping-object)))

(progn

(describe collided-object)

(if (and

(= (get-value 'xpos collided-object)

(get-value 'xpos objectZ))

(= (get-value 'ypos collided-object)

(get-value 'ypos objectZ))) t Nil))))))

(defun get-first-object-in-direction (ping-object)

(if (detect-collision (next-move ping-object) world-objects)

(car (detect-collision (next-move ping-object) world-objects))

(progn

(show-obj ping-object)

(get-first-object-in-direction (next-move ping-object)))))

(defun get-orientation-towards-object (objectA objectZ)

(atan (- (get-value 'ypos objectZ) (get-value 'ypos objectA))

(- (get-value 'xpos objectZ) (get-value 'xpos objectA) )))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Movement utilities

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun next-move (object)

(set-value 'xpos object (+ (get-value 'xpos object) (* (cos (get-value 'orientation object)) (get-value 'speed object))))

(set-value 'ypos object (+ (get-value 'ypos object) (* (sin (get-value 'orientation object)) (get-value 'speed object))))

(if t object object))

 

 

 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;; Object Manipulations Utility Functions

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun get-value (key object)

(cdr (assoc key object)))

(defun set-value (key object value)

(progn

(setf (cdr (assoc key object)) value)

(if t object)))

(defun add-object-to-world (name x y x2 y2)

(cond ((eq name 'obstacle)

(progn

(setq temp-square (copy-alist square-proto))

(set-value 'xpos temp-square (min x x2))

(set-value 'ypos temp-square (min y y2))

(set-value 'x2pos temp-square (max x x2))

(set-value 'y2pos temp-square (max y y2))

(set-value 'name temp-square name)

(setq world-objects (append world-objects (list temp-square)))

;Add the nodes

(setq temp-node (copy-alist node-proto))

(set-value 'xpos temp-node x)

(set-value 'ypos temp-node y)

(set-value 'name temp-square 'test-node)

(setq world-objects (append world-objects (list temp-node)))

(setq temp-node (copy-alist node-proto))

(set-value 'xpos temp-node x2)

(set-value 'ypos temp-node y)

(set-value 'name temp-square 'test-node)

(setq world-objects (append world-objects (list temp-node)))

(setq temp-node (copy-alist node-proto))

(set-value 'xpos temp-node x)

(set-value 'ypos temp-node y2)

(set-value 'name temp-square 'test-node)

(setq world-objects (append world-objects (list temp-node)))

(setq temp-node (copy-alist node-proto))

(set-value 'xpos temp-node x2)

(set-value 'ypos temp-node y2)

(set-value 'name temp-square 'test-node)

(setq world-objects (append world-objects (list temp-node)))))

((eq name 'goal)

(set-value 'xpos goal (/ (+ x x2) 2))

(set-value 'ypos goal (/ (+ y y2) 2))

(set-value 'name goal name)

(setq world-objects (append world-objects (list goal))))

((eq name 'start)

(set-value 'xpos starting-location (/ (+ x x2) 2))

(set-value 'ypos starting-location (/ (+ y y2) 2))

(set-value 'name starting-location name)

(setq world-objects (append world-objects (list starting-location))))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Graphic Utilities

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

 

(defun show-obj (object)

(cond

((eq (get-value 'obj-shape object) 'rectangle)

(progn

(gp:draw-rectangle display-pane

(get-value 'xpos object)

(get-value 'ypos object)

(- (get-value 'x2pos object) (get-value 'xpos object))

(- (get-value 'y2pos object) (get-value 'ypos object))

:filled t

:foreground (get-value 'color object))))

((eq (get-value 'obj-shape object) 'circle)

(progn

(gp:draw-circle display-pane

(get-value 'xpos object)

(get-value 'ypos object)

(get-value 'size object)

:filled t

:foreground (get-value 'color object))))))

 

 

 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;

;;; UI Functions

;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun simulation-not-stopped ()

(or

(eq 'go (pinboard-test-mode global-pinboard-test))

(eq 'pause (pinboard-test-mode global-pinboard-test))))

(defun simulation-stopped ()

(eq 'stop (pinboard-test-mode global-pinboard-test)))

;;----------------------------------------------------------------------------

;;

;; examples/capi/graphics/pinboard-test.lisp

;;

;; This example demonstrates the uses of pinboard-objects and

;; pinboard-layouts in the CAPI.

;;

;; To try it, compile and load this file and then execute:

;;

;; (CL-USER::TEST-PINBOARD)

;;

;;----------------------------------------------------------------------------

;; Copyright (c) 1987--98 Harlequin Group plc. All rights reserved.

;;----------------------------------------------------------------------------

;;----------------------------------------------------------------------------

;; Define an interface

;;----------------------------------------------------------------------------

(capi:define-interface pinboard-test ()

((new-class :accessor new-class :initform nil)

(start-x :accessor start-x)

(start-y :accessor start-y)

(last-x :accessor last-x)

(last-y :accessor last-y))

(:panes

(mode-buttons

capi:radio-button-panel

:accessor mode-buttons

:title "Action:"

:title-position :top

:layout-class 'capi:column-layout

:items '(Stop Go)

:print-function 'string-capitalize)

(object-buttons

capi:radio-button-panel

:accessor object-buttons

:title "Object:"

:title-position :top

:layout-class 'capi:column-layout

:items '(goal obstacle start)

:print-function 'string-capitalize)

(style-buttons

capi:radio-button-panel

:accessor style-buttons

:title "Style:"

:title-position :top

:layout-class 'capi:column-layout

:items '(:solid :outline)

:print-function 'string-capitalize))

(:layouts

(pinboard

capi:pinboard-layout

'()

:background :white

:input-model '(((:button-1 :press) press-button-1)

((:motion :button-1) drag-button-1)

((:button-1 :release) release-button-1)

((:button-2 :press) press-button-2))

:drawing-style (:initarg :display-type)

:vertical-scroll t

:horizontal-scroll t

:min-width 500

:min-height 500)

(button-layout

capi:column-layout

'(mode-buttons object-buttons style-buttons)

:y-gap 10)

(sub-layout

capi:column-layout

'(pinboard)

:title "Drag button 1 to add an object and button 2 to delete one")

(main-layout

capi:row-layout

'(button-layout sub-layout)

))

(:default-initargs

:layout 'main-layout

:title "Pinboard Test"

:best-height 500

:best-width 500))

(defun pinboard-test-object (pinboard-test)

(capi:choice-selected-item (object-buttons pinboard-test)))

(defun pinboard-test-filled (pinboard-test)

(eq (capi:choice-selected-item (style-buttons pinboard-test)) :solid))

(defun pinboard-test-mode (pinboard-test)

(capi:choice-selected-item (mode-buttons pinboard-test)))

 

;;----------------------------------------------------------------------------

;; A few useful utilities

;;----------------------------------------------------------------------------

;; x-y-width-and-height is a simple function which given two coordinates

;; returns the top-left x and y, and the width and height

(defun x-y-width-and-height (x1 y1 x2 y2)

(values (min x1 x2)

(min y1 y2)

(abs (- x1 x2))

(abs (- y1 y2))))

;; WITH-XOR makes all graphics-port operations done within its body be drawn

;; using exclusive-or.

(defmacro with-xor ((port) &body body)

`(gp:with-graphics-state (,port

:foreground (gp:compute-xor-pixel ,port)

:operation boole-xor)

,@body))

 

;;----------------------------------------------------------------------------

;; Define a square pinboard-object

;;----------------------------------------------------------------------------

(defclass square (capi:pinboard-object)

((foreground :accessor foreground :initform nil :initarg :foreground)

(filled :accessor filled :initform nil :initarg :filled))

(:default-initargs

:min-width 30

:min-height 30))

(defmethod capi:draw-pinboard-object (pinboard (square square) &key)

(capi:with-geometry square

(let ((filled? (filled square)))

(gp:draw-rectangle pinboard

capi:%x% capi:%y%

(if filled? capi:%width% (1- capi:%width%))

(if filled? capi:%height% (1- capi:%height%))

:foreground (or (foreground square)

(capi:simple-pane-foreground pinboard))

:filled filled?))))

(defmethod draw-object-outline (pinboard (square square) x1 y1 x2 y2)

(multiple-value-bind

(x y width height)

(x-y-width-and-height x1 y1 x2 y2)

(with-xor (pinboard)

(gp:draw-rectangle pinboard x y width height))))

 

;;----------------------------------------------------------------------------

;; Define an ellipse pinboard object

;;----------------------------------------------------------------------------

(defclass ellipse (capi:pinboard-object)

((foreground :accessor foreground :initform nil :initarg :foreground)

(filled :accessor filled :initform nil :initarg :filled))

(:default-initargs

:min-width 30

:min-height 30))

(defmethod capi:draw-pinboard-object (pinboard (ellipse ellipse) &key)

(capi:with-geometry ellipse

(let ((x-radius (floor (1- capi:%width%) 2))

(y-radius (floor (1- capi:%height%) 2)))

(gp:draw-ellipse pinboard

(+ capi:%x% x-radius)

(+ capi:%y% y-radius)

x-radius

y-radius

:foreground (or (foreground ellipse)

(capi:simple-pane-foreground pinboard))

:filled (filled ellipse)))))

(defmethod draw-object-outline (pinboard (ellipse ellipse) x1 y1 x2 y2)

(multiple-value-bind

(x y width height)

(x-y-width-and-height x1 y1 x2 y2)

(let ((x-radius (floor width 2))

(y-radius (floor height 2)))

(with-xor (pinboard)

(gp:draw-ellipse pinboard

(+ x x-radius)

(+ y y-radius)

x-radius

y-radius)))))

 

;;----------------------------------------------------------------------------

;; Define a text pinboard object

;;----------------------------------------------------------------------------

(defclass text (capi:pinboard-object)

((foreground :accessor foreground :initform nil :initarg :foreground)

(filled :accessor filled :initform nil :initarg :filled))

(:default-initargs

:min-width 30

:min-height 30))

(defmethod capi:draw-pinboard-object (pinboard (text text) &key)

(capi:with-geometry text

(let ((foreground (or (foreground text) (capi:simple-pane-foreground pinboard)))

(background (capi:simple-pane-background pinboard))

(filled (filled text)))

(gp:draw-x-y-adjusted-string pinboard

"This is a test."

capi:%x%

capi:%y%

:y-adjust :top

:foreground (if filled background foreground)

:background (if filled foreground background)

:block (filled text)))))

(defmethod draw-object-outline (pinboard (text text) x1 y1 x2 y2)

(multiple-value-bind

(x y width height)

(x-y-width-and-height x1 y1 x2 y2)

(with-xor (pinboard)

(gp:draw-rectangle pinboard x y width height))))

 

;;----------------------------------------------------------------------------

;; The callbacks

;;----------------------------------------------------------------------------

(defun press-button-1 (pinboard x y)

(let* ((interface (capi:element-interface pinboard))

(shape 'square))

(setf (new-class interface) (clos:class-prototype (find-class shape)))

(setf (start-x interface) x)

(setf (start-y interface) y)

(setf (last-x interface) nil)))

(defun drag-button-1 (pinboard x y)

(let* ((interface (capi:element-interface pinboard))

(object (new-class interface)))

(when (last-x interface)

(draw-object-outline pinboard object

(start-x interface) (start-y interface)

(last-x interface) (last-y interface)))

(setf (last-x interface) x

(last-y interface) y)

(draw-object-outline pinboard object

(start-x interface) (start-y interface)

(last-x interface) (last-y interface))))

(defun release-button-1 (pinboard x y)

(let* ((interface (capi:element-interface pinboard))

(object (new-class interface))

(old-x (start-x interface))

(old-y (start-y interface))

(color (if (eq (pinboard-test-object interface) 'obstacle) :black :green))

(filled (pinboard-test-filled interface))

(width (abs (- old-x x)))

(height (abs (- old-y y))))

;; log the position of the object to the bug routine

(add-object-to-world (pinboard-test-object interface) old-x old-y x y )

(setf display-pane pinboard)

 

 

;; Remove the outline

(when (last-x interface)

(draw-object-outline pinboard object

(start-x interface) (start-y interface)

(last-x interface) (last-y interface)))

;; Create the appropriate pinboard-object and place it into

;; the pinboard-layout. We append it to the end of the list so

;; that it appears on top.

(when (and (> width 1)

(> height 1))

(setf (capi:layout-description pinboard)

(append (capi:layout-description pinboard)

(list

(make-instance (class-of object)

:foreground color

:filled filled

:x (min old-x x)

:y (min old-y y)

:min-width width

:min-height height)))))))

(defun press-button-2 (pinboard x y)

(let ((object (capi:pinboard-object-at-position pinboard x y)))

(when object

(setf (capi:layout-description pinboard)

(remove object (capi:layout-description pinboard))))))

 

;;----------------------------------------------------------------------------

;; The test function

;;----------------------------------------------------------------------------

(defun init-graphics-pane ()

(progn

(setq global-pinboard-test (contain (make-instance 'pinboard-test :display-type :local-pixmap)))

(capi:display global-pinboard-test)))

Hosted by www.Geocities.ws

1