RU beehive logo promo banner for Computing & Info Sciences
ITEC 380
2023fall
ibarland

list processing
asteroids cont.

Part A: Problems 1,2,3,4,5a1-4 and 7,8 due Oct.03 (Tue) start-of-class on D2L-only (no hardcopy).
Part B: The remainder due Oct.06 (Fri) 23:59 05 (Thu) start-of-class (D2L, and hardcopy to next class).

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:

If you want to use let* (as mentioned in class), you certainly may.

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 ../../Lectures/the-design-recipe.html. 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? (listof 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 “thresh” and “nums”): if we call count-bigs with the particular inputs (count-bigs 3 (cons 10 (cons 2 (cons 5 empty)))), what is…
    • thresh =     
    • 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 : (-> (listof number?) (listof 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.

You will not need to turn in hardcopy of things before the dividing-line if they were in your hw04 solution or in the posted hw04-soln and student-extras.rkt2. Please include part A (problems 1,2) in your part B hardcopy.


  1. For each T in {asteroid,bullet}: so T is a type-variable: replace it with a particular type in the sentences below
    1. (0pts) Recall our data-definition for lists-of-T ((listof T)) from lecture: either '() representing the empty-list, or (cons [first T] [rest (listof T)]).
    2. Give at least 4 examples of the type (listof T). Name them, to more easily use them as test-inputs for functions like glide-Ts and draw-Ts below.
    3. Write the template for a list-of-asteroid processing function.
  2. Collision pt.1: Write ship-collide-asteroids? : (-> ship? (listof asteroid) boolean?), which determines whether a single ship collides with any asteroid in a list-of-asteroids.
    (Of course, you should call hw04's ship-collide-asteroid? as a helper.)
    name-change: Oops, in hw04 we actually called it ship-overlap-asteroid?, but I decided I prefer collide. You can use either collide or overlap, as you prefer. To rename an identifier in DrRacket, clock on Check Syntax, then right-click on the identifier.
    This is a bit like count-bigs — or even more like lecture notes'n contains?.
  3. Move functions:
    1. Write glide-asteroids, which return a list of all the glide'd asteroids of the input. (This is very similar to map-sqr above.)
    2. Write glide-bullets similarly. If you have bullets that time out, this function could also be a good place to filter them, keeping just the “still alive” bullets. You decide what can make bullets disappear, if they do at all — my hw04 struct had an “time-remaining” field, but you could also remove them if they reach the edge of the screen, or some other criterion. Alternately, you might have bullets live forever, with collisions being the only way of getting rid of them.
    Note that we'll do “higher-level” processing in functions below — e.g. worrying about collisions.
  4. (0pts) Write split-astr, which returns all the smaller chunks of an asteroid after being hit by a bullet. Don't worry about “too small” results; we'll handle that later. Here's a version that uses my astr-chunk from my hw04-soln and student-extras.rkt: and you are free to let it inspire you, or to copy it with citation
    ; return the fragments of `*` after being split apart.
    ; Note that we're using the rather-odd parameter name `*`,
    ; which also shadows the built-in multiplication function!
    ;
    (define/contract (split-astr *)
      (-> astr?   (listof astr?))
      (cons (astr-chunk * 0 3)
            (cons (astr-chunk * 1 3)
                  (cons (astr-chunk * 2 3)
                        '()))))
    
    (check-expect (split-astr astr1)
                  (cons (astr-chunk astr1 0 3)
                        (cons (astr-chunk astr1 1 3)
                              (cons (astr-chunk astr1 2 3)
                                    '()))))
    Alternatively, you can in-line this task into asteroids-collide-with-bullets below, which would obviate the need for append in that function.
  5. Now write filter-big-astrs : (-> (listof astr) (listof astr)), which keeps all the asteroids that aren't too small. Again, a later higher-level-logic function will call filter-big-astrs as well as split-astr.
  6. Collision pt.2: We'll need functions which, given all the asteroids and bullets, only keep the ones that aren't colliding with each other, and to split-astr those asteroids which are colliding. We'll do this in a few steps:
    1. Let's start with a simpler helper function bullet-collide-asteroids? : (-> bullet? (listof asteroid) boolean) which returns whether one single bullet is colliding with any of the asteroids.
    2. Now write bullets-remaining : (-> (listof bullet) (listof asteroid) (listof bullet), which returns all the bullets remaining after colliding with any of the provided asteroids. This function should not include any bullets that have “timed out” (however you handle that; my solution used a field time-remaining). Note that this task may feel like a nested-loop, but we're actually handling it by putting the inner-loop in the first function.
    3. Now we can write one of our top-level functions, asteroids-remaining : (-> (listof asteroids) (listof bullets) (listof asteroids)). It returns all the asteroids that exist after any bullet-collisions that trigger split-astr, and also filtering just the big-enough asteroids.

      This function is still straightforward, following the list-template as usual. As you hopefully guess, this function should call asteroid-collide-bullets?, split-astr, and filter-big-astrs. This function is the one time you can call the built-in append: you can append the result of (filtered) split-asteroids to the result of the recursive call. (We can't use cons in this situation, since we have an entire list to prepend to the front of the recursive call.)

  7. Worlds:
    1. Define a “world” structure which contains one ship, a list of asteroids, and a list of bullets.

      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 draw-world : (-> world? image?), which draws the world onto an otherwise-empty background.
      Note: This is a bit different than the other drawing functions -- it's the one that provides the initial background.
    4. Write the top-level function move-world : (-> world? world?) which returns a new world one tick later. This entails moving the ship, all asteroids, and all bullets, and handling all collisions between asteroids and bullets.
      Note: This function is straightforward after having written asteroids-remaining and bullets-remaining. Just be sure clear what list you pass to those helpers — the list of already-glided asteroids/bullets.
    5. Write the function world-handle-key : (-> world? key-event? world?) which returns a new world updated to handle the keypress. Will be pretty short — handle the command to fire a bullet, and otherwise defers to ship-handle-key. Your test cases will largely crib from that function.
    6. Finally, write a function game-over? : (-> world? boolean?), which returns whether the game is over (that is, if the ship is colliding with a asteroid, or (optionally) there are no more asteroids).

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.


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 Your hw05 may use any/all of the hw04-soln and student-extras.rkt; of course, cite any code you use like this (including a URL), just as would do for any purpose, hw or not.      

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.