Homework 5
Due Date: Friday February 26, 9pm
Purpose To design simple list processing functions; practice using hierarchical data
Expectations
As with HW4, this and all future homeworks will be pair assignments. Remember that working in pairs means that you both work on the problems together, ideally by one person developing the solution, while the other person observes and comments. Working in pairs does not mean to split up the work between the two of you.
As with all assignments, you must upload one .rkt file in the language specified at the top of the assignment to the Handin Server. Using the wrong language will invalidate your submission and result in a score of 0, so please be careful.
Unless otherwise stated, all data and functions you design must be designed according to the data and function design recipes, resp., following all four steps in each case.
Your code MUST conform to the guidelines outlined in the style guide on the course website. The style guide will be updated as the semester progresses so please remember to read it before submitting each assignment.
-----------------------------------------------------------------------------
This assignment primarily revolves around upgrading the multi-moon eclipse program we developed in class a week ago. At that time, we had just learned about self-referential data types, and applied the concept to creating a simulation for a planet that had multiple moons (we were aiming for Saturn, which has 82!). Using self-referential structures, we were able to accomodate an unlimited number of moons for a system, unlimited number of passengers on a flight, etc.. However, each data type definition was designed from scratch, with custom define-structs, custom selectors, unique base cases, and so on.
We subsequently learned about a common infrastructure in BSL–lists– that allowed us to generalize the handling of these types of collections using a uniform representation: a chain of cons cells terminating in a special "empty list", '(). We no longer had custom constructors and selectors, like make-system and system-moon, instead using common functions like cons and first. We also streamlined our data type definitions in the process.
Our goal for the set of exercises in this homework is to take the make-system-based implementation of the multi-moon eclipse program that we developed in class, which we provide below, and adapt it one part at a time to use BSL lists. Each phase of the upgrade is framed as an individual exercise.
Here is the "legacy" code:
; Create an animation of an eclipse with an arbitrary ; number of moons (to be supplied as initial world state). (require 2htdp/image) (require 2htdp/universe) (define SIZE 500) (define RADIUS (/ SIZE 10)) (define MIDDLE (/ SIZE 2)) (define SUN (circle RADIUS "solid" "yellow")) (define MOON (circle RADIUS "solid" "gray")) (define SKY (square SIZE "solid" "blue")) (define SCENE (place-image SUN MIDDLE MIDDLE SKY)) ; ; Exercise 1: Add design for Moon data type here ; ; ; Exercise 2: upgrade design for System data type here ; (define-struct system [moon system]) ; A System is one of: ; - 0 ; - (make-system Number System) ; the moons we are simulating: ; - zero moons ; - the x-coordinate of the first moon, and the rest of the moons (define system-0 0) (define system-1 (make-system 0 system-0)) (define system-2 (make-system 100 system-1)) (define (system-templ s) (... (cond [(number? s) ...] [(system? s) (... (system-moon s) ... (system-templ (system-system s)) ...)]))) ; eclipse : System -> System ; an eclipse of arbitrarily many moons (define (eclipse initial-s) (big-bang initial-s [to-draw draw-eclipse] [on-tick move-eclipse] [on-mouse add-moon])) ; ; Exercise 3: upgrade design for draw-eclipse here ; ; draw-eclipse : System -> Image ; all moons as an image in the SCENE (check-expect (draw-eclipse system-0) SCENE) (check-expect (draw-eclipse system-2) (place-image MOON 100 MIDDLE (place-image MOON 0 MIDDLE SCENE))) (define (draw-eclipse s) (cond [(number? s) SCENE] [(system? s) (place-image MOON (system-moon s) MIDDLE (draw-eclipse (system-system s)))])) ; ; Exercise 4: upgrade design for move-eclipse here ; ; move-eclipse : System -> System ; all moons after moving by 1 pixel each (check-expect (move-eclipse system-0) system-0) (check-expect (move-eclipse system-2) (make-system 101 (make-system 1 0))) (define (move-eclipse s) (cond [(number? s) s] [(system? s) (make-system (add1 (system-moon s)) (move-eclipse (system-system s)))])) ; ; Exercise 5: upgrade design for add-moon here ; Don't forget to modify big-bang call to try it out ; ; add-moon : System Number Number MouseEvent -> System ; add a moon to the system whenever "button-down" is clicked (check-expect (add-moon system-0 0 0 "button-down") (make-system 0 0)) (check-expect (add-moon system-2 0 0 "button-down") (make-system 100 (make-system 0 (make-system 0 0)))) (check-expect (add-moon system-2 0 0 "button-up") system-2) (define (add-moon s x y me) (if (string=? me "button-down") (cond [(number? s) (make-system 0 0)] [(system? s) (make-system (system-moon s) (add-moon (system-system s) x y me))]) s)) ; ; Exercise 6: add code for move-eclipse/v2 here ; ; ; Exercise 7: add code for the stop-when handler here ;
You should cut-and-paste this code into DrRacket as a starting point for developing your code. Please keep the functions in the order they are given in, to make it easier for the graders to find the required components. You will need to write several helper functions in the process: going along with our top-down style, insert these functions immediately below the function you call them from.
Since you will be starting from code we have provided, which adheres to the design recipes, it should save you some work. However, as you adapt the design, you are responsible for making sure all parts are kept up-to-date and correct. Make sure you update ALL of both data and function design recipe elements: for example, your upgrades might change the examples for a data type, or the purpose statement for a function. You will be graded on the correctness of all parts, not just the functionality of the code.
Here we go!
Exercise 1 Define a new data type Moon that holds both an x position as well as a velocity component; the latter is a signed numerical value so that we can model moons moving in either direction, at any speed.
Exercise 2 Adapt the data type definition for System so that it uses our new lists, i.e., it uses '() and cons cells to build the list of Moons. (Note: you don’t need a define-struct here any more.)
Exercise 3 Adapt the draw-eclipse function to use your new data types. Make sure you update your tests, too.
Exercise 4 Adapt the move-eclipse function to use your new data types. You must also now use each moon’s velocity to decide how much to move the moon, and in what direction. (The old version assumed a fixed "1-pixel-to-the-right/tick" motion.) You must call out to a helper function to move each moon.
Exercise 5 Redesign the add-moon function to convert from an on-mouse to an on-key event handler. It should handle the following 4 keys:
"r" (for "right"): adds a moon with center at the left edge with a velocity of 1 (positive velocity indicating moving left-to-right)
"R" (for "fast-right"): adds a moon with center at the left edge with a velocity of 2 (again, moving left-to-right)
"l" (for "left"): adds a moon with center at the right edge with a velocity of -1 (i.e., moving right-to-left)
"L" (for "fast-left"): adds a moon with center at the right edge with a velocity of -2 (i.e., moving right-to-left)
The function should ignore any other keys. Note that hitting "shift-R" or "shift-L" will create two events, since pressing the shift key creates a "shift" event by itself; however, ignoring this will work fine, because the key event for the following letter will be correctly capitalized.
Don’t forget to update the big-bang call, changing the on-mouse clause to an on-key clause if you want to try out your changes.
Exercise 6 Adapt the move-eclipse function so that it removes any moons that have completely moved off the screen. Notice that this means you can’t just test if a moon’s x position is beyond the screen edge, since the position marks the center of the moon, so half the moon will still be visible when the center goes beyond the edge; you must take the radius into account. You must call out to a helper function to do the checking of the moon’s position. (In Exercise 4, you should have already created a helper function for moving a single moon; leave that as-is.) You are allowed to base your tests on the moon’s original position (as opposed to the new moved position)– this should make your code simpler.
HINT: instead of thinking of this task as "remove the bad moons", you should think of it as: "keep the good".
Exercise 7 Add a stop-when handler that terminates big-bang when the centers of all of the moons have moved beyond the edges of the window. Note: this is different from the test in move-eclipse, which tested for moons where the entire circle has moved out of the window. This means that when the stop-when condition is triggered, there should still be one or more moons left in the final world state (unless you started with an empty system, of course).
As with Exercise 6, the test should be put into a separate helper function.