(require 2htdp/image) (require 2htdp/universe) ;;; The snake game ;;; Constants (define PIXELS/GRID 10) (define FOOD-COLOR "green") (define FOOD-IMAGE (circle (/ PIXELS/GRID 2) "solid" FOOD-COLOR)) (define SEG-COLOR "red") (define SEG-IMAGE (circle (/ PIXELS/GRID 2) "solid" SEG-COLOR)) (define BOARD-WIDTH 30) ; in grid cells (define BOARD-HEIGHT 40) ; in grid cells (define BOARD (empty-scene (* PIXELS/GRID BOARD-WIDTH) (* PIXELS/GRID BOARD-HEIGHT))) ;;; grid coordinates have the origin in the bottom-left ;;; and the x-axis goes to the right; the y-axis goes up ;;; Things that aren't constants ;;; A LOS is one of: ;;; - empty ;;; - (cons Seg LOS) ;;; A NELOS is one of: ;;; - (cons Seg empty) ;;; - (cons Seg NELOS) ;;; Note: it would really be nice if the segments were adjacent ;;; The head of the snake is the first item in the list ;;; The tail of the snake is the last item in the list ;;; A Seg is (make-posn Number Number) ; in grid coordinates ;;; A Dir is one of: 'up, 'down, 'left, 'right ;;; A Snake is (make-snake NELOS Dir) *** CRUCIAL FIX! (define-struct snake (segs dir)) ;;; A Food is (make-posn Number Number) ; in grid coordinates ;;; A Key is one of: ... ;;; A World is (make-world Snake Food) (define-struct world (snake food)) (define segs1 (list (make-posn 2 3))) (define segs2 (list (make-posn 2 3) (make-posn 3 3) (make-posn 4 3) (make-posn 5 3) (make-posn 5 4) (make-posn 5 5))) (define snake1 (make-snake segs1 'up)) (define snake2 (make-snake segs2 'up)) (define food1 (make-posn 10 10)) (define initial-world (make-world snake2 food1)) (define eating-world (make-world snake2 (make-posn 2 3))) (define dead-world (make-world (make-snake (list (make-posn 30 10)) 'right) food1)) #; (define (food-tmpl a-food) ... (posn-x a-food) ... (posn-y a-food) ...) #; (define (dir-tmpl a-dir) (cond [(symbol=? 'up a-dir) ...] [(symbol=? 'left a-dir) ...] [(symbol=? 'down a-dir) ...] [else ...])) #; (define (los-tmpl a-los) (cond [(empty? a-los) ...] [else ... (first a-los) ... (los-tmpl (rest a-los)) ...])) #; (define (nelos-tmpl a-nelos) (cond [(empty? (rest a-nelos)) ...(first a-nelos)...] [else ... (first a-nelos) ... (nelos-tmpl (rest a-nelos)) ...])) #; (define (snake-tmpl a-snake) ... (snake-segs a-snake) ... (snake-dir a-snake) ...) #| ;; Logic grow-snake : Snake -> Snake eating? : World -> Boolean snake-dead? : Snake -> Boolean snake-hit-self? : Snake -> Boolean snake-hit-wall? : Snake -> Boolean new-food : -> Food ;; Big-bang stuff key-handler : ... next-world : World -> World |# ;; Logic functions ;;slither-snake : Snake -> Snake ;; Slithers a snake by one cell in the current direction (define (slither-snake snake) (make-snake (new-segs (snake-segs snake) (snake-dir snake)) (snake-dir snake))) (define (new-segs nelos dir) (cons (move-seg (first nelos) dir) (nelos-without-tail nelos))) ;; move-seg/xy : Seg Number Number -> Seg ;; Moves the given segment by the deltas in x and y (define (move-seg/xy seg dx dy) (make-posn (+ dx (posn-x seg)) (+ dy (posn-y seg)))) ;;move-seg : Seg Dir -> Seg ;; Moves a segment 1 grid cell in the given diection (define (move-seg seg dir) (cond [(symbol=? 'up dir) (move-seg/xy seg 0 1)] [(symbol=? 'left dir) (move-seg/xy seg -1 0)] [(symbol=? 'down dir) (move-seg/xy seg 0 -1)] [else (move-seg/xy seg 1 0)])) ;;nelos-without-tail : NELOS -> LOS (define (nelos-without-tail nelos) (cond [(empty? (rest nelos)) empty] [else (cons (first nelos) (nelos-without-tail (rest nelos)))])) ;; Rendering functions ;;world->image : World -> Image ;; draws the world (food and snake) (define (world->image world) (snake+image (world-snake world) (food+image (world-food world) BOARD))) ;;place-image/grid : Image Number Number Image -> Image ;; Just like place-image, except in grid coordinates (define (place-image/grid img1 x y img2) (place-image img1 (* (+ x 1/2) PIXELS/GRID) (* (- BOARD-HEIGHT (+ y 1/2)) PIXELS/GRID) img2)) ;;snake+image : Snake Image -> Image ;; Draws the snake onto the provided image (define (snake+image snake image) (los+image (snake-segs snake) image)) (define (los+image los image) (cond [(empty? los) image] [else (place-image/grid SEG-IMAGE (posn-x (first los)) (posn-y (first los)) (los+image (rest los) image))])) ;;food+image : Food Image -> Image ;; draws the food onto the provided image (define (food+image food image) (place-image/grid FOOD-IMAGE (posn-x food) (posn-y food) image)) ;; next-world : World -> World (define (next-world world) (make-world (slither-snake (world-snake world)) (world-food world))) ;; key-handler (define (key-handler world keyevent) (cond [(or (string=? keyevent "up") (string=? keyevent "down") (string=? keyevent "left") (string=? keyevent "right")) (make-world (make-snake (snake-segs (world-snake world)) (string->symbol keyevent)) (world-food world))] [else world])) (big-bang initial-world (on-tick next-world 1/3) (on-key key-handler) (to-draw world->image))