Mini-Project 1 : Image composition and decomposition

In the first few days of class, you have received a crash-course introduction to programming in Racket, in particular with images. Furthermore, you also learned about algorithmic decomposition and its importance in computer programming. In this brief demonstration exercise, we’ll practice these techniques further by playing around with images.

External and internal correctness

In this course, we’re concerned about writing good code. What does that look like? Good programs have two qualities we’re looking after:

  • External correctness: Does the program behave correctly according to its specification?
  • Internal correctness: Is the program designed well?

External correctness is observable in the sense that we can run a program and determine that its behavior is correct. In contrast, internal correctness concerns the design of our program: Is it readable? Does it follow the design guidelines outlined in the exercise write-up and otherwise adhere to good coding conventions?

External correctness is often a given—we always want to write programs that do the right thing. However, we’ll find in this course that internal correctness is just as important! Computer programs are not just “consumed” by computers Other people will read and even modify our programs. In particular, you will find that in three months (or perhaps sooner), you will feel like “another person”, forgetting what you were thinking when you were designing the program. So it is important that we build habits that are conducive to writing readable code.

Playing around

As we may have discussed previously, programming is not a spectator sport (really, few things are in this world). You need to write programs to learn how to program. You often need to write programs to learn to think computationally. The labs and projects will be you primary vehicle for this sort of practice. This alone may be enough for some of you to master Racket programming. But for many people, you will need additional practice to truly master these concepts.

One way to do this is through “playing around.” What we mean by this is programming for the purposes of exploring a programming language or its libraries, rather than a specific end-product. This is how many of us approach learning a new language. We may have a few starting points in our back pockets, but as we write, we are less concerned about finishing the task at hand as we are about understanding the new environment. This exploration usually involves investigating and answering questions such as “How do I do X in this language?” or “How does feature X that I don’t understand compare to feature Y that I do understand?” or even “How does this language lead me to think differently about algorithm design?”

Because you are beginning programmers, your questions will likely be markedly simpler: “How can I even make a thing happen?” Hnd “how do I type a thing?”. But nevertheless, “playing around” lets you tackle some of those ideas. You might start with one our lab exercises that you developed with a peer as a starting point and then change the code in ways that are novel to you. Or you might start from scratch and try to reproduce something you have seen or written before. There is no right way to go about “play”. Its the attitude that’s important: one of exploration and asking and answering questions rather than focusing on the final product.

Turn-in details

For this mini project, you will create three files: spaceship.rkt, freestyle.rkt, and my-image-utils.rkt. The particular contents of each are detailed below. For additional details on turning on this assignment and interpreting your feedback from it, please consult the Gradescope page.

Part the first: Rainbow spaceship

For this first part of the demo, your goal is to define an image called rainbow-spaceship that looks like this:

A spaceship made of rainbow-colored rectangular strips.

Here are the details of the rainbow-spaceship image:

  • The spaceship composed of a collection of colored stripes, each of which are 100 pixels wide and 25 pixels tall.
  • As the spaceship grows in height from left to right, a new colored stripe is added in rainbow order from top to bottom. The order of colors of the rainbow are red, orange, yellow, green, blue, and violet.
  • The spaceship then shrinks in height past its center-point, losing a stripe from bottom-to-top order.

The “horizontal pyramid” effect is due to how the image library places sub-images with beside when they are different heights. Smaller images are automatically centered vertically relative to the taller images. For example the left-most red stripe is vertically centered relative to the red-orange two-stack of stripes next to it.

Make sure that the definition of rainbow-spaceship mimics its structure. Also pay special attention to remove redundancy from your code using define and, as appropriate, functions. We do not yet have the machinery to elegantly capture the growing, symmetric nature of the columns of the spaceship. However, note the relationship between the stripes of each successive column. How can you capture this relationship in code?

Please put your definition in the file spaceship.rkt

Part the second: Freestyle

Now that you’ve had a taste for manipulating images and using define and functions to reduce redundancy, you will now get the opportunity to play around making images of some complexity. As discussed, this is open-ended: I have no particular image for you to draw and only some requirements about how you design your program. Feel free to try the following starting points:

  • Take our image drawing / decomposition lab and improve on the pictures there.
  • Find an image on the Internet and do you best to replicate it using the limited image functions we’ve discussed in the course. Keep in mind that your final image will likely be impressionistic in nature!
  • Doodle! Start with a few shapes and try to build up interesting patterns from there.

To encourage you to practice algorithmic decomposition, your program must follow these design requirements:

  • Your image should contain no fewer than five smaller sub-images that you identify and codify in your program using the define command. These sub-images should be independent of each other (i.e., not defined in terms of each other), but can then be combined together.
  • Your image should employ at least one user-defined function that has at least one parameter that is employed in cutting down the code redundancy of your image in some way.
  • The names you define should be evocative of what the image is. It should be pithy, a few words at most, but at the same time descriptive. Racket programming conventions say that these names should be in all lowercase with dashes between words, e.g., names-like-this.
  • Your program should include a define that is the overall image, which you should call my-image.
  • Your program should include introductory documentation, as below. (All of your Racket files should include similar documentation.)

    # lang racket
    (require 2htdp/image)
    (require csc151)
    
    ; freestyle.rkt
    ;
    ; An amazing image of <....> I've created.
    ;
    ; CSC-151 Fall 2021
    ; Mini Project 1, Part 2
    ; Author: Stu Dent
    ; Date: 2021-09-08
    ; Acknowledgements: ...
    
    ; (...code below here...)
    ;
    (define my-image...)
    

