Skip to content

Instantly share code, notes, and snippets.

@davesmylie
Created May 8, 2012 22:44
Show Gist options
  • Save davesmylie/2640081 to your computer and use it in GitHub Desktop.
Save davesmylie/2640081 to your computer and use it in GitHub Desktop.
exercise 170
;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