[comp.sources.misc] v08i057: Elk

allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (09/24/89)

Posting-number: Volume 8, Issue 57
Submitted-by: net@tub.UUCP (Oliver Laumann)
Archive-name: elk/part09

[Let this be a lesson to submitters:  this was submitted as uuencoded,
compressed files.  I lost the source information while unpacking it; this
is the best approximation I could come up with.  ++bsa]

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 9 (of 14)."
# Contents:  tst/billiard lib/xlib/examples/properties
#   lib/xlib/examples/track lib/xlib/examples/picture
#   lib/xlib/examples/useful lib/xlib/pixel.c
# Wrapped by net@tub on Sun Sep 17 17:32:32 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f tst/billiard -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"tst/billiard\"
else
echo shar: Extracting \"tst/billiard\" \(46118 characters\)
sed "s/^X//" >tst/billiard <<'END_OF_tst/billiard'
X;;;
X;;; BILLIARD.SCM: This file contains code for a very simple billiard ball
X;;;               simulator.  The simulation takes place in two dimensions.
X;;;               The balls are really disks in that their height is not taken
X;;;               into account.  All interactions are assumed to be
X;;;               frictionless so spin in irrelevant and not accounted for.
X;;;               (See section on limitations.)
X;;;
X;;; NOTES: A simulation is initiated by creating a number of balls and bumpers
X;;;        and and specifying a duration for the simulation.  For each ball,
X;;;        its mass, radius, initial position, and initial velocity must be
X;;;        specified.  For each bumper, the location of its two ends must be
X;;;        specified.  (Bumpers are assumed to have zero width.)
X;;;
X;;;        A sample run might be started as follows:
X;;;        (simulate
X;;;         (list (make-ball 2 1 9 5 -1 -1)
X;;;               (make-ball 4 2 2 5 1 -1))
X;;;         (list (make-bumper 0 0 0 10)
X;;;               (make-bumper 0 0 10 0)
X;;;               (make-bumper 0 10 10 10)
X;;;               (make-bumper 10 0 10 10))
X;;;         30)
X;;;
X;;;        It would create one billiard ball of mass 2 and radius 1 at position
X;;;        (9, 5) with initial velocity (-1, -1) and a second ball of mass 4
X;;;        and radius 2 at position (2, 5) with initial velocity (1, -1).  The
X;;;        table would be a 10X10 square.  (See diagram below)
X;;;
X;;;        +---------------------------+
X;;;        |                           |
X;;;        |                           |
X;;;        |    XXXX                   |
X;;;        |  XXXXXXXX             XX  |
X;;;        |XXXXXX4XXXXX         XXX2XX|
X;;;        |  XXXXXXXX            /XX  |
X;;;        |    XXXX \                 |
X;;;        |                           |
X;;;        |                           |
X;;;        +---------------------------+
X;;;
X;;; LIMITATIONS:  This simulator does not handle 3 body problems correctly.  If
X;;;               3 objects interact at one time, only the interactions of 2 of
X;;;               the bodies will be accounted for.  This can lead to strange
X;;;               effects like balls tunneling through walls and other balls.
X;;;               It is also possible to get balls bouncing inside of each
X;;;               other in this way. 
X;;;           
X
X
X;;MAKE-QUEUE-RECORD returns a queue record with the given next, previous, and
X;;value values
X;;NEXT = The next record pointer
X;;PREV = The previous record pointer
X;;REST = A list of values for any optional fields (this can be used for
X;;       creating structure inheritance)
X(define-macro (make-queue-record next prev . rest)
X  `(vector ,next ,prev ,@rest))
X	  
X;;QUEUE-RECORD-NEXT returns the next field of the given queue record
X;;QUEUE-RECORD = The queue record whose next field is to be returned
X(define-macro (queue-record-next queue-record)
X  `(vector-ref ,queue-record 0))
X
X;;SET-QUEUE-RECORD-NEXT! sets the next field of the given queue record
X;;QUEUE-RECORD = The queue record whose next field is to be set
X;;VALUE = The value to which the next field is to be set
X(define-macro (set-queue-record-next! queue-record value)
X  `(vector-set! ,queue-record 0 ,value))
X
X;;QUEUE-RECORD-PREV returns the prev field of the given queue record
X;;QUEUE-RECORD = The queue record whose prev field is to be returned
X(define-macro (queue-record-prev queue-record)
X  `(vector-ref ,queue-record 1))
X
X;;SET-QUEUE-RECORD-PREV! sets the prev field of the given queue record
X;;QUEUE-RECORD = The queue record whose prev field is to be set
X;;VALUE = The value to which the prev field is to be set
X(define-macro (set-queue-record-prev! queue-record value)
X  `(vector-set! ,queue-record 1 ,value))
X
X;;QUEUE-RECORD-LEN returns the length of a queue record which has no optional
X;;fields 
X(define-macro (queue-record-len) 2)
X
X;;QUEUE-HEAD returns a dummy record at the end of the queue with the record
X;;with the smallest key.
X;;QUEUE = the queue whose head record is to be returned
X(define-macro (queue-head queue)
X  `(vector-ref ,queue 0))
X
X;;QUEUE-TAIL returns a dummy record at the end of the queue with the record
X;;with the largest key.
X;;QUEUE = the queue whose tail record is to be returned
X(define-macro (queue-tail queue)
X  `(vector-ref ,queue 1))
X
X;;QUEUE-<? returns the less-than comparitor to be used in sorting
X;;records into the queue
X;;QUEUE = The queue whose comparitor is to be returned
X(define-macro (queue-<? queue)
X  `(vector-ref ,queue 2))
X
X
X;;MAKE-SORTED-QUEUE returns a queue object.  A queue header is a vector which
X;;contains a head pointer, a tail pointer, and a less-than comparitor. 
X;;QUEUE-<? = A predicate for sorting queue items
X(define (make-sorted-queue queue-<?)
X  (let ((queue
X	 (vector
X	  (make-queue-record		;The queue head record has no initial
X	   '()				;next, previous, or value values
X	   '())
X	  (make-queue-record		;The queue tail record has no intial
X	   '()				;next, previous, or value values
X	   '())
X	  queue-<?)))
X    (set-queue-record-next!
X     (queue-head queue)
X     (queue-tail queue))
X    (set-queue-record-prev!
X     (queue-tail queue)
X     (queue-head queue))
X    queue))
X
X;;MAKE-EVENT-QUEUE-RECORD returns an event queue record with the given next,
X;;previous, object, and collision-time values
X;;NEXT = The next record pointer
X;;PREV = The previous record pointer
X;;OBJECT = The simulation object associated with this record
X;;COLLISION-TIME = The collision time for this object
X(define-macro (make-event-queue-record next prev object collision-time)
X  `(make-queue-record ,next ,prev ,object ,collision-time))
X
X;;EVENT-QUEUE-RECORD-OBJECT returns the object associated with the given record
X;;QUEUE-RECORD = The queue record whose object field is to be returned
X(define-macro (event-queue-record-object queue-record)
X  `(vector-ref ,queue-record ,(queue-record-len)))
X
X;;EVENT-QUEUE-COLLISION-TIME returns the collision time associated with the
X;;given queue record
X;;QUEUE-RECORD = The queue record whose collision time field is to be returned
X(define-macro (event-queue-record-collision-time queue-record)
X  `(vector-ref ,queue-record ,(1+ (queue-record-len))))
X
X;;SET-EVENT-QUEUE-COLLISION-TIME! sets the collision time associated with the
X;;given queue record
X;;QUEUE-RECORD = The queue record whose collision time field is to be returned
X;;VALUE = The value to which it is to be set
X(define-macro (set-event-queue-record-collision-time! queue-record value)
X  `(vector-set! ,queue-record ,(1+ (queue-record-len)) ,value))
X
X
X;;QUEUE-INSERT inserts the given record in the given queue based on its value
X;;QUEUE = The queue into which the record is to be inserted
X;;QUEUE-RECORD = The record to be inserted in the queue
X(define (queue-insert queue queue-record)
X  (define (actual-insert insert-record next-record)
X    (if (or				;If the insert position has been found
X	 (eq? next-record		;or the end on the queue has been 
X	      (queue-tail queue))	;reached
X	 ((queue-<? queue)		
X	  insert-record
X	  next-record))
X	(sequence			;Link the insert record into the queue
X	  (set-queue-record-next!	;just prior to next-record
X	   (queue-record-prev
X	    next-record)
X	   insert-record)
X	  (set-queue-record-prev!
X	   insert-record
X	   (queue-record-prev
X	    next-record))
X	  (set-queue-record-next!
X	   insert-record
X	   next-record)
X	  (set-queue-record-prev!
X	   next-record
X	   insert-record))
X	(actual-insert			;Else, continue searching for the 
X	 insert-record			;insert position
X	 (queue-record-next
X	  next-record))))
X  (actual-insert			;Search for the correct position to 
X   queue-record				;perform the insert starting at the
X   (queue-record-next			;queue head and perform the insert 
X    (queue-head queue))))		;once this position has been found
X     
X;;QUEUE-REMOVE removes the given queue record from its queue
X;;QUEUE-RECORD = The record to be removed from the queue
X(define (queue-remove queue-record)
X  (set-queue-record-next!
X   (queue-record-prev
X    queue-record)
X   (queue-record-next
X    queue-record))
X  (set-queue-record-prev!
X   (queue-record-next
X    queue-record)
X   (queue-record-prev
X    queue-record)))
X
X;;QUEUE-SMALLEST returns the queue record with the smallest key on the given
X;;queue 
X;;QUEUE = The queue from which the smallest record is to be extracted
X(define (queue-smallest queue)
X  (queue-record-next
X   (queue-head queue)))
X
X
X;;CLEAR-QUEUE! clears the given queue by destructively removing all the records
X;;QUEUE = The queue to be cleared
X(define (clear-queue queue)
X  (set-queue-record-next!
X   (queue-head queue)
X   (queue-tail queue))
X  (set-queue-record-prev!
X   (queue-tail queue)
X   (queue-head queue)))
X
X;;EMPTY-QUEUE? returns true if the given queue is empty
X;;QUEUE = The queue to be tested for emptiness
X(define (empty-queue? queue)
X  (eq? (queue-record-next
X	(queue-head queue))
X       (queue-tail queue)))
X
X
X;;MAKE-SIMULATION-OBJECT returns a simulation object containing the given
X;;fields 
X;;COLLISION-PROCEDURE = A function for processing information about a potential
X;;                      collision between this object and some ball
X;;REST = A list of values for any optional fields (this can be used for
X;;       creating structure inheritance)
X(define-macro (make-simulation-object collision-procedure . rest)
X  `(vector ,collision-procedure ,@rest))
X
X;;SIMULATION-OBJECT-COLLLISION-PROCEDURE returns the collision procedure for
X;;the given simulation object
X;;OBJECT = The object whose collision procedure is to be returned
X(define-macro (simulation-object-collision-procedure object)
X  `(vector-ref ,object 0))
X
X;;SIMULATION-OBJECT-LEN returns the length of a simulation object which has no
X;;optional fields
X(define-macro (simulation-object-len) 1)
X
X
X;;ACTUAL-MAKE-BALL returns a ball object
X;;BALL-NUMBER = An index into the ball vector for this ball
X;;MASS = The ball's mass
X;;RADIUS = The ball's radius
X;;PX = The x-coordinate of the ball's initial position
X;;PY = The y-coordinate of the ball's initial position
X;;VX = The x-coordinate of the ball's initial velocity
X;;VY = The y-coordinate of the ball's initial velocity
X(define-macro (actual-make-ball ball-number mass radius px py vx vy)
X  `(make-simulation-object
X    ball-collision-procedure		;The collision procedure for a ball
X    ,ball-number
X    ,mass
X    ,radius
X    (make-sorted-queue			;The event queue
X     collision-time-<?)
X    0					;Time of last collision
X    ,px					;Position of last collision
X    ,py					; "
X    ,vx					;Velocity following last colliosion
X    ,vy					; "
X    '()					;No vector of queue records for ball's
X					;with smaller numbers  
X    '()					;No vector of queue records for bumpers
X    '()					;No list of balls with larger numbers
X    '()))				;No global event queue record, yet
X  
X(define (make-ball mass radius px py vx vy)
X  (actual-make-ball '() mass radius px py vx vy))
X
X;;BALL-NUMBER returns the index of the given ball
X;;BALL = The ball whose index is to be returned
X(define-macro (ball-number ball)
X  `(vector-ref ,ball ,(simulation-object-len)))
X
X;;SET-BALL-NUMBER! set the index of the given ball to the given value
X;;BALL = The ball whose index is to be set
X;;VALUE = The value to which it is to be set
X(define-macro (set-ball-number! ball value)
X  `(vector-set! ,ball ,(simulation-object-len) ,value))
X
X;;BALL-MASS returns the mass of the given ball
X;;BALL = The ball whose mass is to be returned
X(define-macro (ball-mass ball)
X  `(vector-ref ,ball ,(+ (simulation-object-len) 1)))
X
X;;BALL-RADIUS returns the radius of the given ball
X;;BALL = The ball whose radius is to be returned
X(define-macro (ball-radius ball)
X  `(vector-ref ,ball ,(+ (simulation-object-len) 2)))
X
X;;BALL-EVENT-QUEUE returns the sort queue of collision events for the given
X;;ball
X;;BALL = The ball whose event is to be returned
X(define-macro (ball-event-queue ball)
X  `(vector-ref ,ball ,(+ (simulation-object-len) 3)))
X
X;;BALL-COLLISION-TIME returns the time of the last collision for the given ball
X;;BALL = The ball whose collision time is to be returned
X(define-macro (ball-collision-time ball)
X  `(vector-ref ,ball ,(+ (simulation-object-len) 4)))
X
X
X;;SET-BALL-COLLISION-TIME! sets the time of the last collision for the given
X;;ball 
X;;BALL = The ball whose collision time is to be set
X;;VALUE = The value to which the ball's collision time is to be set
X(define-macro (set-ball-collision-time! ball value)
X  `(vector-set! ,ball ,(+ (simulation-object-len) 4) ,value))
X
X;;BALL-COLLISION-X-POSITION returns the x-coordinate of the position  of the
X;;last collision for the given ball 
X;;BALL = The ball whose collision position is to be returned
X(define-macro (ball-collision-x-position ball)
X  `(vector-ref ,ball ,(+ (simulation-object-len) 5)))
X
X;;SET-BALL-COLLISION-X-POSITION! sets the x-coordinate of the position of the
X;;last collision for the given ball 
X;;BALL = The ball whose collision position is to be set
X;;VALUE = The value to which the ball's collision position is to be set
X(define-macro (set-ball-collision-x-position! ball value)
X  `(vector-set! ,ball ,(+ (simulation-object-len) 5) ,value))
X
X;;BALL-COLLISION-Y-POSITION returns the y-coordinate of the position  of the
X;;last collision for the given ball 
X;;BALL = The ball whose collision position is to be returned
X(define-macro (ball-collision-y-position ball)
X  `(vector-ref ,ball ,(+ (simulation-object-len) 6)))
X
X;;SET-BALL-COLLISION-Y-POSITION! sets the y-coordinate of the position of the
X;;last collision for the given ball 
X;;BALL = The ball whose collision position is to be set
X;;VALUE = The value to which the ball's collision position is to be set
X(define-macro (set-ball-collision-y-position! ball value)
X  `(vector-set! ,ball ,(+ (simulation-object-len) 6) ,value))
X
X;;BALL-X-VELOCITY returns the x-coordinate of the velocity of the given ball
X;;following its last collision
X;;BALL = The ball whose velocity is to be returned
X(define-macro (ball-x-velocity ball)
X  `(vector-ref ,ball ,(+ (simulation-object-len) 7)))
X
X;;SET-BALL-X-VELOCITY! sets the x-coordinate of the velocity of the given ball
X;;BALL = The ball whose velocity is to be set
X;;VALUE = The value to which the ball's velocity is to be set
X(define-macro (set-ball-x-velocity! ball value)
X  `(vector-set! ,ball ,(+ (simulation-object-len) 7) ,value))
X
X;;BALL-Y-VELOCITY returns the y-coordinate of the velocity  of the given ball
X;;following its last collision
X;;BALL = The ball whose velocity is to be returned
X(define-macro (ball-y-velocity ball)
X  `(vector-ref ,ball ,(+ (simulation-object-len) 8)))
X
X;;SET-BALL-Y-VELOCITY! sets the y-coordinate of the velocity of the given ball
X;;BALL = The ball whose velocity is to be set
X;;VALUE = The value to which the ball's velocity is to be set
X(define-macro (set-ball-y-velocity! ball value)
X  `(vector-set! ,ball ,(+ (simulation-object-len) 8) ,value))
X
X
X;;BALL-BALL-VECTOR returns the vector of queue records for balls with smaller
X;;ball numbers
X;;BALL = The ball whose ball vector is to be returned
X(define-macro (ball-ball-vector ball)
X  `(vector-ref ,ball ,(+ (simulation-object-len) 9)))
X
X;;SET-BALL-BALL-VECTOR! sets the vector of queue records for balls with smaller
X;;ball numbers
X;;BALL = The ball whose ball vector is to be set
X;;VALUE = The vector to which the field is to be set
X(define-macro (set-ball-ball-vector! ball value)
X  `(vector-set! ,ball ,(+ (simulation-object-len) 9) ,value))
X
X;;BALL-BUMPER-VECTOR returns the vector of queue records for bumpers
X;;BALL = The ball whose bumper vector is to be returned
X(define-macro (ball-bumper-vector ball)
X  `(vector-ref ,ball ,(+ (simulation-object-len) 10)))
X
X;;SET-BALL-BUMPER-VECTOR! sets the vector of queue records for bumpers
X;;BALL = The ball whose bumper vector is to be set
X;;VALUE = The vector to which the field is to be set
X(define-macro (set-ball-bumper-vector! ball value)
X  `(vector-set! ,ball ,(+ (simulation-object-len) 10) ,value))
X
X;;BALL-BALL-LIST returns a list of balls with larger ball numbers than the
X;;given ball
X;;BALL = The ball whose ball list is to be returned
X(define-macro (ball-ball-list ball)
X  `(vector-ref ,ball ,(+ (simulation-object-len) 11)))
X
X;;SET-BALL-BALL-LIST! sets the list of balls with larger ball numbers than the
X;;given ball
X;;BALL = The ball whose ball list is to be set
X;;VALUE = The value to which the ball list is to be set
X(define-macro (set-ball-ball-list! ball value)
X  `(vector-set! ,ball ,(+ (simulation-object-len) 11) ,value))
X
X;;BALL-GLOBAL-EVENT-QUEUE-RECORD returns the global event queue record for the
X;;given ball
X;;BALL = The ball whose global event queue record is to be returned
X(define-macro (ball-global-event-queue-record ball)
X  `(vector-ref ,ball ,(+ (simulation-object-len) 12)))
X
X;;SET-BALL-GLOBAL-EVENT-QUEUE-RECORD! set the global event queue record for the
X;;given ball to the given value
X;;BALL = The ball whose global event queue record is to be set
X;;VALUE = The value to which the global event queue record field is to be set
X(define-macro (set-ball-global-event-queue-record! ball value)
X  `(vector-set! ,ball ,(+ (simulation-object-len) 12) ,value))
X
X
X
X;;ACTUAL-MAKE-BUMPER returns a bumper object
X;;BUMPER-NUMBER = An index into the bumper vector for this bumper
X;;X1 = The x-coordiante of one end of the bumper
X;;Y1 = The y-coordiante of one end of the bumper
X;;X2 = The x-coordiante of the other end of the bumper
X;;Y2 = The y-coordiante of the other end of the bumper
X(define-macro (actual-make-bumper bumper-number x1 y1 x2 y2)
X  `(make-simulation-object
X    bumper-collision-procedure		;The collision procedure for a bumper
X    ,bumper-number
X    ,x1					;The bumper endpoints
X    ,y1
X    ,x2
X    ,y2))
X
X(define (make-bumper x1 y1 x2 y2)
X  (actual-make-bumper '() x1 y1 x2 y2))
X
X;;BUMPER-NUMBER returns the index of the given bumper
X;;BUMPER = The bumper whose index is to be returned
X(define-macro (bumper-number bumper)
X  `(vector-ref ,bumper ,(simulation-object-len)))
X
X;;SET-BUMPER-NUMBER! set the index of the given bumper to the given value
X;;BUMPER = The bumper whose index is to be set
X;;VALUE = The value to which it is to be set
X(define-macro (set-bumper-number! bumper value)
X  `(vector-set! ,bumper ,(simulation-object-len) ,value))
X
X;;BUMPER-X1 returns the x-coordinate of one end of the given bumber
X;;BUMPER = the bumper whose x-coordinate is to be returned
X(define-macro (bumper-x1 bumper)
X  `(vector-ref ,bumper ,(1+ (simulation-object-len))))
X
X;;SET-BUMPER-X1! sets the x-coordinate of one end of the given bumber
X;;BUMPER = the bumper whose x-coordinate is to be set
X;;VALUE = The value to which the bumpers x-coordinate is to be set
X(define-macro (set-bumper-x1! bumper value)
X  `(vector-set! ,bumper ,(1+ (simulation-object-len)) ,value))
X
X;;BUMPER-Y1 returns the y-coordinate of one end of the given bumber
X;;BUMPER = the bumper whose y-coordinate is to be returned
X(define-macro (bumper-y1 bumper)
X  `(vector-ref ,bumper ,(+ (simulation-object-len) 2)))
X
X;;SET-BUMPER-Y1! sets the y-coordinate of one end of the given bumber
X;;BUMPER = the bumper whose y-coordinate is to be set
X;;VALUE = The value to which the bumpers y-coordinate is to be set
X(define-macro (set-bumper-y1! bumper value)
X  `(vector-set! ,bumper ,(+ (simulation-object-len) 2) ,value))
X
X;;BUMPER-X2 returns the x-coordinate of the other end of the given bumber
X;;BUMPER = the bumper whose x-coordinate is to be returned
X(define-macro (bumper-x2 bumper)
X  `(vector-ref ,bumper ,(+ (simulation-object-len) 3)))
X
X;;SET-BUMPER-X2! sets the x-coordinate of the other end of the given bumber
X;;BUMPER = the bumper whose x-coordinate is to be set
X;;VALUE = The value to which the bumpers x-coordinate is to be set
X(define-macro (set-bumper-x2! bumper value)
X  `(vector-set! ,bumper ,(+ (simulation-object-len) 3) ,value))
X
X
X;;BUMPER-Y2 returns the y-coordinate of the other end of the given bumber
X;;BUMPER = the bumper whose y-coordinate is to be returned
X(define-macro (bumper-y2 bumper)
X  `(vector-ref ,bumper ,(+ (simulation-object-len) 4)))
X
X;;SET-BUMPER-Y2! sets the y-coordinate of the other end of the given bumber
X;;BUMPER = the bumper whose y-coordinate is to be set
X;;VALUE = The value to which the bumpers y-coordinate is to be set
X(define-macro (set-bumper-y2! bumper value)
X  `(vector-set! ,bumper ,(+ (simulation-object-len) 4) ,value))
X
X;;COLLISION-TIME-<? is a predicate which returns true if the first event queueu
X;;record represents a collision that will take place at an earlier time than
X;;the one for the second event queue record
X;;EVENT-QUEUE-RECORD1 = The first event queue record
X;;EVENT-QUEUE-RECORD2 = The second event queue record
X(define (collision-time-<? event-queue-record1 event-queue-record2)
X  (time-<?
X   (event-queue-record-collision-time
X    event-queue-record1)
X   (event-queue-record-collision-time
X    event-queue-record2)))
X
X;;TIME-<? is a predicate which returns true if the first time is smaller than
X;;the second.  '() represents a time infinitly large.
X(define (time-<? time1 time2)
X  (if (null? time1)
X      #f
X      (if (null? time2)
X	  #t
X	  (< time1 time2))))
X
X;;SQUARE returns the square of its argument
X(define (square x)
X  (* x x))
X
X
X;;BALL-BALL-COLLISION-TIME returns the time at which the two given balls would
X;;collide if neither interacted with any other objects, '() if never.  This
X;;calculation is performed by setting the distance between the balls to the sum
X;;of their radi and solving for the contact time.
X;;BALL1 = The first ball
X;;BALL2 = The second ball
X(define (ball-ball-collision-time ball1 ball2)
X  (let ((delta-x-velocity		;Cache the difference in the ball's
X	 ( - (ball-x-velocity ball2)	;velocities,
X	     (ball-x-velocity ball1)))
X	(delta-y-velocity
X	 ( - (ball-y-velocity ball2)	
X	     (ball-y-velocity ball1)))
X	(radius-sum			;the sum of their radi,
X	 (+ (ball-radius ball1)
X	    (ball-radius ball2)))
X	(alpha-x			;and common subexpressions in the time
X	 (-				;equation
X	  (- (ball-collision-x-position
X	      ball2)
X	     (ball-collision-x-position
X	      ball1))
X	  (-
X	   (* (ball-x-velocity ball2)	
X	      (ball-collision-time
X	       ball2))
X	   (* (ball-x-velocity ball1)	
X	      (ball-collision-time
X	       ball1)))))
X	(alpha-y
X	 (-
X	  (- (ball-collision-y-position
X	      ball2)
X	     (ball-collision-y-position
X	      ball1))
X	  (-
X	   (* (ball-y-velocity ball2)	
X	      (ball-collision-time
X	       ball2))
X	   (* (ball-y-velocity ball1)	
X	      (ball-collision-time
X	       ball1))))))
X    (let* ((delta-velocity-magnitude-squared
X	    (+ (square
X		delta-x-velocity)
X	       (square		
X		delta-y-velocity)))
X	   (discriminant
X	    (- (* (square radius-sum)
X		  delta-velocity-magnitude-squared)
X	       (square
X		(- (* delta-y-velocity
X		      alpha-x)
X		   (* delta-x-velocity
X		      alpha-y))))))
X
X
X      (if (or (negative? discriminant)	;If the balls don't colloide:
X	      (zero?
X	       delta-velocity-magnitude-squared))
X	  '()				;Return infinity
X	  (let ((time			;Else, calculate the collision time
X		 (/
X		  (- 0
X		     (+ (sqrt discriminant)
X			(+
X			 (* delta-x-velocity
X			    alpha-x)
X			 (* delta-y-velocity
X			    alpha-y))))
X		  (+ (square
X		      delta-x-velocity)
X		     (square
X		      delta-y-velocity)))))
X	    (if (and			;If the balls collide in the future:
X		 (time-<?
X		  (ball-collision-time
X		   ball1)
X		  time)
X		 (time-<?
X		  (ball-collision-time
X		   ball2)
X		  time))
X		time			;Return the collision time
X		'()))))))		;Else, return that they never collide
X
X;;BALL-BUMPER-COLLISION-TIME returns the time at which the given ball would
X;;collide with the given bumper if the ball didn't interacted with any other
X;;objects, '() if never.  This is done by first calculating the time at which
X;;the ball would collide with a bumper of infinite length and then checking if
X;;the collision position represents a portion of the actual bumper.
X;;BALL = The ball
X;;BUMPER = The bumper
X(define (ball-bumper-collision-time ball bumper)
X  (let ((delta-x-bumper			;Collision time with the bumper of 
X	 (- (bumper-x2 bumper)		;infinite extent is calculated by 
X	    (bumper-x1 bumper)))	;setting the distance between the ball
X	(delta-y-bumper			;and the bumper to be the radius of the
X	 (- (bumper-y2 bumper)		;ball and solving for the time.  The
X	    (bumper-y1 bumper))))	;distance is calculated by |aXb|/|a|,
X    (let ((bumper-length-squared	;where 'a' is the vector from one end
X	   (+ (square delta-x-bumper)	;of the bumper to the other and 'b' is
X	      (square delta-y-bumper)))	;the vector from the first end of the 
X	  (denominator			;bumper to the center of the ball
X	   (- (* (ball-y-velocity ball)
X		 delta-x-bumper)
X	      (* (ball-x-velocity ball)
X		 delta-y-bumper))))
X      (if (zero? denominator)		;If the ball's motion is parallel to
X					;the bumper:
X	  '()				;Return infinity
X	  (let ((delta-t		;Calculate the collision time
X		 (-
X		  (/
X		   (+
X		    (*
X		     (-	(ball-collision-x-position
X			 ball)
X			(bumper-x1 bumper))
X		     delta-y-bumper)
X		    (*
X		     (- (ball-collision-y-position
X			 ball)
X			(bumper-y1 bumper))
X		     delta-x-bumper))
X		   denominator)
X		  (/
X		   (* (ball-radius
X		       ball)
X		      (sqrt
X		       bumper-length-squared))
X		   (abs denominator)))))
X	    (if (not (positive?		;If the ball is moving away from the
X		      delta-t))		;bumper:
X		'()			;Return infinity
X
X
X		(let ((ball-x-contact	;Whether the ball contacts the actual
X		       (+ (ball-collision-x-position ;bumper of limited extent
X			   ball)	;will be determined by comparing |b.a|
X			  (* (ball-x-velocity ;with |a|^2
X			      ball)
X			     delta-t)))
X		      (ball-y-contact
X		       (+ (ball-collision-y-position
X			   ball)
X			  (* (ball-y-velocity
X			      ball)
X			     delta-t))))
X		  (let ((delta-x-ball
X			 (- ball-x-contact
X			    (bumper-x1
X			     bumper)))
X			(delta-y-ball
X			 (- ball-y-contact
X			    (bumper-y1
X			     bumper))))
X		    (let ((dot-product
X			   (+
X			    (* delta-x-ball
X			       delta-x-bumper)
X			    (* delta-y-ball
X			       delta-y-bumper))))
X		      (if (or		;If the ball misses the bumper on 
X			   (negative?	;either end:
X			    dot-product)
X			   (> dot-product
X			      bumper-length-squared))
X			  '()		;Return infinity
X			  (+ delta-t	;Else, return the contact time
X			     (ball-collision-time
X			      ball))))))))))))
X			       
X
X;;BALL-COLLISION-PROCEDURE calculates the new velocities of the given balls
X;;based on their collision at the given time.  Also, tells all other balls
X;;about the new trajectories of these balls so they can update their event
X;;queues 
X;;BALL1 = The first ball
X;;BALL2 = The second ball
X;;COLLISION-TIME = The collision time
X;;GLOBAL-EVENT-QUEUE = The global queue of earliest events for each ball
X(define (ball-collision-procedure ball1 ball2 collision-time
X				  global-event-queue)
X  (queue-remove				;Remove the earliest event associated
X   (ball-global-event-queue-record	;with each ball from the global event 
X    ball1))				;queue
X  (queue-remove
X   (ball-global-event-queue-record
X    ball2))
X  (let ((ball1-collision-x-position	;Calculate the positions of both balls
X	 (+ (ball-collision-x-position	;when they collide
X	     ball1)
X	    (* (ball-x-velocity
X		ball1)
X	       (- collision-time
X		  (ball-collision-time
X		   ball1)))))
X	(ball1-collision-y-position
X	 (+ (ball-collision-y-position
X	     ball1)
X	    (* (ball-y-velocity
X		ball1)
X	       (- collision-time
X		  (ball-collision-time
X		   ball1)))))
X	(ball2-collision-x-position
X	 (+ (ball-collision-x-position
X	     ball2)
X	    (* (ball-x-velocity
X		ball2)
X	       (- collision-time
X		  (ball-collision-time
X		   ball2)))))
X	(ball2-collision-y-position
X	 (+ (ball-collision-y-position
X	     ball2)
X	    (* (ball-y-velocity
X		ball2)
X	       (- collision-time
X		  (ball-collision-time
X		   ball2))))))
X    (let ((delta-x			;Calculate the displacements of the
X	   (- ball2-collision-x-position ;centers of the two balls
X	      ball1-collision-x-position))
X	  (delta-y
X	   (- ball2-collision-y-position
X	      ball1-collision-y-position)))
X
X
X      (let* ((denominator		;Calculate the angle of the line 
X	      (sqrt (+ (square		;joining the centers at the collision 
X			delta-x)	;time with the x-axis  (this line is
X		       (square		;the normal to the balls at the
X			delta-y))))	;collision point)
X	     (cos-theta			
X	      (/ delta-x denominator))
X	     (sin-theta
X	      (/ delta-y denominator)))
X	  (let ((ball1-old-normal-velocity ;Convert the velocities of the balls
X		 (+ (* (ball-x-velocity	;into the coordinate system defined by 
X			ball1)		;the normal and tangential lines at 
X		       cos-theta)	;the collision point
X		    (* (ball-y-velocity
X			ball1)
X		       sin-theta)))
X		(ball1-tang-velocity
X		 (- (* (ball-y-velocity
X			ball1)
X		       cos-theta)
X		    (* (ball-x-velocity
X			ball1)
X		       sin-theta)))
X		(ball2-old-normal-velocity
X		 (+ (* (ball-x-velocity
X			ball2)
X		       cos-theta)
X		    (* (ball-y-velocity
X			ball2)
X		       sin-theta)))
X		(ball2-tang-velocity
X		 (- (* (ball-y-velocity
X			ball2)
X		       cos-theta)
X		    (* (ball-x-velocity
X			ball2)
X		       sin-theta)))
X		(mass1 (ball-mass
X			ball1))
X		(mass2 (ball-mass
X			ball2)))
X	    (let ((ball1-new-normal-velocity ;Calculate the new velocities
X		   (/			;following the collision (the 
X		    (+			;tangential velocities are unchanged
X		     (*			;because the balls are assumed to be
X		      (* 2		;frictionless)
X			 mass2)
X		      ball2-old-normal-velocity)
X		     (*
X		      (- mass1 mass2)
X		      ball1-old-normal-velocity))
X		    (+ mass1 mass2)))
X
X
X		  (ball2-new-normal-velocity
X		   (/
X		    (+
X		     (*
X		      (* 2
X			 mass1)
X		      ball1-old-normal-velocity)
X		     (*
X		      (- mass2 mass1)
X		      ball2-old-normal-velocity))
X		    (+ mass1 mass2))))
X	      (set-ball-x-velocity!	;Store data about the collision in the
X	       ball1			;structure for each ball after 
X	       (- (* ball1-new-normal-velocity ;converting the information back
X		     cos-theta)		;to the x,y frame
X		  (* ball1-tang-velocity
X		     sin-theta)))
X	      (set-ball-y-velocity!
X	       ball1
X	       (+ (* ball1-new-normal-velocity
X		     sin-theta)
X		  (* ball1-tang-velocity
X		     cos-theta)))
X	      (set-ball-x-velocity!
X	       ball2
X	       (- (* ball2-new-normal-velocity
X		     cos-theta)
X		  (* ball2-tang-velocity
X		     sin-theta)))
X	      (set-ball-y-velocity!
X	       ball2
X	       (+ (* ball2-new-normal-velocity
X		     sin-theta)
X		  (* ball2-tang-velocity
X		     cos-theta)))
X	      (set-ball-collision-time!
X	       ball1
X	       collision-time)
X	      (set-ball-collision-time!
X	       ball2
X	       collision-time)
X	      (set-ball-collision-x-position!
X	       ball1
X	       ball1-collision-x-position)
X	      (set-ball-collision-y-position!
X	       ball1
X	       ball1-collision-y-position)
X	      (set-ball-collision-x-position!
X	       ball2
X	       ball2-collision-x-position)
X	      (set-ball-collision-y-position!
X	       ball2
X	       ball2-collision-y-position))))))
X
X
X  (newline)
X  (display "Ball ")
X  (display (ball-number ball1))
X  (display " collides with ball ")
X  (display (ball-number ball2))
X  (display " at time ")
X  (display (ball-collision-time ball1))
X  (newline)
X  (display "   Ball ")
X  (display (ball-number ball1))
X  (display " has a new velocity of ")
X  (display (ball-x-velocity ball1))
X  (display ",")
X  (display (ball-y-velocity ball1))
X  (display " starting at ")
X  (display (ball-collision-x-position ball1))
X  (display ",")
X  (display (ball-collision-y-position ball1))
X  (newline)
X  (display "   Ball ")
X  (display (ball-number ball2))
X  (display " has a new velocity of ")
X  (display (ball-x-velocity ball2))
X  (display ",")
X  (display (ball-y-velocity ball2))
X  (display " starting at ")
X  (display (ball-collision-x-position ball2))
X  (display ",")
X  (display (ball-collision-y-position ball2))
X
X  (recalculate-collisions ball1 global-event-queue)
X  (recalculate-collisions ball2 global-event-queue))
X
X
X;;BUMPER-COLLISION-PROCEDURE calculates the new velocity of the given ball
X;;following its collision with the given bumper at the given time.  Also, tells
X;;other balls about the new trajectory of the given ball so they can update
X;;their event queues.
X;;BALL = The ball
X;;BUMPER = The bumper
X;;COLLISION-TIME = The collision time
X;;GLOBAL-EVENT-QUEUE = The global queue of earliest events for each ball
X(define (bumper-collision-procedure ball bumper collision-time
X				    global-event-queue)
X  (queue-remove				;Remove the earliest event associated
X   (ball-global-event-queue-record	;with the ball from the global event 
X    ball))				;queue
X  (let ((delta-x-bumper			;Compute the bumper's delta-x
X	 (- (bumper-x2 bumper)
X	    (bumper-x1 bumper)))
X	(delta-y-bumper			;delta-y
X	 (- (bumper-y2 bumper)
X	    (bumper-y1 bumper))))
X    (let ((bumper-length		;length
X	   (sqrt
X	    (+ (square
X		delta-x-bumper)
X	       (square
X		delta-y-bumper)))))
X      (let ((cos-theta			;and cosine and sine of its angle with
X	     (/ delta-x-bumper		;respect to the positive x-axis
X		bumper-length))
X	    (sin-theta
X	     (/ delta-y-bumper
X		bumper-length))
X	    (x-velocity			;Cache the ball's velocity in the x,y
X	     (ball-x-velocity ball))	;frame
X	    (y-velocity
X	     (ball-y-velocity ball)))
X	(let ((tang-velocity		;Calculate the ball's velocity in the
X	       (+ (* x-velocity		;bumper frame
X		     cos-theta)
X		  (* y-velocity
X		     sin-theta)))
X	      (normal-velocity
X	       (- (* y-velocity
X		     cos-theta)
X		  (* x-velocity
X		     sin-theta))))
X
X
X	  (set-ball-collision-x-position! ;Store the collision position
X	   ball
X	   (+ (ball-collision-x-position
X	       ball)
X	      (* (- collision-time
X		    (ball-collision-time
X		     ball))
X		 (ball-x-velocity
X		  ball))))
X	  (set-ball-collision-y-position!
X	   ball
X	   (+ (ball-collision-y-position
X	       ball)
X	      (* (- collision-time
X		    (ball-collision-time
X		     ball))
X		 (ball-y-velocity
X		  ball))))
X	  (set-ball-x-velocity!		;Calculate the new velocity in the 
X	   ball				;x,y frame based on the fact that 
X	   (+ (* tang-velocity		;tangential velocity is unchanged and
X		 cos-theta)		;the normal velocity is inverted when
X	      (* normal-velocity	;the ball collides with the bumper
X		 sin-theta)))
X	  (set-ball-y-velocity!
X	   ball
X	   (- (* tang-velocity
X		 sin-theta)
X	      (* normal-velocity
X		 cos-theta)))
X	  (set-ball-collision-time!
X	   ball
X	   collision-time)))))
X  (newline)
X  (display "Ball ")
X  (display (ball-number ball))
X  (display " collides with bumper ")
X  (display (bumper-number bumper))
X  (display " at time ")
X  (display (ball-collision-time ball))
X  (newline)
X  (display "   Ball ")
X  (display (ball-number ball))
X  (display " has a new velocity of ")
X  (display (ball-x-velocity ball))
X  (display ",")
X  (display (ball-y-velocity ball))
X  (display " starting at ")
X  (display (ball-collision-x-position ball))
X  (display ",")
X  (display (ball-collision-y-position ball))
X
X  (recalculate-collisions ball global-event-queue))
X
X
X;;RECALCULATE-COLLISIONS removes all old collisions for the given ball from
X;;all other balls' event queues and calcultes new collisions for these balls
X;;and places them on the event queues.  Also, updates the global event queue if
X;;the recalculation of the collision effects the earliest collision for any
X;;other balls.
X;;BALL = The ball whose collisions are being recalculated
X;;GLOBAL-EVENT-QUEUE = The global queue of earliest events for each ball
X(define (recalculate-collisions ball global-event-queue)
X  (clear-queue (ball-event-queue	;Clear the queue of events for this 
X		ball))			;ball as they have all changed
X  (let ((event-queue			;Calculate all ball collision events
X	 (ball-event-queue ball)))	;with balls of lower number
X    (let ((ball-vector
X	   (ball-ball-vector ball)))
X      (do ((i (-1+ (ball-number ball))
X	      (-1+ i)))
X	  ((negative? i))
X	(let ((ball2-queue-record
X	       (vector-ref
X		ball-vector
X		i)))
X	  (set-event-queue-record-collision-time!
X	   ball2-queue-record
X	   (ball-ball-collision-time
X	    ball
X	    (event-queue-record-object
X	     ball2-queue-record)))
X	  (queue-insert
X	   event-queue
X	   ball2-queue-record))))
X    (let ((bumper-vector		;Calculate all bumper collision events
X	   (ball-bumper-vector ball)))
X      (do ((i (-1+ (vector-length
X		    bumper-vector))
X	      (-1+ i)))
X	  ((negative? i))
X	(let ((bumper-queue-record
X	       (vector-ref
X		bumper-vector
X		i)))
X	  (set-event-queue-record-collision-time!
X	   bumper-queue-record
X	   (ball-bumper-collision-time
X	    ball
X	    (event-queue-record-object
X	     bumper-queue-record)))
X	  (queue-insert
X	   event-queue
X	   bumper-queue-record))))
X
X
X    (let ((global-queue-record		;Get the global event queue record 
X	   (ball-global-event-queue-record ;for this ball
X	    ball)))
X      (set-event-queue-record-collision-time! ;Set the new earliest event time
X       global-queue-record		;for this ball
X       (if (empty-queue? event-queue)
X	   '()
X	   (event-queue-record-collision-time
X	    (queue-smallest event-queue))))
X      (queue-insert			;Enqueue on the global event queue
X       global-event-queue		;the earliest event between this ball
X       global-queue-record)))		;and any ball of lower number or any
X					;bumper
X  (for-each				;For each ball on the ball list:
X   (lambda (ball2)
X     (let ((ball2-event-queue
X	    (ball-event-queue ball2)))
X       (let ((alter-global-event-queue?	;Set flag to update global event queue 
X	      (and			;if the earliest event for ball2 was
X	       (not (empty-queue?	;with the deflected ball
X		     ball2-event-queue))
X	       (eq? ball
X		    (event-queue-record-object
X		     (queue-smallest
X		      ball2-event-queue)))))
X	     (ball-event-queue-record	;Get the queue record for the deflected
X	      (vector-ref		;ball for this ball
X	       (ball-ball-vector
X		ball2)
X	       (ball-number ball))))
X	 (queue-remove			;Remove the queue record for the 
X	  ball-event-queue-record)	;deflected ball
X	 (set-event-queue-record-collision-time! ;Recalculate the collision 
X	  ball-event-queue-record	;time for this ball and the deflected
X	  (ball-ball-collision-time	;ball
X	   ball
X	   ball2))
X	 (queue-insert			;Enqueue the new collision event
X	  ball2-event-queue
X	  ball-event-queue-record)
X	 (if (or alter-global-event-queue? ;If the earliest collision event for
X		 (eq? ball		;this ball has changed:
X		      (event-queue-record-object
X		       (queue-smallest
X			ball2-event-queue))))
X	     (let ((queue-record	;Remove the old event from the global
X		    (ball-global-event-queue-record ;event queue and replace it
X		     ball2)))		;with the new event
X	       (set-event-queue-record-collision-time! 
X		queue-record
X		(event-queue-record-collision-time
X		 (queue-smallest
X		  ball2-event-queue)))
X	       (queue-remove
X		queue-record)
X	       (queue-insert
X		global-event-queue
X		queue-record))))))
X   (ball-ball-list ball)))
X	   
X
X;;SIMULATE performs the billiard ball simulation for the given ball list and
X;;bumper list until the specified time.  
X;;BALL-LIST = A list of balls
X;;BUMPER-LIST = A list of bumpers
X;;END-TIME = The time at which the simulation is to terminate
X(define (simulate ball-list bumper-list end-time)
X  (let ((num-of-balls			;Cache the number of balls and bumpers
X	 (length ball-list))
X	(num-of-bumpers
X	 (length bumper-list))
X	(global-event-queue		;Build the global event queue
X	 (make-sorted-queue
X	  collision-time-<?)))
X    (let ((complete-ball-vector		;Build a vector for the balls
X	   (make-vector
X	    num-of-balls)))
X      (let loop ((ball-num 0)		;For each ball:
X		 (ball-list ball-list))
X	(if (not (null? ball-list))
X	    (let ((ball (car ball-list)))
X	      (set-ball-number!		;Store the ball's number
X	       ball
X	       ball-num)
X	      (vector-set!		;Place it in the ball vector
X	       complete-ball-vector
X	       ball-num
X	       ball)
X	      (set-ball-ball-list!	;Save the list of balls with ball
X	       ball			;numbers greater than the current ball
X	       (cdr ball-list))
X	      (display-ball-state
X	       ball)
X	      (loop
X	       (1+ ball-num)
X	       (cdr ball-list)))))
X      (let loop ((bumper-num 0)		;For each bumper:
X		 (bumper-list
X		  bumper-list))
X	(if (not (null? bumper-list))
X	    (sequence
X	      (set-bumper-number!	;Store the bumper's number
X	       (car bumper-list)
X	       bumper-num)
X	      (display-bumper-state
X	       (car bumper-list))
X	      (loop
X	       (1+ bumper-num)
X	       (cdr bumper-list)))))
X
X      (do ((ball-num 0 (1+ ball-num)))	;For each ball:
X	  ((= ball-num num-of-balls))
X	(let* ((ball (vector-ref	;Cache a reference to the ball
X		      complete-ball-vector
X		      ball-num))
X	       (ball-vector		;Build a vector for the queue records 
X		(make-vector		;of balls with smaller numbers than 
X		 ball-num))		;this ball
X	       (bumper-vector		;Build a vector for the queue records
X		(make-vector		;of bumpers
X		 num-of-bumpers))
X	       (event-queue		;Build an event queue for this ball
X		(ball-event-queue
X		 ball)))
X	  (set-ball-ball-vector!	;Install the vector of ball queue 
X	   ball				;records
X	   ball-vector)
X	  (do ((i 0 (1+ i)))		;For each ball of smaller number than 
X		  ((= i ball-num))	;the current ball:
X		(let* ((ball2		;Cache the ball
X			(vector-ref
X			 complete-ball-vector
X			 i))
X		       (queue-record	;Create a queue record for this ball
X			(make-event-queue-record ;based on the collision time 
X			 '()		;of the two balls
X			 '()
X			 ball2
X			 (ball-ball-collision-time
X			  ball
X			  ball2))))
X		  (vector-set!		;Install the queue record in the ball
X		   ball-vector		;vector for this ball
X		   i
X		   queue-record)
X		  (queue-insert		;Insert the queue record into the event
X		   event-queue		;queue for this ball
X		   queue-record)))
X
X	  (set-ball-bumper-vector!	;Install the vector of bumper queue
X	   ball				;records
X	   bumper-vector)
X	  (let loop ((bumper-num 0)
X		     (bumper-list
X		      bumper-list))
X	    (if (not (null? bumper-list))
X		(let* ((bumper		;Cache the bumper
X			(car
X			 bumper-list))
X		       (queue-record	;Create a queue record for this bumper
X			(make-event-queue-record ;based on the collision time 
X			 '()		;of the current ball and this bumper
X			 '()
X			 bumper
X			 (ball-bumper-collision-time
X			  ball
X			  bumper))))
X		  (vector-set!		;Install the queue record in the bumper
X		   bumper-vector	;vector for this ball
X		   bumper-num
X		   queue-record)
X		  (queue-insert		;Insert the queue record into the event
X		   event-queue		;queue for this ball
X		   queue-record)
X		  (loop
X		   (1+ bumper-num)
X		   (cdr bumper-list)))))
X	  (let ((queue-record		;Build a global event queue record for
X		 (make-event-queue-record ;the earliest event on this ball's 
X		  '()			;event queue
X		  '()
X		  ball
X		  (if (empty-queue?
X		       event-queue)
X		      '()
X		      (event-queue-record-collision-time
X		       (queue-smallest
X			event-queue))))))
X	    (set-ball-global-event-queue-record! ;Store this queue record in 
X	     ball			;the frame for this ball
X	     queue-record)
X	    (queue-insert		;Insert this queue record in the global
X	     global-event-queue		;event queue
X	     queue-record)))))
X    (actually-simulate			;Now that all of the data structures
X     global-event-queue			;have been built, actually start the 
X     end-time)))			;simulation
X	      
X
X;;DISPLAY-BALL-STATE displays the ball number, mass, radius, position, and
X;;velocity of the given ball
X;;BALL = The ball whose state is to be displayed
X(define (display-ball-state ball)
X  (newline)
X  (display "Ball ")
X  (display (ball-number ball))
X  (display " has mass ")
X  (display (ball-mass ball))
X  (display " and radius ")
X  (display (ball-radius ball))
X  (newline)
X  (display "   Its position at time ")
X  (display (ball-collision-time ball))
X  (display " was ")
X  (display (ball-collision-x-position ball))
X  (display ",")
X  (display (ball-collision-y-position ball))
X  (display " and its velocity is ")
X  (display (ball-x-velocity ball))
X  (display ",")
X  (display (ball-y-velocity ball)))
X
X;;DISPLAY-BUMPER-STATE displays the bumper number and position of the given
X;;bumper 
X;;BUMPER = The bumper whose state is to be displayed
X(define (display-bumper-state bumper)
X  (newline)
X  (display "Bumper ")
X  (display (bumper-number bumper))
X  (display " extends from ")
X  (display (bumper-x1 bumper))
X  (display ",")
X  (display (bumper-y1 bumper))
X  (display " to ")
X  (display (bumper-x2 bumper))
X  (display ",")
X  (display (bumper-y2 bumper)))
X
X
X;;ACTUALLY-SIMULATE performs the actual billiard ball simulation
X;;GLOBAL-EVENT-QUEUE = The global queue of earliest events for each ball.
X;;                     Contains a single event for each ball which is the
X;;                     earliest collision it would have with a ball of a
X;;                     smaller number or a bumper, if no other collisions took
X;;                     place first.
X;;END-TIME = The time at which the simulation should be terminated
X(define (actually-simulate global-event-queue end-time)
X  (letrec ((loop			
X	    (lambda ()
X	      (let* ((record		;Get the globally earliest event and
X		      (queue-smallest	;its time
X		       global-event-queue))
X		     (collision-time
X		      (event-queue-record-collision-time
X		       record)))
X		(if (not		;If this event happens before the
X		     (time-<?		;simulation termination time:
X		      end-time
X		      collision-time))
X		    (let* ((ball	;Get the ball involved in the event,
X			    (event-queue-record-object
X			     record))
X			   (ball-queue	;the queue of events for that ball,
X			    (ball-event-queue
X			     ball))
X			   (other-object ;and the first object with which the 
X			    (event-queue-record-object ;ball interacts
X			     (queue-smallest
X			      ball-queue))))
X		      ((simulation-object-collision-procedure ;Process this
X			other-object)	;globally earliest collision
X		       ball
X		       other-object
X		       collision-time
X		       global-event-queue)
X		      (loop)))))))	;Process the next interaction
X    (loop)))
X
X
X(require 'cscheme)
X(set! autoload-notify? #f)
X
X        (simulate
X         (list (make-ball 2 1 9 5 -1 -1)
X               (make-ball 4 2 2 5 1 -1))
X         (list (make-bumper 0 0 0 10)
X               (make-bumper 0 0 10 0)
X               (make-bumper 0 10 10 10)
X               (make-bumper 10 0 10 10))
X         100)
END_OF_tst/billiard
if test 46118 -ne `wc -c <tst/billiard`; then
    echo shar: \"tst/billiard\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f lib/xlib/examples/properties -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"lib/xlib/examples/properties\"
else
echo shar: Extracting \"lib/xlib/examples/properties\" \(969 characters\)
sed "s/^X//" >lib/xlib/examples/properties <<'END_OF_lib/xlib/examples/properties'
X;;; -*-Scheme-*-
X;;;
X;;; Display all properties of all windows (with name, type, format,
X;;; and data).
X
X(require 'xlib)
X
X(define (properties)
X  (let ((dpy (open-display)))
X    (unwind-protect
X     (let* ((w (car (query-tree (display-root-window dpy))))
X	    (l (map (lambda (win) (cons win (list-properties win)))
X		    (cons (display-root-window dpy) (vector->list w))))
X	    (tab (lambda (obj n)
X		   (let* ((s (format #f "~s" obj))
X			  (n (- n (string-length s))))
X		     (display s)
X		     (if (positive? n)
X			 (do ((i 0 (1+ i))) ((= i n)) (display #\space)))))))
X       (for-each
X	(lambda (w)
X	  (format #t "Window ~s:~%" (car w))
X	  (for-each
X	   (lambda (p)
X	     (tab (atom-name dpy p) 20)
X	     (display "= ")
X	     (let ((p (get-property (car w) p #f 0 20 #f)))
X	       (tab (atom-name dpy (car p)) 18)
X	       (tab (cadr p) 3)
X	       (format #t "~s~%" (caddr p))))
X	   (vector->list (cdr w)))
X	  (newline))
X	l))
X     (close-display dpy))))
X
X(properties)
END_OF_lib/xlib/examples/properties
if test 969 -ne `wc -c <lib/xlib/examples/properties`; then
    echo shar: \"lib/xlib/examples/properties\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f lib/xlib/examples/track -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"lib/xlib/examples/track\"
else
echo shar: Extracting \"lib/xlib/examples/track\" \(1062 characters\)
sed "s/^X//" >lib/xlib/examples/track <<'END_OF_lib/xlib/examples/track'
X;;; -*-Scheme-*-
X
X(require 'xlib)
X
X(define (track)
X  (let* ((dpy (open-display))
X	 (root (display-root-window dpy))
X	 (gc (make-gcontext (window root)
X			    (function 'xor)
X			    (foreground (black-pixel dpy))
X			    (subwindow-mode 'include-inferiors)))
X	 (lx 0) (ly 0) (lw 0) (lh 0)
X	 (move-outline
X	  (lambda (x y w h)
X	    (if (not (and (= x lx) (= y ly) (= w lw) (= h lh)))
X		(begin
X		  (draw-rectangle root gc lx ly lw lh)
X		  (draw-rectangle root gc x y w h)
X		  (set! lx x) (set! ly y)
X		  (set! lw w) (set! lh h))))))
X    (unwind-protect
X     (case (grab-pointer root #f '(pointer-motion button-press)
X			 #f #f 'none 'none 'now)
X       (success
X	(with-server-grabbed dpy
X	  (draw-rectangle root gc lx ly lw lh)
X	  (display-flush-output dpy)
X	  (handle-events dpy
X	    (motion-notify
X	     (lambda (event root win subwin time x y . rest)
X	       (move-outline x y 300 300) #f))
X	    (else (lambda args #t)))))
X       (else
X	(format #t "Not grabbed!~%")))
X     (begin
X       (draw-rectangle root gc lx ly lw lh)
X       (close-display dpy)))))
X
X(track)
END_OF_lib/xlib/examples/track
if test 1062 -ne `wc -c <lib/xlib/examples/track`; then
    echo shar: \"lib/xlib/examples/track\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f lib/xlib/examples/picture -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"lib/xlib/examples/picture\"
else
echo shar: Extracting \"lib/xlib/examples/picture\" \(2425 characters\)
sed "s/^X//" >lib/xlib/examples/picture <<'END_OF_lib/xlib/examples/picture'
X;;; -*-Scheme-*-
X
X;;; -*- Mode:Lisp; Package:XLIB; Syntax:COMMON-LISP; Base:10; Lowercase:T -*-
X
X;;; CLX - Point Graphing demo program
X
X;;; Copyright (C) 1988 Michael O. Newton (newton@csvax.caltech.edu)
X
X;;; Permission is granted to any individual or institution to use, copy,
X;;; modify, and distribute this software, provided that this complete
X;;; copyright and permission notice is maintained, intact, in all copies and
X;;; supporting documentation.
X
X;;; The author provides this software "as is" without express or
X;;; implied warranty.
X
X;;; This routine plots the recurrance
X;;;      x <- y(1+sin(0.7x)) - 1.2(|x|)^.5
X;;;      y <- .21 - x
X;;; As described in a ?? 1983 issue of the Mathematical Intelligencer
X;;; It has ONLY been tested under X.V11R2 on a Sun3 running KCL
X
X(require 'xlib)
X
X(define (picture point-count)
X  (let* ((dpy (open-display))
X	 (width 600)
X	 (height 600)
X	 (black (black-pixel dpy))
X	 (white (white-pixel dpy))
X	 (root (display-root-window dpy))
X	 (win (make-window (parent root) (background-pixel white)
X			   (event-mask '(exposure button-press))
X			   (width width) (height height)))
X	 (gc (make-gcontext (window win)
X			    (background white) (foreground black))))
X    (map-window win)
X    (unwind-protect
X     (handle-events dpy
X       (expose
X	(lambda ignore
X	  (clear-window win)
X	  (draw-points win gc point-count 0.0 0.0 (* width 0.5) (* height 0.5))
X	  (draw-poly-text win gc 10 10 (translate "Click a button to exit")
X			  '1-byte)
X	  #f))
X       (else (lambda ignore #t)))
X     (close-display dpy))))
X
X;;; Draw points.  These should maybe be put into a an array so that they do
X;;; not have to be recomputed on exposure.  X assumes points are in the range
X;;; of width x height, with 0,0 being upper left and 0,H being lower left.
X;;;      x <- y(1+sin(0.7x)) - 1.2(|x|)^.5
X;;;      y <- .21 - x
X;;; hw and hh are half-width and half-height of screen
X
X(define (draw-points win gc count x y hw hh)
X  (if (zero? (modulo count 100))
X      (display-flush-output (window-display win)))
X  (if (not (zero? count))
X      (let ((xf (floor (* (+ 1.2 x) hw ))) ; These lines center the picture
X	    (yf (floor (* (+ 0.5 y) hh ))))
X	(draw-point win gc xf yf)
X	(draw-points win gc (1- count)
X		     (- (* y (1+ (sin (* 0.7 x)))) (* 1.2 (sqrt (abs x))))
X		     (- 0.21 x)
X		     hw hh))))
X
X(define (translate string)
X  (list->vector (map char->integer (string->list string))))
X
X(picture 10000)
END_OF_lib/xlib/examples/picture
if test 2425 -ne `wc -c <lib/xlib/examples/picture`; then
    echo shar: \"lib/xlib/examples/picture\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f lib/xlib/examples/useful -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"lib/xlib/examples/useful\"
else
echo shar: Extracting \"lib/xlib/examples/useful\" \(567 characters\)
sed "s/^X//" >lib/xlib/examples/useful <<'END_OF_lib/xlib/examples/useful'
X;;; -*-Scheme-*-
X
X(require 'xlib)
X
X(define dpy
X  (open-display))
X
X(define (f)
X  (display-wait-output dpy #t))
X
X(define root
X  (display-root-window dpy))
X
X(define cmap
X  (display-colormap dpy))
X
X(define white (white-pixel dpy))
X(define black (black-pixel dpy))
X
X(define rgb-white (query-color cmap white))
X(define rgb-black (query-color cmap black))
X
X(define win
X  (make-window (parent root)
X	       (width 300) (height 300)
X	       (background-pixel white)))
X
X(define gc (make-gcontext
X	    (window win)
X	    (background white) (foreground black)))
X
X(map-window win)
END_OF_lib/xlib/examples/useful
if test 567 -ne `wc -c <lib/xlib/examples/useful`; then
    echo shar: \"lib/xlib/examples/useful\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f lib/xlib/pixel.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"lib/xlib/pixel.c\"
else
echo shar: Extracting \"lib/xlib/pixel.c\" \(1332 characters\)
sed "s/^X//" >lib/xlib/pixel.c <<'END_OF_lib/xlib/pixel.c'
X#include "xlib.h"
X
XGeneric_Predicate (Pixel);
X
XGeneric_Simple_Equal (Pixel, PIXEL, pix);
X
XGeneric_Print (Pixel, "#[pixel 0x%lx]", PIXEL(x)->pix);
X
XObject Make_Pixel (val) unsigned long val; {
X    register char *p;
X    Object pix;
X
X    pix = Find_Object (T_Pixel, (GENERIC)0, Match_X_Obj, val);
X    if (Nullp (pix)) {
X	p = Get_Bytes (sizeof (struct S_Pixel));
X	SET (pix, T_Pixel, (struct S_Pixel *)p);
X	PIXEL(pix)->tag = Null;
X	PIXEL(pix)->pix = val;
X	Register_Object (pix, (GENERIC)0, (PFO)0, 0);
X    }
X    return pix;
X}
X
Xunsigned long Get_Pixel (p) Object p; {
X    Check_Type (p, T_Pixel);
X    return PIXEL(p)->pix;
X}
X
Xstatic Object P_Pixel_Value (p) Object p; {
X    return Make_Unsigned ((unsigned)Get_Pixel (p));
X}
X
Xstatic Object P_Black_Pixel (d) Object d; {
X    Check_Type (d, T_Display);
X    return Make_Pixel (BlackPixel (DISPLAY(d)->dpy,
X	DefaultScreen (DISPLAY(d)->dpy)));
X}
X
Xstatic Object P_White_Pixel (d) Object d; {
X    Check_Type (d, T_Display);
X    return Make_Pixel (WhitePixel (DISPLAY(d)->dpy, 
X	DefaultScreen (DISPLAY(d)->dpy)));
X}
X
Xinit_xlib_pixel () {
X    Generic_Define (Pixel, "pixel", "pixel?");
X    Define_Primitive (P_Pixel_Value,   "pixel-value",    1, 1, EVAL);
X    Define_Primitive (P_Black_Pixel,   "black-pixel",    1, 1, EVAL);
X    Define_Primitive (P_White_Pixel,   "white-pixel",    1, 1, EVAL);
X}
END_OF_lib/xlib/pixel.c
if test 1332 -ne `wc -c <lib/xlib/pixel.c`; then
    echo shar: \"lib/xlib/pixel.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 9 \(of 14\).
cp /dev/null ark9isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 14 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0