Other than this, there are no minimum requirements regarding limits, code size, or complexity. Have fun with it!

Please put your definitions in the file freestyle.rkt.

Part three: Your own library functions

As you have likely noted, as your images and programs grow in complexity, it is helpful to write procedures (functions, subroutines) that encapsulate and parameterize a piece of code. For example, you may find that you regularly want to build “blocks” by overlaying an outline on a solid figure.

;;; (block size color) -> image?
;;;   size : non-negative-integer?
;;;   color : color?
;;; Create a square block of the specified size and color
(define block
  (lambda (size color)
    (overlay (square size 'outline 'black)
             (square size 'solid color))))

Write five (5) procedures that you think will be useful in building more complex images.

Create a list of five images, one build from each procedure, and call that list examples.

(define examples (list (block 20 "red") ...))

Once again, there are no minimum requirements regarding limits, code size, or complexity.

Please put our procedures and the examples list in the file my-image-utils.rkt

Part four: Generalizing images

Take the image you generated in part two and turn it into a procedure, generate-my-image, with at least two parameters (e.g., color and size) so that someone can easily make variants of that image.

Provide a call to your procedure that generates the same image you used in part 2. Call it my-image-alt.

(define my-image-alt (generate-my-image ...))

Provide a call to your procedure that generates a substantially different image. Call it my-other-image.

(define my-other-image (generate-my-image ...))

All three new new definitions (for generate-my-image, my-image-alt, and my-other-image) should go in the file freestyle.rkt.

A note on additional complexity

You are under no obligation to use additional functions or language features beyond what we have introduced in the first week or so of the class. However, You may feel limited by the functions we have discussed so far. If so, you are free to reference the documentation for the 2htdp/image library for the full set of functions available:

Note that this documentation may not be entirely comprehensible to you yet! That is fine. If you choose to explore this library in more detail, I recommend experimenting with these functions in the interactions pane and figure out how they work before throwing them into your code. Remember, if you adapt any code from this library’s documentation, you should cite that you did so in a comment in your code!

Q&A

Could you explain the difference between generate-my-image, my-image-alt, and my-other-image?

generate-my-image is a procedure. It should return an image that looks something like the image you created earlier.

my-image-alt should be the result of a call to generate-my-image. It demonstrates that generate-my-image can create something that looks identical to (or nearly identical to) the original image.

my-other-image should also be the result of a call to generate-my-image. It demonatrates that generate-my-image can create something that looks similar to, but different from, the original image.

Could you give an example?

Consider the “fancy house” from the reading on user-defined procedures. We might call that my-image.

We wrote a (fancy-house size color) procedure in the corresponding lab. That’s a model of the kind of thing we’d expect for generate-my-image. Depending on how we defined that procedure, we would write something like (define my-image-alt (fancy-house 50 "black")) to get another house that looks identical to my-image.

Of course, since you writing generate-my-image, you would use (define my-image-alt (generate-my-image 50 "black")) or something like that.

But the point of fancy-house (or generate-my-image) isn’t just that we can make an identical house (or other image). We should also be able to make variants. So we might write (define my-other-image (fancy-house 100 "yellow")) to show that we can make different size and diffent color houses.

Once again, you would write (define my-other-image (generate-my-image 100 "yellow")) or something like that.

Partial rubric

In grading these assignment, we will look for the following for each level. We may also identify other characteristics that move your work between levels.

You should read through the rubric and verify that your submission meets the rubric.

Redo or above

Submissions that lack any of these characteristics will get an I.

[ ] Includes the three specified files (correctly named).
[ ] Includes an appropriate header on each file that indicates the course, author, etc.
[ ] Code runs in DrRacket.

Meets expectations or above

Submissions that lack any of these characteristics will get an R or below.

[ ] In Part 1, creates the correct spaceship.
[ ] In Part 2, includes at least five sub-images.
[ ] In Part 2, includes at least one procedure.
[ ] In Part 2, the image is correctly named `my-image`.
[ ] In Part 3, includes five helper procedures.
[ ] In Part 3, each helper procedure has at least one parameter.
[ ] In Part 3, includes the required `examples` list, which has the required form.
[ ] In Part 4, the procedure has at least two parameters.
[ ] In Part 4, the procedure is correctly named `generate-my-image`.
[ ] In Part 4, there is a call to generate `my-image-alt`.
[ ] In Part 4, there is a call to generate `my-other-image`.

Exemplary / Exceeds expectations

Submissions that lack any of these characteristics will get an M or below.

[ ] In Part 1, code is concise and avoids repetition.
[ ] In Part 2, image is particularly interesting or creative.
[ ] In Part 3, one or more of the helper procedures is especially innovative.
[ ] In Part 4, `my-image-alt` appears the same as `my-image`.
[ ] In Part 4, `my-other-image` appears different from `my-image`.
[ ] In Part 4, decomposes the procedure.