[Index of Problem Sets]

Problem Set 05—Notes and link to solution

Problem set 5 is the most difficult problem set so far, and the problem set that has the most code in it all term.

To solve problem set 5 you really had to work systematically using HtDW, HtDF, and all the helper rules we learned this week. It was a challenging problem set, and some people decided to use the "one problem set grade dropped rule" on this one. Nonetheless, if you do use what you have learned it is possible to do well on it, and many people do.

The following notes are intended to illustrate some of how we intended problem set 5 to be solved. It covers what appear to have been some of the most difficult points - it is not a complete walk through of the solution. Ask your TA or instructor in office hours if you want more information.

First thing is that the way to start was at the beginning of HtDW and go through the process focusing on differences between the problem set 4 goal and the problem set 5 goal. One way to do this was actually to print out the starter file on single sided paper so you can lay it all out in front of you. Another was to mark up the starter file, perhaps using !!! and ALL CAPS to take notes about what needs to happen.

The first question is whether there is new constant information? Yes the starter file has these constants:

(define PADDLE-WIDTH 60)
(define PADDLE-THICKNESS 10)
(define PADDLE (rectangle PADDLE-WIDTH PADDLE-THICKNESS "solid" "white"))
(define PADDLE-CTR-Y (- HEIGHT 40))
(define PADDLE-MOVE-PER-KEY 10)
    

It was definitely a good idea at this point to draw a picture of the screen with a paddle of about the right size and y position. Maybe in the margin next to these constants. This is important to be sure you really understand what the constants mean.

Then we ask whether there is new changing information. We still have an abitrary number of balls with their x, y, dx, and dy. But now there is also a moving paddle with its changing x position. The starter file has this data definition in it:

(define-struct game (balls paddle))
;; Game is (make-game ListOfBall Number)
;; interp. the current state of a game, with all the balls in play,
;;         as well as the x-position of the paddle in screen coordinates

... examples, template rules, and template are left out here ...
    

This is a major point in the analysis. HtDW tells us that the type that represents all the changing information plays a key role in the design. Every place the world program template has WS we now know will be Game. This is a good time to go to the main function and make a note that says it will now have a signature of Game -> Game, and that all of its handlers need to change to consume and produce Game -- the fact that Game includes a list of balls means that what we will probably do is make a new function for each handler, the new function will consume and produce Game, and the new function will probably call the old function as part of it's work.

A next good thing to do would be to highlight key points in the problem description that you will need to complete the problem set, including noting the new helper touch-paddle?

After doing that you will proceed to the main function. In the starter it looks like this:

(@htdf main)
(@signature ListOfBall -> ListOfBall)
;; start the game, call with (main LOB1)
;; 

(@template htdw-main)

(define (main b)
  (big-bang b
    (on-draw   render-balls)   ;ListOfBall -> Image<
    (on-tick   next-balls)     ;ListOfBall -> ListOfBall
    (on-key    handle-key)     ;ListOfBall KeyEvent -> ListOfBall
    (on-mouse  handle-mouse))) ;ListOfBall MouseEvent Integer Integer 
;;                             ;  -> ListOfBall
    

Working on it a bit we end up with:

(@htdf main)
(@signature Game -> Game)
;; start the game, call with (main G0)
;; 

(@template htdw-main)

(define (main g)
  (big-bang g
    (on-draw   render-game)    ;Game -> Image  !!! need to design this
    (on-tick   next-game)      ;Game -> Game   !!! need to design this
    (on-key    handle-key)     ;Game KeyEvent -> Game  !!! update this
    (on-mouse  handle-mouse))) ;Game MouseEvent Integer Integer
;;                             ;  -> Game  !!! update this
    

Note that at this point we've made a decision to make two new render-game and next-game functions. We have decided to instead update handle-key and mouse-key. That wasn't essential, you could have decided to redesign them too. But they are templated on KeyEvent and MouseEvent, and they will still be templated on KeyEvent and MouseEvent, so it seems better to update them rather than write new ones.

So at this point we might go and put a !!! next to both handle-key and handle-mouse to remind us we need to work on them later, and also do wish list entries for render-game and next-game.

To keep this note from being too long we'll pick up a bit of speed here. The starter gave us a big bit of direction on next-game, so we relatively quickly end up with:

(@htdf next-game)
(@signature Game -> Game)
;; advance all the balls; paddle is unchanged
(check-expect (next-game G0) G0)
(check-expect (next-game
               (make-game (cons (make-ball (+ LEF 1) 100 -1 2)
                                (cons (make-ball 123
                                                 PADDLE-CTR-Y
                                                 3
                                                 -2)
                                      (cons (make-ball 30 40 4 4) empty)))
                          123))
              (make-game (cons (make-ball (+ LEF 1) 100 1 2)
                               (cons (make-ball 34 44 4 4) empty))
                         123))

(@template fn-composition)

(define (next-game g)
  (game-with-caught-balls (game-with-next-balls g)))
    

As well as these two wish list entries:

(@htdf game-with-next-balls)
(@signature Game -> Game)
;; !!!
;; produce a new game which has each of its balls moved by one clock tick

(define (game-with-next-balls g) g)

(@htdf game-with-caught-balls)
(@signature Game -> Game)
;; !!!
;; produces a new game where any balls that were touching the paddle are removed

(define (game-with-caught-balls g) g)
    

Let's look for a minute at the templating stage for game-with-caught-balls. (It would be the same for game-with-next-balls).

The template tag and template are:

(@template Game)

(define (game-with-caught-balls g)
  (... (game-balls g)
       (game-paddle g)))
    

Now we know this function has to produce a game, so we might do this:

(define (game-with-caught-balls g)
  (make-game  ...
              (game-balls g)
              (game-paddle g)))
    

Now we know that the job of this function is to get rid of any balls that the paddle is touching. But we don't know where those balls are in the list of game-balls. It might be the first ball in the list, or the last, or anywhere in between. That means the operate on arbitrary-sized data rules comes up, and we need a new function to remove just those balls in the list that are touching the paddle. So we write:

(define (game-with-caught-balls g)
  (make-game (catch-balls (game-balls g)
                          (game-paddle g))
             (game-paddle g)))
    

And this wish list entry:

(@htdf catch-balls)
(@signature ListOfBall Number -> ListOfBall)
;; produce a new list of balls that only includes balls not touching the paddle

(define (catch-balls lob p) lob)
    

With a some more work we come up with some examples, and then the complete function definition.

(@htdf catch-balls)
(@signature ListOfBall Number -> ListOfBall)
;; produce a new list of balls that only includes balls not touching the paddle
(check-expect (catch-balls empty (/ WIDTH 2)) empty)
(check-expect (catch-balls (cons (make-ball 3 4 -5 4)
                                 (cons (make-ball 50 PADDLE-CTR-Y 3 1)
                                       empty))
                           50)
              (cons (make-ball 3 4 -5 4) empty))

(@template ListOfBall)

(define (catch-balls lob p)
  (cond [(empty? lob) empty]
        [else
         (if (touch-paddle? (first lob) p)
             (catch-balls (rest lob) p)
             (cons (first lob)
                   (catch-balls (rest lob) p)))]))
    

Designing game-with-next-balls follows a very similar structure except that the next-balls helper already exists so it doesn't have to be designed.

Updating the handle-key and handle-mouse functions can be done by redoing the HtDF recipes for the functions with the new signatures, updating purpose, examples, and function as you go.

The solution for this problem set is: