Created
May 8, 2012 22:44
-
-
Save davesmylie/2640081 to your computer and use it in GitHub Desktop.
exercise 170
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;Exercise 170: Design an interactive GUI program that continually moves a one-segment worm and enables a player to | |
;control the movement of the worm with the four cardinal arrow keys. Your program should use a red disk to render the | |
;one-and-only segment of the worm. For each clock tick, the worm should move diameter. | |
; Game constants and constants | |
; We make the worm size changable here, and when we move the worm it will be by the amount | |
; specified | |
; The hints provided in the question suggest two different means to keep track of the worm - a physical and logical | |
; location and suggests that one of these may be easier than the other in terms of changing the size of the worm | |
; and the game board. They both seem fairly similar to me in this regard, bu I have chosen a physical representation | |
; as it seems much easier in terms of drawing. The logical position would need to be converted back to a physical | |
; position at the time of drawing. | |
(define WORM-SIZE 10) | |
(define WORM-MOVE WORM-SIZE) | |
(define WIDTH 800) ; width of the game | |
(define HEIGHT 500) ; height of the game | |
; this struct will hold the current position of the struct. I imagine later on it will | |
; end up holding a list of the tail of the worm | |
(define-struct worm(x-pos y-pos)) | |
; a struct to hold the direction the worm currently moving in. | |
(define-struct direction(x y)) | |
; To save repeating these directions in tests and code, we'll define them here | |
(define DOWN (make-direction 0 1)) | |
(define UP (make-direction 0 -1)) | |
(define RIGHT (make-direction 1 0)) | |
(define LEFT (make-direction -1 0)) | |
; this is a key struct - this is the our world and gets passed around to all the functions so | |
; that they can take appropriate action and modify the world as needed. Currently it just holds the | |
; worm position and direction, but later it will hold the positions of the worm food. | |
(define-struct world(worm direction)) | |
; This functions draws a worm in its current location on the screen | |
(define (draw-worm background worm) | |
(place-image (circle WORM-SIZE "solid" "red") (worm-x-pos worm) (worm-y-pos worm) background)) | |
; This draws the current world. Currently it is just drawing the sake but this will probably be | |
; extended to draw other things. | |
(define (show world) | |
(draw-worm (empty-scene WIDTH HEIGHT) (world-worm world)) ) | |
; this function is called on each clock tick and moves the worm in the last direction that was pressed. | |
; this takes in a world and constructs a new world with the worm moved along the current | |
; direction. The direction doesn't need to change so isn't changed. | |
(define (move-worm world) | |
(make-world | |
(make-worm (+ (worm-x-pos (world-worm world)) (* WORM-MOVE (direction-x (world-direction world)))) | |
(+ (worm-y-pos (world-worm world)) (* WORM-MOVE (direction-y (world-direction world))))) | |
(world-direction world) | |
)) | |
; handle keyboard events. this is a very simple function that just calls the change direction | |
; function with a new direction vector. This returns the new world state as returned by change-direction | |
(define (handle-key-events ws ke) | |
(cond | |
[(string=? "left" ke) (change-direction ws LEFT)] | |
[(string=? "right" ke) (change-direction ws RIGHT)] | |
[(string=? "up" ke) (change-direction ws UP )] | |
[(string=? "down" ke) (change-direction ws DOWN)] | |
[else ws] | |
)) | |
; create a new world with the direction the worm is travelling in changed. | |
; this function doesn't do much - it just creates a new world struct and returns it. | |
; this could have been done in the handle-key-events function, but having a named function | |
; for it makes things clearer. | |
(define (change-direction world direction) | |
(make-world (world-worm world) direction)) | |
; This is the big bang function that drives the game. I had trouble locating concise directions for | |
; how this function should work. The first argument is the main argument - it is a 'world' object, or a | |
; data structure containg the dynamic (changing) aspects of the game. This is passed into each of the following | |
; callback functions (along with possibly other arguments) and is expected to be returned (possibly modified) | |
; from each of these functions. As this is a functional program, we are not changing the world, but rather | |
; creating an entirely new representation of the world each time. This seems very inefficient to me. | |
; | |
; Within our big-bang function, we creation the initial representation of the world. This is a worm in | |
; the center of the screen, moving to the right. | |
; We supply a function 'show' that will draw our world as it currently stands, a function handle-key-events | |
; that will change the direction the worm is travelling in, and on each 'tick' we move the worm one unit | |
; in the current direction. | |
(define (worm-main rate) | |
(big-bang (make-world (make-worm (/ WIDTH 2) (/ HEIGHT 2)) | |
(make-direction 1 0)) | |
(to-draw show) | |
(on-key handle-key-events) | |
(on-tick move-worm rate) )) | |
; start the game off! 10 movements a second seems to provide a reasonable speed for the current worm/world size | |
(worm-main 0.1) | |
; ### TESTS ### | |
; Test our worm draws as we expect it. | |
(check-expect (draw-worm (empty-scene 100 100) (make-worm 50 50)) | |
(place-image (circle WORM-SIZE "solid" "red") 50 50 (empty-scene 100 100))) | |
; Test our worm moves in the direction we expect | |
(check-expect (move-worm (make-world (make-worm 50 50) DOWN)) | |
(make-world (make-worm 50 60) DOWN)) | |
(check-expect (move-worm (make-world (make-worm 50 50) UP)) | |
(make-world (make-worm 50 40) UP)) | |
(check-expect (move-worm (make-world (make-worm 50 50) LEFT)) | |
(make-world (make-worm 40 50) LEFT)) | |
(check-expect (move-worm (make-world (make-worm 50 50) RIGHT)) | |
(make-world (make-worm 60 50) RIGHT)) | |
; Test our change-direction function changes the direction, but doesn't impact the postion | |
(check-expect (change-direction (make-world (make-worm 50 50) DOWN) UP) | |
(make-world (make-worm 50 50) UP)) | |
(check-expect (change-direction (make-world (make-worm 50 50) DOWN) RIGHT) | |
(make-world (make-worm 50 50) RIGHT)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment