(require 2htdp/image) (require 2htdp/universe) ;;; ======================================================= ;;; CMPU-101, Spring 2013 ;;; Assignment 7 ;;; ======================================================= (display "\n CS101 Assignment 7, Spring 2013") (display "\n Please write your name here\n\n") ; ; In this assignment, you will: ; ; - Use the on-key clause of big-bang to change direction of worm ; ; - Use the stop-when clause to sense a stopping condition (when worm ; hits wall) ; ; Add a final scene function as second argument to stop-when to draw ; message to player when game ends. ; (require 2htdp/image) (require 2htdp/universe) ; ; Design an interactive program that continually moves a one-segment ; worm and enables a player to control the movement of the worm with the ; four 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 distance either up, down, right, or left. ; ; Start by pressing the Run button. You should see a grid like the ; one you created for homework 6 (only smaller), with a single red ; circle moving from right to left. You will modify this simulation ; so that it consumes a compound struct instead of a number. ; ; ; ; ; ; ; ; ; ; ; ;; ; ; ; ; ; ; ;;; ;; ; ;;; ; ; ; ;; ; ; ;;; ; ;; ; ; ; ; ;;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ; ; ; ; ; ; ; ; ; ; ;; ; ; ; ; ;;;; ;;; ; ; ; ; ;;; ;; ;; ;; ;; ; ; As discussed in lecture 18, the state of the world will be a worm, ; composed of 4 numeric fields. These fields will represent the ; current x and y position of the worm and the change in the x and ; y coordinate on each clock tick (dx and dy). (define-struct wormpos (x y dx dy)) ; A wormpos is a (make-wormpos x y dx dy), where x and y are numbers ; representing the position of the worm on the x,y plane and the dx and ; dy are either DIAMETER, 0 , or -DIAMETER, representing the direction and ; the offset of movement. ; NOTE: AT ANY POINT IN THE SIMULATION, EXACTLY ONE OF THE dx AND dy FIELDS ; WILL BE 0 (SO NO MOVEMENT CAN OCCUR ON THE DIAGONAL). ;; WRITE CONTRACTS FOR CONSTRUCTOR AND ACCESSOR FUNCTIONS FOR WORMPOS STRUCT ;; HERE. ; ; ; ; ; ; ; ; ; ; ;; ; ;;; ; ; ;;; ;; ;;; ; ;;; ; ; ;; ; ;;; ; ; ; ; ; ; ; ;; ; ; ; ;; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ;; ;;; ; ;; ;;;; ; ; ; ; ; ; ; ; ; ; ; ; Problem 1: ; ; Write the contracts for the constructors and accessor fields of the ; wormpos struct in the place indicated above. ; ;; The state of the world is a wormpos struct: the current x,y coordinate for ;; the head of the worm, and the current direction dx, dy of the worm ; ; ; ; ;; ;; ; ; ; ; ;;; ;;; ; ;; ;;; ;;;; ;;; ; ;; ;;;; ;;; ; ; ; ; ; ;;; ; ; ; ;; ; ;;; ; ; ; ; ; ; ;; ; ;; ; ; ; ; ; ;; ; ; ; ; ; ; ; ;; ; ;; ; ; ; ;; ; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ; ; ; ; ;; ; ; ; ; ;;; ; ; ; ; ; ;; ; ; ;;; ;;; ; ;; ;;;; ;; ;; ;; ; ;; ;; ;;;; ; Constants (define RADIUS 10) ;\ (define DIAMETER (* RADIUS 2)) ; worm-related (define SEGMENT (circle RADIUS 'solid 'red)) ;/ (define WIDTH 400) ;\ (define HEIGHT 400) ; scene-related (define MT (empty-scene WIDTH HEIGHT)) ; (define COLOR 'black) ;/ (define RATE 1/4) ;; The initial state of the world is a worm whose head is positioned ;; at the middle of the scene and whose direction is to the right ;; (as indicated by the dx field value DIAMETER). (define INIT-WORM (make-wormpos (/ WIDTH 2) (/ HEIGHT 2) DIAMETER 0)) ;; Contract: (make-grid-hor-lines-v2) -> list of posn pairs ;; Header: (define make-grid-hor-lines-v1 (lambda () ...)) ;; Purpose: To make horizontal lines at every DIAMETER position in ;; grid (uses build-list for recursion). (define make-grid-hor-lines-v2 (lambda () (build-list (sub1 (/ WIDTH DIAMETER)) (lambda (c) (list (make-posn 0 (* (add1 c) DIAMETER)) (make-posn WIDTH (* (add1 c) DIAMETER))))))) ;; Contract: (make-grid-vert-lines-v2) -> list of posn pairs ;; Header: (define make-grid-vert-lines-v2 (lambda () ...)) ;; Purpose: To make vertical lines at every DIAMETER position in ;; grid (uses build-list). (define make-grid-ver-lines-v2 (lambda () (build-list (sub1 (/ HEIGHT DIAMETER)) (lambda (c) (list (make-posn (* (add1 c) DIAMETER) 0) (make-posn (* (add1 c) DIAMETER) HEIGHT)))))) ;; Contract: (draw-lines list-of-posn-pairs) -> image ;; Header: (define draw-lines (lambda (lopp) ...)) ;; Purpose: To draw lines between endpoints specified by each posn ;; pair in input list (define draw-lines (lambda (lopp) (cond [(empty? lopp) MT] [else (scene+line (draw-lines (rest lopp)) (posn-x (first (first lopp))) (posn-y (first (first lopp))) (posn-x (first (rest (first lopp)))) (posn-y (first (rest (first lopp)))) COLOR)]))) ;; Make the endpoints of all the lines to be in grid (define LOPS (append (make-grid-hor-lines-v2) (make-grid-ver-lines-v2))) ;; The game board: the equivalent of the empty-scene (define GRID (draw-lines LOPS)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;;; ; ;;;; ; ;;; ;;; ; ;; ;;;; ; ; ; ; ; ; ; ; ; ; ;; ; ;;; ; ; ; ; ;; ; ; ; ; ;; ; ; ; ;; ; ; ; ; ; ; ; ; ; ;;; ; ; ; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;;;; ;; ; ; ; ;;; ; ; ; ; ; ;; ; ;; ;; ;;; ; ; ;; ;; ;; ; ;; ;;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ;; ; ; Contract: (worm-main number) -> worm ; Header: (define worm-main (lambda (rate) ... )) ; Purpose: starts big-bang using the INIT-WORM constant for the ; initial world and a number for the clock rate. (define worm-main (lambda (w) (big-bang w (on-tick worm-tick RATE) (to-draw draw-worm)))) ;(on-key worm-ctrl) ;(stop-when at-wall? final-scene)))) ; ; ; ; ; ; ;;; ; ; ;; ;; ; ;; ; ; ; ; ; ;;; ;; ;;; ; ;;; ; ; ; ;; ; ;;; ; ; ; ; ; ; ; ; ;; ; ; ; ;; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ; ; ; ; ; ; ; ; ; ; ;; ; ; ;; ;; ;;; ; ;; ;;;;;;; ; ; ; ; ; ; ; ; ; ; ; ; Problem 2: ; ; Modify the draw-worm function below so that it consumes a wormpos ; instead of a number. Remember to change the contract, header, ; and purpose along with the function. ; ; IMPORTANT: Before you call worm-main with the on-draw clause uncommented, ; go to the bottom of this file to the section labeled "call main". ; Comment out the call "(worm-main DIAMETER)" and uncomment the call ; "(worm-main INIT-WORM)". ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ; ;;; ; ;; ;;; ;; ;;; ; ; ; ; ; ; ;;; ; ;; ; ;;; ;; ; ; ; ;; ; ;; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ; ;;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ; ; ; ; ; ; ; ; ;;; ; ; ; ; ;;; ; ; ; ;; ; ;;; ; ;; ;; ;; ;; ;; ;; ; ; ; Contract: (draw-worm number) -> image ; Header: (define draw-worm (lambda (w) ... )) ; Purpose: draws the dot in the grid (define draw-worm (lambda (w) (place-image SEGMENT w DIAMETER GRID))) ;; Uncomment the two lines below after you finish modifying the ;; draw-worm function. ;(printf "(draw-worm INIT-WORM) ~%") ;(draw-worm INIT-WORM) ; ; ; ; ; ; ; ; ;;;;;; ; ;; ; ; ; ; ; ;;; ;; ;;; ; ;;; ; ; ;; ; ;;; ; ; ; ; ; ;; ; ;; ; ; ; ;; ; ;; ; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ; ; ; ;; ;; ;;; ; ;; ;;;; ; ; ; ; ; ; ; ; ; ; Problem 3: ; ; Modify the worm-tick function below so that it consumes a wormpos ; instead of a number. ; ; The revised function should move the worm by adding the values ; in the dx and dy fields to the values in the x and y fields of ; the wormpos. The function should make a new worm to return as the ; current state of the world. Note that this function should not ; have to check if the worm is hitting the wall, since the function ; fed as input to stop-when will stop the simulation if this occurs. ; ; Remember to change the contract, header, and purpose along ; with the function. ; ; ; ; ; ; ; ; ; ; ;; ; ; ; ; ; ;;; ; ;; ;;;; ; ;;; ; ;; ; ; ; ;;; ; ; ; ; ; ; ;; ; ;; ; ;; ; ; ; ; ; ;; ; ; ; ;; ; ;;; ; ; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;;;; ;;; ; ; ; ;;; ; ;; ;; ;; ;;; ; ;; ; ; Contract: (worm-tick number) -> number ; Header: (define worm-tick (lambda (w) ... )) ; Purpose: moves the worm on the grid by adding the DIAMETER to ; the current state of the world (define worm-tick (lambda (w) (+ DIAMETER w))) ; ; ; ; ; ; ; ; ; ; ; ;; ; ; ; ; ;;; ;; ;;; ; ;;; ; ; ; ;; ; ;;; ; ; ; ; ; ; ; ; ;; ; ; ; ;; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ;;;;;;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ;; ;;; ; ;; ; ; ; ; ; ; ; ; ; ; ; Problem 4: ; ; Write the worm-ctrl function, an argument to the on-key ; clause of big-bang, below. This function should consume a ; wormpos and a string (a key event) and return a new wormpos ; (using make-wormpos). ; ; The worm-ctrl function should modify the state of the worm ; as follows: ; ; if key=? "up" or "down", change the dx field. ; ; if key=? "left" or "right", change the dy field. ; ; else return the state of the world unchanged. ; ; The contract, header, and purpose are given below to get you ; started. ; ; ; ; ; ; ; ; ; ; ; ; ;;; ; ;; ; ;; ;;; ; ; ; ; ; ;;; ; ; ;; ; ; ; ; ; ;; ; ;; ; ;; ; ;; ; ; ; ; ; ;; ; ;;; ;; ; ; ;; ; ; ; ; ; ; ; ; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;;; ; ;;; ; ;; ; ;; ;;; ;; ;; ; ; ; ; ; ; ; ; ; ; ;;; ; Contract: (worm-ctrl wormpos string) -> wormpos ; Header: (define worm-ctrl (lambda (w k) ... )) ; Purpose: changes direction of worm given direction of ; arrow key pressed ;; DEFINE THE WORM-CTRL FUNCTION HERE. ; ; ; ; ; ; ; ; ; ;;;; ; ;; ; ; ; ; ;;; ;; ;;; ; ;;; ;;; ; ;; ; ;;; ; ; ; ; ; ;; ; ;; ; ; ; ;; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ;; ;;; ; ;; ;;; ; ; ; ; ; ; ; ; ; ; ; ; Problem 5: ; ; Write the at-wall? function, an argument to the stop-when ; clause of big-bang, below. This function should consume a ; wormpos and return a boolean. ; ; The at-wall? function should return true if the wormpos ; is embedded in the left, right, top, or bottom of the ; scene. ; ; The contract, header, and purpose are given below to get ; you started. ; ; ; ; ; ;; ; ; ; ; ; ;;; ;;;; ;;; ; ;;; ; ; ; ; ;; ;;; ; ;; ; ; ; ; ; ;; ; ; ; ;;; ;; ; ; ; ;;; ; ; ; ; ;; ; ;; ; ; ; ;;; ; ; ;; ;; ; ; ;; ; ; ; ; ; ;;; ; ; ; ;; ; ; ;; ;; ; ; ; ; ; ; ; ; ; ;; ; ; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ;; ; ; ;; ; ; ; ; ; ;;; ;; ;;; ; ;; ; ; ; ;; ;;; ; ;; ; ; ; ; ; ; ; Contract: (at-wall? wormpos) -> boolean ; Header: (define at-wall? (lambda (w) ... )) ; Purpose: Returns true if worm is embedded in wall ;; DEFINE THE AT-WALL? FUNCTION HERE. ; ; ; ; ; ; ;;; ; ; ; ;; ; ;; ; ; ; ; ;;; ;; ;;; ; ;;; ; ;; ; ;; ; ;;; ; ; ; ; ; ;;; ; ; ;; ; ; ; ;; ; ;; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ;; ;;; ; ;; ;;; ; ; ; ; ; ; ; ; ; ; ; ; Problem 6: ; ; Write the final-scene function, an argument to the stop- ; when clause of big-bang, below. This function should consume ; a wormpos struct and return a scene image. ; ; The final-scene function should overlay the text "WORM ; HIT WALL" in 48 point and colored blue on a call to draw- ; worm. ; ; The contract, header, and purpose are given below to get ; you started. ; ; Contract: (final-scene wormpos) -> scene (image) ; Header: (define final-scene (lambda (w) ... )) ; Purpose: Returns text on last scene produced by draw-worm ;; DEFINE THE FINAL-SCENE FUNCTION HERE. ; ; ; ; ; ; ; ; ;;;;; ; ;; ; ; ; ; ; ;;; ;; ;;; ; ;;; ; ; ;; ; ;;; ; ; ; ; ; ; ; ;; ; ; ; ;; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ;; ;;; ; ;; ; ; ; ; ; ; ; ; ; ; ; Problem 7: ; ; When you have finished writing the worm-ctrl, at-wall?, ; and final-scene functions, go back to the big-bang invo- ; cation above and uncomment the on-key and stop-when clauses. ; ; Then comment out the first call to worm-main below, ; uncomment the second call to worm-main below, and press ; run. ; ; When this simulation runs, you should be able to control ; the movement of the SEGMENT by pressing the arrow keys. ; When the SEGMENT runs into a wall, the simulation should ; stop and display a message. ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;;; ;;; ; ; ; ;; ;; ;;; ; ; ;; ; ; ; ;; ; ; ; ;;; ; ; ; ;; ; ; ;;; ; ; ; ; ; ; ; ; ;; ;; ; ; ; ; ;; ; ; ; ; ; ; ; ;; ;; ; ; ; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ; ;;; ; ;;;;;; ; ; ; ;; ;;; ; ;;;; ; ; ; ;;; ;; ;; ;; ;; ; ; ;; ;; ;; ;; ; ;; (worm-main DIAMETER) ;(worm-main INIT-WORM)