;;; -*- Mode:LISP; Package:HACKS; Base:8; Readtable:ZL -*- (defflavor wormy-flavor () (tv:label-mixin tv:kbd-mouse-buttons-mixin tv:select-mixin tv:graphics-mixin tv:borders-mixin tv:stream-mixin tv:minimum-window)) (defvar *worm-step-length* 10.) (defvar *decision-node-radius* 3) (defvar *worm-pond* nil) (defvar *blinker* nil) (defvar *pond-dimensions*) (defvar *x-delta-array* (make-array 9. :element-type '(signed-byte 16.))) (defvar *y-delta-array* (make-array 9. :element-type '(signed-byte 16.))) (defvar *direction-to-go* (make-array 256. :element-type '(mod 16.))) (defconst pi//4 (// pi 4)) (defconst pi//8 (// pi 8.)) (defconst  0.0000001) (defvar *diagonal-trails*) (defvar *straight-trails*) (defvar *move-list*) (defvar *x-pos*) (defvar *y-pos*) (defun worm-trails () (unwind-protect (progn (if (null *worm-pond*) (initialize-pond)) (send *worm-pond* ':expose) (send *worm-pond* ':select) (do ((play-it-again t (let ((*query-io* *worm-pond*)) (y-or-n-p "Again? ")))) ((null play-it-again)) (send *worm-pond* :clear-window) (let ((returnage (wander-around))) (send *worm-pond* ':set-cursorpos 0 0 ':character) (format *worm-pond* "Died of ~A~&Length: ~A~&Moves were ~A~%" (first returnage) (second returnage) (nreverse (cddr returnage)))))) (send *worm-pond* :deselect))) (defun wander-around () (let ((*x-pos* (truncate (car *pond-dimensions*) 2)) ;start in the center of the screen (*y-pos* (truncate (cadr *pond-dimensions*) 2)) (*move-list* nil) (*straight-trails* 0) (*diagonal-trails* 0)) (fill *direction-to-go* 0) ;you don't know what to do! (do ((forced-move 1 (1+ forced-move)) (forced-nodes '(254. 253. 251. 247. 239. 223. 191. 127.) (cdr forced-nodes))) ((null forced-nodes)) (aset forced-move *direction-to-go* (car forced-nodes))) (hacks:with-real-time (do ((node (calculate-node) (calculate-node))) ((or (not (plusp *x-pos*)) ;run until you hit a wall (not (plusp *y-pos*)) ( *x-pos* (car *pond-dimensions*)) ( *y-pos* (cadr *pond-dimensions*))) (punt 'brain-damage)) (if (= node 255.) (return (punt 'starvation)) (move (if (zerop (aref *direction-to-go* node)) (ask-where-to-go node) (aref *direction-to-go* node)))))))) (defun move (direction) (let ((new-x (+ *x-pos* (* (aref *x-delta-array* direction) *worm-step-length*))) (new-y (+ *y-pos* (* (aref *y-delta-array* direction) *worm-step-length*)))) (send *worm-pond* ':draw-line *x-pos* *y-pos* new-x new-y tv:alu-ior) (if (evenp direction) (setq *diagonal-trails* (1+ *diagonal-trails*)) (setq *straight-trails* (1+ *straight-trails*))) (setq *x-pos* new-x ;update global position of worm. *y-pos* new-y))) (defun calculate-node () (do ((node-value 0) (direction 1 (1+ direction)) (pixel-value 1 (lsh pixel-value 1))) ((= direction 9.) node-value) (if (not (zerop (send *worm-pond* ':point (+ *x-pos* (aref *x-delta-array* direction)) (+ *y-pos* (aref *y-delta-array* direction))))) (setq node-value (+ node-value pixel-value))))) (defun ask-where-to-go (node &aux (offset (* *worm-trails-blinker-halfsize* *worm-trails-blinker-factor*))) (send *worm-pond* ':draw-circle *x-pos* *y-pos* *decision-node-radius*) (sys:%beep 500. 100000.) (setq tv:mouse-x *x-pos* tv:mouse-y *y-pos*) (send *blinker* ':set-cursorpos (- *x-pos* offset) (- *y-pos* offset)) (send *blinker* ':set-visibility ':on) (tv:with-mouse-usurped (setq tv:who-line-mouse-grabbed-documentation " Move mouse around to see possible worm moves -- Click any to select one.") (do ((over-line nil) (old-direction 0) (new-direction 0) (delta-mouse (multiple-value-list (tv:mouse-input)) (multiple-value-list (tv:mouse-input))) (mouse-x *x-pos* (fifth delta-mouse)) (mouse-y *y-pos* (sixth delta-mouse))) ((and (not (zerop tv:mouse-last-buttons)) (de-click) (not over-line)) (send *blinker* ':set-visibility ':off) (learn-to-go-from node new-direction) new-direction) (send *blinker* ':set-cursorpos (- mouse-x offset) (- mouse-y offset)) (setq new-direction (calculate-direction mouse-x mouse-y)) (cond (( old-direction new-direction) (if (not over-line) (ghost-line old-direction)) (cond ((zerop (send *worm-pond* ':point (+ *x-pos* (aref *x-delta-array* new-direction)) (+ *y-pos* (aref *y-delta-array* new-direction)))) (ghost-line new-direction) (setq over-line nil)) (t (sys:%beep 250. 10000.) (setq over-line t))) (setq old-direction new-direction)))))) (defun de-click () (do ((delta-mouse (multiple-value-list (tv:mouse-input)) (multiple-value-list (tv:mouse-input)))) ((zerop tv:mouse-last-buttons) t))) (defun ghost-line (direction) (send *worm-pond* ':draw-line *x-pos* *y-pos* (+ *x-pos* (* (aref *x-delta-array* direction) *worm-step-length*)) (+ *y-pos* (* (aref *y-delta-array* direction) *worm-step-length*)) tv:alu-xor nil) T) (defun calculate-direction (x y) (do ((angle (atan (- *y-pos* y) (+ (- x *x-pos*) ))) (border-angle pi//8 (+ border-angle pi//4)) (direction 1) (doop 2 (1+ doop))) ((= doop 10.) (if (= direction 9.) 1 direction)) (if (> angle border-angle) (setq direction doop)))) (defun learn-to-go-from (node direction) (setq *move-list* (cons direction *move-list*)) (do ((rotated-nodes nil (cons temp-node rotated-nodes)) (temp-node node (* temp-node 2)) (temp-direction direction (1+ temp-direction))) ((mem #'= temp-node rotated-nodes)) (if (> temp-node 255.) (setq temp-node (- temp-node 255.))) (if (> temp-direction 8.) (setq temp-direction (- temp-direction 8.))) (aset temp-direction *direction-to-go* temp-node))) (defun punt (reason) (sys:%beep 2000. 100000.) ; (setq tv:who-line-mouse-grabbed-documentation ; " hit any character when done gawking at screen") (send *worm-pond* :tyi) (cons reason (cons (+ *straight-trails* ;I think this number is more what the user wants to know - RMS. *diagonal-trails*) ; (* *diagonal-trails* (sqrt 2.0))) *move-list*))) (defdemo "Worm-Trails" "Teach this ignorant worm to be efficient and live." (worm-trails)) (compile-flavor-methods wormy-flavor) (defconst *worm-trails-blinker-factor* 2) (defconst *worm-trails-blinker-halfsize* 6) (defun initialize-pond () (setq *worm-pond* (make-instance 'wormy-flavor :borders 5 :label nil :activate-p t :expose-p nil :blinker-p nil) *blinker* (make-instance 'tv:magnifying-blinker :sheet *worm-pond* :height (* 2 *worm-trails-blinker-halfsize* *worm-trails-blinker-factor*) :width (* 2 *worm-trails-blinker-halfsize* *worm-trails-blinker-factor*) :x-offset (* *worm-trails-blinker-halfsize* *worm-trails-blinker-factor*) :y-offset (* *worm-trails-blinker-halfsize* *worm-trails-blinker-factor*) :magnification *worm-trails-blinker-factor* :half-period 10. :visibility :off) *pond-dimensions* (multiple-value-list (send *worm-pond* :size))) (fillarray *x-delta-array* '(0 1 1 0 -1 -1 -1 0 1)) (fillarray *y-delta-array* '(0 0 -1 -1 -1 0 1 1 1)))