Homework 5
Last updated: Mon, 10 Mar 2025 14:48:20 -0400
Out: Tue Mar 04 2025, 11am EST
Due: Tue Mar 11 2025, 11am EST
Overview
In this assignment, you will practice using the The Design Recipe to write programs that compute with recursive data, e.g., lists!
This hw will be graded accordingly:
correctness (autograder) (8 pts)
design recipe (15 pts)
testing (15 pts)
style (8 pts)
README (2 pt)
Setup
Create a new repository for this assignment by going to the CS450 Spring 2025 GitHub Organization and clicking "New".
Note: The CS450 Spring 2025 GitHub Organization must be the owner of the repository. Do not create the repository in your own account.
On the "Create a new repository" screen:
Name the repository hw<X>-<LASTNAME>-<FIRSTNAME> where <X> is the current homework number.
For example, I would name my hw5 repository hw5-Chang-Stephen.
Mark the repository as Private.
Check "Add a README file".
Select the Racket template for the .gitignore.
Choose whatever you wish for the license.
When done click "Create repository".
Tasks
In this assignment we will implement a big-bang program similar to previous ones, except now there will be multiple blocks.
(Note that no solution to previous hws are needed to complete this assignment. In fact, since this assignment requires new data definitions, it is recommended that all students start from scratch, even those who completed previous ones. Trying to "adapt" a previous solution will likely be the more error-prone path, so do so at your own risk.)
Here is an online demo that approximates the behavior of the program (maybe coming soon!)
Reading
Read Chapters 8-10 of the Textbook (where reading means working through the examples and exercises interactively).
Review the The Design Recipe section of the course website for new elements of the design recipe that we have learned.
Pre-programming Notes
- All code must be written following the The Design Recipe. (Just submitting code is not sufficient.) In additional to the required receipe steps, some language features may only be used in the certain scenarios, as called for by The Design Recipe.
For example, set! and other "imperative" features are not allowed ever.
NEW: Each function is allowed one if expression, to "process" a piece of Boolean data, in addition to another kind of data, e.g., a WorldState. (Conditionals such as cond remain restricted to Data Definitions.)
NEW: Only list constructors (e.g., cons and list), accessors (e.g., first and rest), and predicates (e.g., empty?) are allowed in this assignment. Other list functions (e.g., map, filter, foldl, etc) are not allowed.
Signatures should use define/contract and the predicates defined in the Data Design Recipe step. If a function is defined with define/contract and it’s clear which data definitions its contract refers to, then comment signatures no longer need to be submitted with code. NEW: The listof contract constructor may be useful to use with functions that process list inputs.
For Examples and Tests, do not use check-expect from the Beginning Student Language (even though the textbook says to). Instead, use check-equal? or other testing forms from rackunit.
Examples for a function definition should be right after the define. But Tests should be put into the test-suite in tests.rkt. Try to think about corner cases and code coverage. Each function should have at minimum one Example, and "sufficient" Tests.
Tests should go in a tests.rkt file, as described in lecture and the hw5 starter code, and the rest of the code should go in a file named hw5.rkt.
The submitted program must be only a series of defines (both constants and function definitions are allowed). It should not run any code (e.g., it should not start the big-bang loop automatically!). Not following this will result in GradeScope errors and/or timeouts.
You may look at lecture code to help you but DO NOT SUBMIT ANY OF THIS CODE (even if you change the variable names, etc). You won’t receive any credit. Instead, you should write code for this homework from scratch using The Design Recipe.
NEW: One-line helper functions—
if the name and description clearly describe what it does (the course staff is the final arbiter of this)— do not need to be submitted with Examples and Tests, if they are covered by other tests. NOTE: This does not change the Design Recipe. It is only changing submission requirements. As usual, however, we will not be able to debug code that does not follow the design recipe, so omit these steps at your own risk. struct instances, e.g., for WorldState data, must be comparable with equal? and check-equal?, which means that they should be declared with the #:transparent keyword.
Programming
- Create a big-bang program that uses a 10\cdot\texttt{UNIT}\times 20\cdot\texttt{UNIT} pixel scene, whereThe big-bang expression should include (see below for details):
an on-tick clause that is given a "tick" function and a tick rate of 1 tick per second,
a to-draw clause that is given a "render" function.
a on-key clause that is given a "key handler" function.
NEW: a stop-when clause that is given two functions, a "game over" predicate, and a function that draws the last scene.
A J-block (in ROTATION1 state) should "fall" from the top of the scene to the bottom, at a rate of UNIT pixels per tick.
The block should initially be completely off the screen, but the "horizontal" part should be visible after one tick.
NEW: The block should stop "falling" and "lock" when it touches the bottom of the scene or another block on a "tick".
The initial "x" coordinate of the block center should be centered in the scene should be such that the block leftmost side is 3 UNITs away from the leftmost edge of the scene.
Once the "active" block is "locked", a new block should spawn in the initial position (just out of the top of hte scene).
If a user presses the "left" keyboard key, the block should move left by UNIT pixels (if it can), and same for "right" and "down". Once it is fully in the scene, the block should never go out of the scene (even partially) on any of the scene edges. The block should still be movable horizontally, even if it is at the bottom of the scene.
If a user presses the "down" keyboard key, the block should move down by UNIT pixels (if it can). Once it is fully in the scene, the block should never go out of the scene (even partially) on any of the scene edges. NOTE: A block should not "lock" due to pressing the down key, or any other key press.
This assignment does not need to handle "left" or "right" or "up" key presses. The block should not be able to move horizontally and should not be able to rotate.
The game should end if blocks pile up such that the top edge of the topmost block touches the top edge of the scene. The game end condition should be detected by passing a predicate to the stop-when big-bang clause (see below). When the game ends, a "GAME OVER" or some other message should be displayed so the user knows that the game is over. This last scene should also be computed by a function that is given to stop-when.
a Data Definition named Block that represents a block. The design details are your choice, so long as you define and provide the functions below.
a Data Definition named WorldState that represents the world state values of your big-bang program (remember that a world state should only include values that change—
constant values should be defined as constants). NEW: Your WorldState data definition should include a list as at least one of the components.
Note: You won’t be able to re-use your Data Definitions from previous assignments, so it is highly recommended that you start from scratch and think carefully about the different kinds of data the program will need. You likely will not be able to successfully complete this assignment without the design recipe. To give a hint, you may need to reason about all these different kinds of data, at different places in the program:
the rotation point of the block,
the "center" of the block,
the "top edge" of the block.
the "bottom edge" of the block.
Do not write any code until you at least understand what these mean. Ask questions (with examples) on Piazza if you do not. You do not want to, e.g., be writing code that expects a "center" but receives a "bottom edge". That is a sure-fire way to wind up in a marathon debugging session. Ideally, you should have well-named functions that "convert" between these different kinds of data when appropriate. Note that the various coordinates above may also change as the block is rotated so make sure to take that into account.a mk-Block function that takes a big-bang x and y coordinate representing a block rotation point, and returns a Block at the given coordinates in ROTATION1 state,
a Block? predicate that returns true when given a valid Block data value (if Block is compound data, then this should be a shallow check that does not check the fields),
a function Block->Image, with signature Block -> Image (Image is a built-in basic data definition from 2htdp/image where (image? i) evaluates to true if i is a valid Image), that is called by WorldState->Image,
a WorldState-active function that takes a WorldState and returns the "active" Block (the one that is still moving),
a WorldState-locked function that takes a WorldState and returns a list of Blocks that are locked and no longer moving,
a WorldState? predicate that returns true when given a value that is a valid WorldState (if WorldState is compound data, then the predicate should be a "shallow" check, meaning it should not deeply check the data structure fields, etc.),
a function next-WorldState, with signature WorldState -> WorldState, that is given to on-tick,
a function WorldState->Image, with signature WorldState -> Image (Image is a built-in basic data definition from 2htdp/image where (image? i) evaluates to true if i is a valid Image), that is given to to-draw,
a function Blocks-top, with signature Listof<Block> -> Real, that returns the y-coordinate of the topmost edge of the topmost block in the given list of blocks,
a function handle-key, with signature WorldState KeyEvent -> WorldState that is given to on-key,
a predicate game-over?, with signature WorldState -> Boolean, that is given to stop-when. This predicate should return true when the game should end, which is when blocks pile up such that the topmost edge of the topmost block touches the top of the scene.
a function render-last, with signature WorldState -> Image, that is given as the second argument to stop-when. It produces the last scene when the game is over. The function should call WorldState->Image but add a "GAME OVER" message to the user.
a constant INIT-BLOCK that is the initial Block. Remember that the block should initially be centered horizontally 3 UNITs away from the left edge of the scene, vertically sitting just above the top of the scene, and in RotationState ROTATION1.
a constant INIT-WORLDSTATE where (WorldState? INIT-WORLDSTATE) is true, (WorldState-active INIT-WORLDSTATE) is INIT-BLOCK, and (WorldState-locked INIT-WORLDSTATE) is empty.
a function main that takes no arguments and starts the big-bang interactive loop (main does not need Examples or Tests)
Before Submitting
Testing (and Autograders)
Before submitting, note:
Do not submit until all code has been thoroughly tested (by you), which means writing a "sufficient" number of Test cases.
A GradeScope "Autograder" may or may not be released before the due date but either way, an Autograder is not a software development/testing tool, so do not use it as one. Code must be tested independent of any Autograder and questions about Autograders will be ignored (e.g., posts asking "why is the Autograder giving an error?" are not allowed)
If you do submit before the deadline and get an Autograder error, this is bonus information that indicates the submitted code is not complete and/or not correct. But it’s up to you to figure out what "correct" means and how to fix to the program.
Of course, the course staff is here and eager to help, but cannot do so without context information. The best way to supply this information is to INCLUDE EXAMPLES WITH ALL QUESTIONS, along with what the "expected" result should be! The posted examples should be the minimal amount of code needed to communicate the problem. This will receive the clearest possible answer.
The Autograder test suite is subject to change. This means that the visible grade seen during submission is not the final grade.
Style
All code should follow proper Racket Style.
Also, the repository itself must follow proper style. Specifically, it must have appropriate commit messages. See How to Write a Git Commit Message if you are unsure how to write a commit message.
Files
A submission must have the following files in the repository root:
hw5.rkt: Contains the hw solution code.
All defines should use the name specified in the exercise (ask if you are unsure) and should be provided.
The easiest (but not always the most readable) way to ensure all necessary definitions are provided is to (initially) put as the second line in the file:
This automatically provides all definitions in the file (the first line should be #lang racket).
tests.rkt: This file should require hw5.rkt and define tests for it.
Specifically, it should define a rackunit test-suite named TESTS which contains "sufficient" rackunit Test cases (e.g., check-equal?, etc.) for each defined function.
README.md: Contains the required README information, including the GitHub repo url.
Submitting
When you are done, submit your work to Gradescope hw5. You must use the "GitHub" Submission Method and select your hw<X>-<LASTNAME>-<FIRSTNAME> repository.
Note that this is the only acceptable way to submit homework in this course. (Do not manually upload files and do not email files to the course staff. Homework submitted via any unapproved methods will not be graded.)