; Maze game for Adafruit PyGamer v2 - 7th December 2021 ; ; Reading the PyGamer joystick (defun joystick () (let ((x 0) (x0 536) (y 0) (y0 523)) (dotimes (s 3) (incf x (analogread 25)) (incf y (analogread 24))) (list (- (truncate x 3) x0) (- (truncate y 3) y0)))) (defun readgamerbuttons () (let ((buttons 0) (clock 48) (data 49) (latch 50)) (pinmode clock t) (digitalWrite clock 0) (pinmode latch t) (digitalWrite latch 1) (pinmode data nil) (digitalwrite latch 0) (digitalWrite latch 1) (dotimes (b 8 buttons) (setq buttons (logior (ash buttons 1) (if (digitalread data) 1 0))) (digitalwrite clock 1) (digitalwrite clock 0)) (let* ((j (joystick)) (x (first j)) (y (second j))) (logior buttons (cond ((< x -350) 1) ((< y -350) 2) ((> y 350) 4) ((> x 350) 8) (t 0)))))) ; Colours (defvar mazecol #xF80F) ; Red + some blue (defvar green #x07E0) (defvar boardcol 0) ; Black (defvar gold #xFFE0) ; Maze parameters (defvar mwidth 20) (defvar mheight 15) (defvar gap 8) (defvar mx 0) (defvar my 8) (defvar cellsize 6) (defvar wall 1) (defvar grid) ; Directions W N S E (defun dx (dir) (nth dir '(-1 0 0 1))) (defun dy (dir) (nth dir '( 0 -1 1 0))) (defun opposite (dir) (- 3 dir)) (defvar maxdepth) (defvar gx) (defvar gy) (defun init-maze () (fill-rect mx my (* gap mwidth) (* gap mheight) mazecol) (fill-rect (+ mx wall) (+ my wall) cellsize cellsize boardcol) (setq grid (make-array (list mwidth mheight) :initial-element 0)) (setq maxdepth 0) (create-maze 0 0 0)) (defun create-maze (ax ay depth) (when (> depth maxdepth) (setf gx ax gy ay maxdepth depth)) (let ((r (random 4))) (dotimes (d 4) (let* ((dir (mod (+ d r) 4)) (bx (+ ax (dx dir))) (by (+ ay (dy dir)))) (when (and (< -1 bx mwidth) (< -1 by mheight) (zerop (aref grid bx by))) (setf (aref grid bx by) (ash 1 (opposite dir))) (setf (aref grid ax ay) (logior (aref grid ax ay) (ash 1 dir))) (create-maze bx by (incf depth))))))) (defun draw-maze () (dotimes (x mwidth) (dotimes (y mheight) (let* ((cell (aref grid x y)) (cx (+ mx (* x 8))) (cy (+ my (* y 8))) (dx (+ cx gap -1)) (dy (+ cy gap -1))) (unless (logbitp 0 cell) (draw-line cx cy cx dy)) (unless (logbitp 1 cell) (draw-line cx cy dx cy)) (unless (logbitp 2 cell) (draw-line cx dy dx dy)) (unless (logbitp 3 cell) (draw-line dx cy dx dy)))))) (defun sprite (x y col) (fill-round-rect (+ (* 8 x) mx 1) (+ (* 8 y) my 1) cellsize cellsize 2 col)) (defun display (txt) (with-gfx (str) (fill-rect 0 0 160 8 0) (set-cursor 0 0) (princ txt str))) (defun play () (let ((direction 1) (time 0) (score 0) (x 0) (y 0) (start (millis))) (init-maze) (draw-maze) (sprite x y green) (sprite gx gy gold) (loop (let ((now (truncate (- (millis) start) 1000))) (when (> now time) (setq time now) (display (format nil "Time: ~a" time)))) ; Read buttons (let ((r (case (readgamerbuttons) (1 0) (2 1) (4 2) (8 3) (t nil)))) (when r (setq direction r) ; Are we allowed to go that way? (when (logbitp direction (aref grid x y)) ; Undraw old position and draw new one (sprite x y mazecol) (incf x (dx direction)) (incf y (dy direction)) ; At goal? (when (and (= x gx) (= y gy)) (display (format nil "Solved in ~a secs!" time)) (return)) (sprite x y green)))) (delay 100))))