RU beehive logo promo banner for Computing & Info Sciences
ITEC 380
2024spring
ibarland

list processing
Snake (gridless) cont.

Due Mar.05 (Tue) in class Mar.12 23:59. I strongly recommend completing at least Part A by Friday morning, to allow for coming to office hours before break, to allow any uncertainties to be clarified in office hours before spring break.

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 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)))
  3. Write insert-at-end : (-> list? any? list?), which inserts an item so that it is the last item in the list. This will be a perfect function to use later, for our list-of-segments. 2

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 may use any/all of the hw04-soln, to be posted by Mar.03 (Sun).
  1. Write head-collide-fruit?, segment-collide-fruit?, (and perhaps wall-collide-fruit?). Yeah, these are a few functions that coulda/shoulda been included on ../structs.html.
    inheritance: Okay, I usually don't mention struct-inheritance, but since for Snake (gridless) objects are unusually uniform (IF everything is the same width & height hitbox), you can see how by reading comments inside student-extras.rkt for examples of struct-inheritance. If you use inheritance, then perhaps a one or two -collide- functions can suffice for all of hw04/hw05.
  2. Datatype definition:
    1. Give at least 4 examples of the type (listof segment). Name them, to more easily use them as test-inputs for functions like glide-segments and draw-segments below.
    2. Write the template for any function which handles a listof segment.
  3. Collisions:
    1. Write head-collide-segments? : (-> head? (listof segment) boolean?), which determines whether a single head collides with any segment in a list-of-segments.
      (Of course, you should call hw04's head-collide-segment? as a helper.) This is a bit like count-bigs — or even more like lecture note's contains?.
    2. If supporting walls, write head-collide-walls? similarly.
  4. Write segments-collide-fruit? (and, perhaps, walls-collide-fruit?). These will be helpful when teleporting fruits, below.
  5. Drawing:
    1. Write draw-segments : (listof segment) image? image?), which takes in any image, and returns that image with all segments in the drawn onto it.
    2. If supporting walls, write draw-walls similarly.
  6. Worlds:
    1. Define a world structure which contains one head, a list of segments, and (perhaps) a list of walls.

      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 teleport-fruit : (-> world world). The important part of teleporting the fruit is that it doesn't end up
      inside
      the snake (or a wall).
      to be random, or not to be?: The teleport-destination doesn't have to be a random; e.g. it could just do a constant offset from the current location, or even depend on things like the head's current location. This makes testing predictable. If you do choose to use random, your test cases will need to use check-random.
    5. Optional: If you have/want fruits that age (and teleport after sitting in the same place long enough), you might also write/update age-fruit. What does the signature for this reviesed age-fruit need to be?
    6. Write the top-level function glide-world : (-> world? world?) which returns a new world one tick later. This entails gliding the head, all segments, and the fruit.
    7. Write the function update-segments : head (listof segment) -> (listof segment) which may (or may not) add one new segment. Note that this function depends on the head. To think about: Which template will this function follow — head, (listof segment), or a combination/cross-product of those two?
    8. 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 fruit, and otherwise defers to head-handle-key. Your test cases will largely crib from that function.
    9. Finally, write a function game-over? : (-> world? boolean?), which returns whether the game is over (that is, if the head is colliding with a segment, or (optionally) there are no more segments).

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 Slightly higher level: you could write push-and-dequeue : (-> list? any? list?), for adding a new segment and removing (and throwing away) the oldest segment. Since you can decide which end of the linked-list holds the new elements, you can decide if this means (a) doing an insert-last (pretty-easy) and a remove-first (trivial/built-in), or if it means doing (b) an insert-at-front (trivial/built-in) and a remove-last (a bit harder — uses the template for processing a non-empty list). But even if you opt for doing this higher-level abstraction, insert-at-end and/or remove-last are helpful functions by themselves.      

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.