RU beehive logo ITEC dept promo banner
ITEC 380
2020fall
ibarland

list processing
Asteroids II

Due Sep.23 (Wed) start of class: questions 1-3;
Sep.25 (Fri)Sep.27 (Sun) 23:59: the remainder (and if by original deadline, I'll add 10% of your score).
You need only submit your file hw05.rkt each time (no .zip, thanks).

For this homework:

(These restrictions will all be lifted after this homework.)

Reading: §6.6, and §10.1–10.3.1.
(Additional recommended, but not required, background reading: all of Chpt.6, and §10.3. Additional, non-required, challenge-reading: § 10.5.)

All problems are to be written in Racket. Do not call any of the following functions:

Your name and the assignment-number must be in a comment at the start of the file All functions/data must include the appropriate steps1 of the design recipe. In particular, test cases alone might be worth 40-50% of the credit for a function. Have enough test cases to cover different corner cases; often 2–3 can suffice.

  1. Write the function count-bigs : real, list-of-real → natnum, which takes in a threshold and a list of numbers, and returns how many of them are larger than the threshold. To help you out, here are some test cases; no further ones are required. (The data-definition for list-of-number has already been given in lecture, so you don't need to repeat steps 1-3 of the design recipe for list-of-number.)
    Remember: We can't re-assign to variables, in functional programming. So we won't have a counter which we increment, like you might in your imperative-programming class. Instead, be sure to follow the design recipe, and after copying the template, think about the inventory-with-values (assuming we call our parameters “threshold” and “nums”): if we call count-bigs with the particular inputs (count-bigs 3 (cons 10 (cons 2 (cons 5 empty)))), what is…
    • threshold =     
    • nums =                                                                                                   
    • (first nums) =       
    • (rest nums) =                                                                   
    • (count-bigs threshold (rest nums)) =     
    Fill in each blank with a particular number, or list-of-numbers. Then, ask yourself: Starting with those pieces of info, how do I assemble them to get my desired result of 2?

    You don't need to include the above in your answer — it's just to remind you of what you do, for the “inventory-with-values” step of the design-recipe, #6. If you get stuck on any of the problems below, make sure you didn't skip this step; it's the one that can really make things click!

  2. Write the racket function map-sqr : list-of-number → list-of-number, which squares each number in a list; do not call map . To help you out, here are some test cases; no further ones are required.
    (check-expect (map-sqr empty)  empty)
    (check-expect (map-sqr (cons 7 empty))  (cons 49 empty))
    (check-expect (map-sqr (cons 9 (cons 7 empty)))  (cons 81 (cons 49 empty)))

Copy your hw04(structs) racket file to one that we'll use for this one. Add a very noticeable dividing-line (say, 80 ;s) between old code and the new.

To save some typing, feel free to rename your asteroid-struct to be an astr. I'll do that in the instructions here, though you can use whichever name you prefer.

Your hw05 may use any/all of the hw04-soln; of course, cite any code you use like this (including a URL), just as would do for any purpose, hw or not.

  1. For List-of-astrs,
    1. Give the data-definition for list-of-astr but no define-structs are necessary, since using the built-in cons suffices.
    2. Give at least 4 example values of this type. Your last example should contain at least four astrs; you may use this as the astrs in your game's initial world.
    3. Write the template for a list-of-astr processing function.
    4. Make some examples of List-of-bullets.
      (You don't need to give a data-def'n or template (since it is so similar to those for List-of-astrs), though.)
  2. Moving lists-of-objects.
    1. Write move-astrs : list-of-astr → list-of-astr, which returns a list where each astr has moved.
      Note: Your test cases can call our already-tested move-astr, which in turn suggests your code canshould! call it as well.
      Note: The code for this will follow directly from the template. Its return value happens to be a list; we have seen that both in lecture's tee (triple-every-even), and map-sqr above.
    2. Write move-bullets, similarly.
  3. To determine collisions, we will be happy with the hack of using bounding boxes: We'll say that an oval and a triangle collide if the imaginary rectangles containing each of them overlap. That's expedient, because it's easy to tell if two rectangles overlap?.
    1. Write ship-collide-astr?, which determines whether a single ship overlaps with a single astr.

      Then use this as a helper to write ship-collide-astrs?, which determines whether a single ship overlaps with any astr in a list-of-astr.

    2. Similarly, write astr-collide-bullet?, and use it as a helper to write astr-collide-bullets?.
    3. Write explode-astr : astr → List-of-astr, which will be called an astr is hit by a bullet. It returns a list of exactly three new astrs that are one size smaller than the input astr, or (if the astr was already the smallest size) an empty list. You might simply2 make the velocity of each new astr just be a (fixed) offset to the original velocity. That is, if an astr with velocity (5,2) explodes, it might result in astrs with velocities (5+3,2+3), (5-5,2+1), and (5,2-6).
      Note: This function takes in an astr, not a list; be sure to use the correct template.
    4. Write astrs-remaining : List-of-astr, List-of-bullet → List-of-astr which returns all astrs after accounting for any bullet-collisions. You'll want to sometimes call explode-astr, and can use the provided function cons3-or-0.
    5. Write bullets-remaining, which takes in a list of bullets, and returns a list of those bullets that survive until the following tick. The exact details are left up to you, but you should probably have bullets die if either — or possible both — of the following happen: (a) the bullet has collided with some asteroid, and/or (b) the bullet dies of old-age. The former requires a helper bullet-collides-astrs?, and passing in a list-of-astrs; the latter requires adding a field to your bullet struct. (I believe the original Asteroids game did both.)
      Note: I placed this filter last, since if you don't get to it you simply have immortal bullets, which isn't the worst possible game.
    For each of the functions, have (of course) 2-3 test cases, incl. one with an empty-list. Two tests suffice for individual-collisions, since an already-tested helper overlap? is provided. For lists, three tests should suffice: lists of length zero, one, and “many”. And the tests for list-of-length-0 is trivial, and the test for list-of-length-1 is similar to your earlier tests.
  4. Drawing functions:
    1. Write function draw-astrs, which takes a list-of-items and a background-image, and return the background image with the items overlaid on it. When creating the expected-output for your test cases, feel free to include the calls to draw-astr (singular), etc. from the previous homework. Creating the expected-result for a test for a list-of-length-2 will help you understand what your code needs to do.
    2. Write draw-bullets similarly.
  5. Worlds:
    1. Define a “world” structure which contains one ship, a list of bullets, and a list of astrs

      As usual for our data-definitions, make examples of the data (at least two).

    2. Give a template for world-processing functions.
    3. Write the function world-handle-key : world, key-event → world which returns a new world updated to handle the keypress. (Should be easy — mostly defers to ship-handle-key, and your test cases will largely crib from that. However, this function will also handle firing.
    4. Write the function update-world : world → world which returns a new world one “tick” later. You need simply to move the ship; for the the bullets and astrs you'll want to only move the ones -remaining. A single test-case might suffice for this, since your expected-result can(should) involve calls to functions that have already passed their tests.
    5. Write the function game-over? : world → boolean. This will be a thin wrapper over ship-collides-astrsbullets.
  6. Update draw-world from the previous homework to have the signature world -> image. This is the function that will proide the very first background-image that gets passed to other draw- functions. You might consider using empty-scene.

All the above should have their tests, as well as signatures and (brief) purpose statements.

Only after all tests pass, add

(require 2htdp/universe)

(big-bang some-initial-world
[on-key  world-handle-key]
[on-tick update-world]
[to-draw draw-world]
[stop-when game-over?]
)
and you can play your game. Btw, if you want to add sounds (which you have license to use), you can call play-sound-then from student-extras.rkt.


Here is a function that you might find helpful, to combine the result of calling explode-astr with an existing list-of-astr. It's just a special-case of append, but for this homework that's one of our disallowed-functions.

; cons3-or-0 : (union   '()   (cons ANY (cons ANY (cons ANY '()))),
;              (list-of ANY)
;              -> (list-of ANY)
; Add the exactly-three-or-zero-elements of the first list  onto the front of the second.
;
; source: https://www.radford.edu/~itec380/2020fall-ibarland/Homeworks/lists/  (CC-BY)
;
(define (cons3-or-0 three-things-or-none others)
  (cond [(empty? three-things-or-none) others]
        [else ; it must be a list of exactly three items:
         (cons (first three-things-or-none)
               (cons (second three-things-or-none)
                     (cons (third three-things-or-none)
                            others)))]))
         ; Btw, `second` is shorthand for `(first (rest ..))`.




(check-expect (cons3-or-0 '() '())
'())

(check-expect (cons3-or-0 (cons 'hi (cons 'bye (cons 'aloha '())))
'())
(cons 'hi (cons 'bye (cons 'aloha '()))))

(check-expect (cons3-or-0 '()
(cons 100 (cons 101 '())))
(cons 100 (cons 101 '())))

(check-expect (cons3-or-0 (cons 'hi (cons 'bye (cons 'aloha '())))
(cons 100 (cons 101 '())))
(cons 'hi (cons 'bye (cons 'aloha (cons 100 (cons 101 '()))))))

1 Your final program doesn't need to include any "transitional" results from the template: For example, you don't need the stubbed-out version of a function from step 5. However, you should still have passed through this phase.      
2 If you want to have exploding astrs conserve momentum and angular momentum, that'd be extra neat!, but not at all required.      

logo for creative commons by-attribution license
This page licensed CC-BY 4.0 Ian Barland
Page last generated
Please mail any suggestions
(incl. typos, broken links)
to ibarlandradford.edu
Rendered by Racket.