CSU211 Assignment 9 - Spring 2004

Overview

For this assignment you are to complete the interactive UFO game from HtDP+ and create a fully working program. For full credit you must complete the final version, as described in Section 2.5, although partial credit will be given if your program runs and is able to implement some part of the desired functionality. Here is a summary of the game, from a player's point of view:

There is a single UFO working its way toward the bottom of the canvas (representing the ground). If the UFO reaches the ground, the player loses. At the bottom of the canvas is a single anti-UFO platform (AUP), controlled by the player, that is capable of stopping the UFO in either of two ways:

If the UFO is prevented from reaching the ground, the player wins. The player can take one of three actions at every time step: These actions are selected by pressing the right arrow, left arrow, or up arrow keys, respectively.

Extra Credit: Create a version of the program that has multiple UFOs as well. The player loses if any one of the UFOs reaches the ground. (There are many variations on this idea: The embellished version I will demonstrate in class includes multiple UFOs, but only allows UFOs to be destroyed by shots. Also, the game does not end until all UFOs have either reached the ground or have been shot. In addition, throughout the game it keeps track of how many UFOs have been shot and how many have landed at the bottom, reporting these as text on the canvas as well as producing a corresponding message at the end of the game. If you do create an extra-credit variant of this game, feel free to incorporate some of these aspects as well as any other original ideas you can think of and can implement.)

Collaboration: For this assignment, you must not collaborate with anyone else but your partner. We will consider every other form of collaboration as cheating and will take action on it.

Objectives

There are two major objectives of this assignment:

Objective 1: To have you use all the knowledge you've acquired up to this point in the course to build a complete program. In the process, this will serve as a way for you to review and consolidate what you've been learning in this course. We hope you will also feel a sense of accomplishment at being able to build a complete program using all the design principles you've been practicing.

Objective 2: To have you distinguish among the various design recipes you've learned about so far by explicitly indicating with every function in your program just which design recipe it conforms to.

Because of the first objective, unlike the other assignments in this course, grading of this assignment will be based heavily on your ability to create a complete working program. When we grade this assignment, we will play the game you have created. If your program does not work, this will count heavily against you, so you should comment out all code that doesn't run properly so that at least the part that runs is able to do something without causing the program to crash.

To meet the second objective, in this assignment every function in your program should have an additional comment line, just below the purpose statement, indicating which of several possible design recipes it conforms to

Design Recipe Type

Here are the options for what to specify as the design recipe type associated with each function in your program:

Here are some examples:

;; distance-to-0 : Number Number -> Number
;; computes distance from (x,y) to the origin
;; domain knowledge
(define (distance-to-0 x y)
  (sqrt (+ (sqr x) (sqr y))))

;; dist-to-0 : Posn -> Number
;; computes distance from a-posn to the origin
;; structural, using a-posn
(define (dist-to-0 a-posn)
  (sqrt (+ (sqr (posn-x a-posn)) (sqr (posn-y a-posn)))))

;; contains? : (Listof Symbol) Symbol -> Boolean
;; checks whether a-sym is on a-los
;; structural, using a-los
(define (contains? a-los a-sym)
  (cond
    [(empty? a-los) false]
    [else (or (symbol=? (first a-los) a-sym)
              (contains? (rest a-los) a-sym))]))

;; contains2? : (Listof Symbol) Symbol -> Boolean
;; checks whether a-sym is on a-los
;; structural with loop, using a-los
(define (contains2? a-los a-sym)
  (ormap (lambda (s) (symbol=? s a-sym)) a-los))

You should re-read the sections on design recipes in HtDP to help you understand these distinctions.

The UFO Game Program

You should develop all the relevant functions and data definitions specified in the exercises of Sections 2.1-2.5 of HtDP+ necessary to construct the complete game program (with some slight modifications, as detailed below). You may also wish to incorporate solutions to relevant exercises from Section 2.6, using abstraction and loops, but this is optional. You have already developed solutions to many of these problems in previous assignments, so you should re-use as many of these as you can.

Also, you may find it especially helpful to develop the complete program incrementally, as is done in the HtDP+ description, first creating a running program that displays the UFO moving downward (Section 2.1), then creating another running program that only allows movement of an AUP (Section 2.2), then combining these into a complete game in which no shots can be fired but the AUP can intercept the UFO (Section 2.3). From this point you can either continue on to develop the program allowing exactly one shot (Section 2.4), or skip directly to the final version of the program allowing unlimited shots (Section 2.5).

Your main program and driver for the final version will be essentially what appears in Figure 7, but with one major modification, as detailed below.

Here are the specifications for the parts of the program that will differ from what appears in the HtDP+ description:

  1. Develop a function random-in-range. It accepts two integers, lower and upper, and generates a random integer uniformly in the closed interval [lower, upper]. (This is a slight generalization of the function random-range specified in Exercise 2.1.2.) For example, (random-in-range 5 8) should generate any of the four numbers 5, 6, 7, or 8. Use this function in move-ran-ufo or anywhere else in the program you need to generate a random pixel offset or random pixel location.
  2. Develop move-aup so that it consumes an AUP and a symbol. The symbol can be one of 'move-left, 'move-right, 'shoot, or 'none. It should behave essentially the same as the function specified in Exercise 2.2.3 except that the symbols 'move-left and 'move-right take the place of the KeyEvents 'left and 'right.
  3. Develop a new function update-shots. It should consume a list of shots, an AUP, and a symbol. The symbol can be one of 'move-left, 'move-right, 'shoot, or 'none. If the symbol is 'shoot, it adds a new shot from the AUP to the list of shots and moves all the shots on the list; if the symbol is anything else, it just moves all the shots.
  4. Develop a new function decode-user-input. It consumes a KeyEvent and produces a symbol, which can be 'move-left, 'move-right, 'shoot, or 'none, depending on which key the user pressed, if any.
  5. Replace the code for fly-until-down in Figure 7 by this modified version:
    ;; fly-until-down : UFO AUP (Listof Shot) -> Boolean
    ;; flies the UFO until it hits bottom or is shot
    ;; returns true iff the UFO lands on the AUP or is shot
    (define (fly-until-down ufo an-aup shots)
      (cond
        [(at-bottom? ufo) (and (draw-scene ufo an-aup shots)
                               (landed-on-aup? an-aup ufo))]
        [(hit-by-shot? shot ufo) (draw-scene ufo an-aup shots)]
        [else
         (and
          (draw-scene ufo an-aup shots)
          (sleep-for-a-while .05)
          (clear-scene ufo an-aup shots)
          {local [(define user-action (decode-user-input (get-key-event)))]
            (fly-until-down
             (move-ran-ufo ufo)
             (move-aup an-aup user-action)
             (update-shots shots an-aup user-action))})]))
    

Your file should include tests of all the functions in your program, with the exception of all functions that draw to the canvas and functions that respond to keyboard input. In particular, do not include (or at least comment out) tests for all functions with the names draw-... or clear-... as well as main and fly-until-down. However, the last two lines of your file should consist of the code that opens the canvas and the code that runs the program, but commented out. (We will uncomment these two lines when we test your program.)