; ; Snake game for Adafruit PyGamer ; ; Coordinates (defun move (dir) (nth dir '((0 0) (0 -1) (1 0) (0 1) (-1 0)))) (defun add (c1 c2) (list (mod (+ (first c1) (first c2)) 20) (mod (+ (second c1) (second c2)) 16))) ; Sprites (defun sprite (grid coord cell char) (let ((x (first coord)) (y (second coord))) (draw-char (* 8 x) (* 8 y) char) (setf (aref grid x y) cell))) (defun headsprite (n) (nth (1- n) '(#\030 #\016 #\031 #\017))) (defvar bodysprite #\004) (defun tailsprite (n) (nth (1- n) '(#\| #\- #\| #\-))) ; Reading the buttons (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)))))) ; Sound effects (defun sound (fy) (dotimes (y 96) (dotimes (x (funcall fy y)) (analogwrite 14 (* 16 x))))) (defun crash (y) (* y 4)) (defun gobble (y) (- 96 y)) (defun drop (y) 32) ; Maybe drop food (defun drop-food (grid) (loop (let ((cell (list (random 20) (random 16))) (meal (1+ (random 9)))) ; Find an empty space to drop it (when (zerop (aref grid (first cell) (second cell))) (sprite grid cell (+ 10 meal) (code-char (+ (char-code #\0) meal))) (sound drop) (return)))))) ; Game over (defun game-over () (set-text-size 4) (set-cursor 36 32) (with-gfx (str) (princ "GAME" str)) (set-cursor 36 64) (with-gfx (str) (princ "OVER" str))) ; The game! (defun play () ; Start new game (loop ; Enable speaker amp (digitalwrite 51 1) (fill-screen) ; Draw initial snake (let ((grid (make-array '(20 16) :initial-element 0)) (headxy '(8 8)) (tailxy '(11 8)) (direction 4) ; West (grow 0)) (sprite grid headxy 5 (headsprite direction)) (sprite grid '(9 8) direction bodysprite) (sprite grid '(10 8) direction bodysprite) (sprite grid tailxy direction (tailsprite direction)) ; Main game loop (loop (let* ((hxy (add headxy (move direction))) (newhead (aref grid (first hxy) (second hxy)))) ; Test for collision (cond ((> newhead 10) (setq grow (- newhead 10)) (sound gobble)) ((plusp newhead) (sound crash) (return))) ; Move head (sprite grid headxy direction bodysprite) (sprite grid hxy 5 (headsprite direction)) (setq headxy hxy) ; Move tail unless growing (cond ((zerop grow) (let* ((oldtail (aref grid (first tailxy) (second tailxy))) (txy (add tailxy (move oldtail)))) (sprite grid tailxy 0 #\space) (sprite grid txy (aref grid (first txy) (second txy)) (tailsprite oldtail)) (setq tailxy txy))) (t (decf grow))) ; Maybe drop food (when (zerop (random 100)) (drop-food grid)) ; Read keys (let ((r (case (readgamerbuttons) (1 4) (2 1) (4 3) (8 2) (t 0)))) (unless (or (zerop r) (= 2 (abs (- r direction)))) (setq direction r))) (delay 100))) (delay 2000) (game-over) ; Wait for Start button (loop (when (= 32 (readgamerbuttons)) (return))))))