Homework 6
Due Date: Friday October 23, deadline extended to 9pm
Purpose: To practice design of world programs.
Expectations
You and your partner must submit a single .rkt file containing your responses to all exercises via the Handin Server. We accept no email submissions.
You must use the language specified at the top of this page.
Your code must conform to the guidelines outlined in the style guide on the course website. The style guide will be updated as the semester progresses, so revisit it before submitting each assignment. (You can resubmit as many times as you like until the due date without penalty.)
Unless otherwise stated, every function and data definition that you design, including helper functions, must follow all steps of the design recipe.
Failure to comply with these expectations will result in deductions and possibly a 0 score.
Finger Exercises: HtDP/2e: 144, 145, 162, 163, 167, 168, 165, 170
Notes: to find the finger exercises, you’ll need to read the textbook and search for them by number. Also note the “2e” in the name: the exercise numbers changed substantially between the first and second editions. Make sure you’re reading the more recent edition. Finally, some of the finger exercises we recommend above rely on earlier exercises for context: you may need to scroll backwards in the textbook to figure out where the overall exercise starts.
Graded Exercises:
Tetris
Tetris is a classic game from the 1980’s. In the original version, a “tetra” is made up of four smaller square bricks and there are seven different kinds of tetra, but over the years there have been versions of Tetris that generalize to “pieces” in all sorts of shapes and sizes (with different numbers of bricks). In this and subsequent assignments, you will be designing increasingly complex iterations of Tetris, each one approaching the actual game.
A “piece” is made of some number of bricks and there are a variety of different kinds of pieces. A piece falls from just above the top of a grid (in the classic version, the grid is 10 bricks wide and 20 bricks tall) at a constant rate and as it falls the user can navigate the piece left and right or rotate the piece, although the movement and rotation is only allowed if all the bricks of the piece remain within the left and right edges of the grid. Once a piece lands on the base of the grid or on another piece, it is frozen in position and two things happen. First, if the board now has any full rows of bricks, those rows are deleted, and everything piled up above those rows is shifted down. Second, a new piece, of randomly selected shape, starts to fall from the ceiling. The game is over as soon as a piece lands but extends beyond the top of the grid.
The game is scored by counting the number of bricks that have been fit onto the grid and there may be bonus points when rows, or multiple rows, are cleared.
For the first iteration of the game that you do for this homework, we will only deal with pieces made of four bricks and the classic seven shapes of tetra. For subsequent assignments, we will add support for pieces with more or less than four bricks.
"O"
"I"
"L"
"J"
"T"
"Z"
"S"
the player’s ability to rotate the pieces and move them left and right —
but remember that the desired movement or rotation is not allowed if it results in any part of the piece being outside of the left and right edges of the grid the piece falling at a constant rate
generating a new piece when the last one has fallen below —
i.e., all parts of it have fallen below — the lower border of the grid. (In future assignments, we will have pieces land on the base of the grid and have more pieces pile up on top of them.)
Exercise 1 Design however many data definitions (and related interpretations) you need for this iteration of the game. For this first iteration, a World consists only of the one falling piece, which has at least one brick visible in the grid. A piece itself consists of a collection of bricks, but also has a center point around which the piece spins when rotated. Each brick has an x and y (grid) coordinate as well as a color.
(define-struct brick (x y color)) ; A Brick is a (make-brick Integer Integer Color) ; Interpretation: A (make-brick x-g y-g c) represents a square brick ; at position (x-g, y-g) in the grid, to be rendered in color c. Make sure you design your data definitions so it’s easy to accommodate pieces with more or less than four bricks in future assignments.
Preview For the next iteration of the game, your will enhance your world state to include the falling piece as well as the pile of bricks that have collected at the bottom of the grid.
Exercise 2 Define examples of your data definitions as well as their templates.
Exercise 3 Design functions to produce each of the seven shapes of pieces shown above at a given x and y grid position. Next, design a function to produce a new piece at the top of the grid at a random x coordinate (making sure that all parts of the newly spawned piece are within the left and right edges of the grid).
Exercise 4 Design your main function, including a signature and purpose for it. This will entail designing a wishlist of all of your big-bang handlers and all the helper functions they will need, then working through that wishlist to implement your program. You will also need to produce an initial world with a randomly chosen new piece.
We strongly recommend writing the wishlist explicitly in a comment near the top of your program, right after your data definitions:
as you conceive of new functions to be added, add them to the bottom of your wish list;
as you finish a function, put a star next to it; and
if you realize a function isn’t needed, don’t delete it from your wishlist, but instead leave a comment explaining why it’s no longer relevant.
This wishlist is both a good progress tracker for you, and a helpful outline of your program for your graders.You will at minimum need to design handlers to render the world state, to change the world state on each clock tick, and to handle keyboard commands.
This iteration of your game should support the following keyboard commands:
left arrow: Shift the current piece left.
right arrow: Shift the current piece right.
s: Rotate the current piece 90 degrees clockwise.
a: Rotate the current piece 90 degrees counterclockwise.
You will be asked to support additional keyboard commands in a future assignment.Rotations are a little tricky; here’s how you do it. Assuming the above data definition for Brick, this code will perform a counterclockwise rotation of a brick around a given point:
; brick-rotate-ccw : Posn Brick -> Brick ; Rotate the brick _b_ 90 degrees counterclockwise around the center _c_. (define (brick-rotate-ccw c b) (make-brick (+ (posn-x c) (- (posn-y c) (brick-y b))) (+ (posn-y c) (- (brick-x b) (posn-x c))) (brick-color b))) A clockwise rotation is just the same as three counterclockwise rotations.
Note that you must choose the rotation point for each piece carefully: if the piece’s bricks are all grid aligned before the rotation, you want them to be grid-aligned after the rotation, too. For example, if you rotate the long "I"-piece (four bricks in a horizontal straight line) around its exact center-point, it will wind up between two columns of the grid. If you set the rotation point as the center of either brick 2 or brick 3 in the piece, then the long piece will rotate a bit eccentrically, but bricks will always land on grid squares.
Parts involving random elements will be tricky to test. To test outputs that depend on random, it is ok to just test that the output has the properties you expect. For this you can use check-satisfied. When functions produce lists of random elements, you may also find check-member-of useful. You can also use check-random but it it somewhat brittle and may not be easy to use.
You will not receive 100% credit simply for having code that works. For full credit, your must have followed the Design Recipe and have well written code. Please re-read the style guide on the course webpage and follow style guidelines carefully, as we will be strict about deducting style points for naming, code organization, boolean simplification, etc. from now on.
You will be upgrading the game to full Tetris in future assignments. Effort expended in making sure that your code is clean and well-written will pay off when you have to extend it later —
it is extremely difficult to modify and extend code that is a snarled-up, confused pile of chaos. As always, we advise you that the Design Recipe will help you get your code written.