Harvey Mudd College
Computer Science 60
Assignment 0, Due Tuesday, September 9, by 11:59 pm


Link to the CS submission site
Back to the top-level assignments page
Back to the top-level CS 60 page
CS 60 Students: Look-up your login information

The 3Rs: Racket, recursion, and run-time!

In this homework you will have the chance to familiarize yourself with the Racket programming language. Racket is considered a very "clean" language, with a minimal syntax: few punctuation and formatting rules. In fact some might argue it's too minimal! As a result, Racket is one of the best examples of a language whose focus is supporting computation itself, as opposed to intricate data structuring.  In the first problem of this assignment you'll work through Racket's "Quick start" tutorial; in the second problem, you'll implement some mathematical functions in Racket, remind yourself about recursion, and reflect on a few running times... .


Pair and individual problems

Some problems each week will be designated as individual; others as pair problems. You should complete the individual problems on your own, though you are - as always - welcome to get assistance in lots of ways, as the syllabus outlines. You're may solve pair problems individually if you'd like, but you're also welcome to submit a single file with a partner. Pair programming is very effective -- we encourage it! -- but it's important that you practice pair programming as the syllabus details: Because Racket may be entirely new to you, this week both problems may be done in a pair (but they don't have to be). In general, we will make it clear in each assignment which problems are which.


Submitting Your Work

For this assignment, you will write (and test!) your Racket code in two files:

Be sure to submit your files at the CS 60 submissions site. If you work with a partner, please make sure you each submit the file under your own submission-site account.

To log in to the submission site, use your login id, which you can look-up here. Use the default password at first. After you log in the first time, change it to something you'll remember.

You may submit your work multiple times -- only the file submitted latest will be graded, but all of them will be saved in case you or we need to access them for any reason. The submission site is a convenient way to access your latest copy of a HW assignment if you work on multiple computers.


Design, commenting, and formatting

Design and formatting account for roughly a quarter of the credit for each function or program you complete. Correctness, supported by careful testing of your code, accounts for the rest.

Design, here, means algorithm design, that is, how you break a problem down into smaller pieces and then compose those pieces into an overall solution. Large, convoluted functions are difficult to understand (and debug!). Use small, clear functions with lots of small helper functions, as necessary. Formatting includes coding style: clean and clear structure, meaningful variable and function names, ample use of spacing, and indenting that reflects code structure.

Here are specific formatting features the graders will look for:

As for commenting, in each assignment we ask you to include


Testing your code

Computation in the form of software is useful only to the extent that it works. But it only works (for sure) to the extent that it has been tested! Testing your own software thoroughly is important -- we use test cases to check how well your functions work, and you will certainly want to do the same!

It's impossible to programmatically guarantee that your code is correct. In fact, it's provably impossible to make such a guarantee! In practice, however, creating and running a set of tests for each of your functions, called unit-testing, is vital to producing useful, maintainable software. Unit testing is also a standard industry practice. In particular,

The provided example and starter file for problem 2 reinforces all of these points -- and shows off the built-in testing interface: a starter file for hw0pr2.rkt, with a comment and testing template. This includes the functions we wrote in class, which will be helpful as a starting point for Problem 2. (Problem 1 is both exploratory and graphical, so we will not unit-test its functions.)




Problem 0: Getting Started with Piazza

We will use Piazza for all Q&A in the class. You can ask questions that anyone in the class can answer, or (if you need to include code in your question) you can post a private question that only the Profs and Grutors will see.

Sign in to Piazza and check it out. If you have a question - post a question! If you can answer a question - answer a question!



Problem 1: hw0pr1.rkt (45 points)

A quick tour of Racket

Get to the Dr. Racket programming environment, either by downloading it to your personal computer or by using the CS lab.

On the CS department's Macs in BkB102 and BkB105, Dr. Racket can be found in the Additional Applications folder:

If you have forgotten your CS login or password (they may be different than the CIS one), feel free to ask Tim Buchheim, our administrator across the hall in Beckman B101, to reset it. Note this your CS password and your CS submission-site password are not the same (unless you've set them to be).

Once you have Racket running, go to the "Quick introduction" site:

The Racket quick-introduction site

which is a fun guide through a small piece of the language that uses images.

What to do    Work your way through those examples, at least up to section 8.

Do NOT worry if things start seeming crazy as you get into the later sections -- or, perhaps, the whole time! This problem is to start getting used to learning new computational interfaces, and they always seem crazy at first! You won't learn everything at once, but start to keep a list of some questions you have about the Racket language.

We will examine the ideas in sections 6-8 in more detail next week. As for sections 9-11, they are Racket-specific, rather than CS-specific, and we won't use enough Racket in CS 60 to warrant worrying about those.

Do type (or copy) the functions from sections 4-6 into the definitions pane of Dr. Racket's interface. Run them as you go. Also, save those definitions as the file hw0pr1.rkt. This is the file you will submit for problem 1.

To complete this problem, add these two functions and your answer to Question #1 to your hw0pr1.rkt file.

Question #1: Reflect (0 points - encouraged!)

Make a list of at least three notes about Racket. These can include:

Function #1: cboard (24 points)

Using the provided checkerboard function as a guide, create a function named cboard. But cboard should take three inputs, so that its definition will begin

(define (cboard n color1 color2)
The inputs should be n, the number of pixels of the component square of the resulting checkerboard, color1, a string representing the color of the upper left square, and color2, a string representing the color of the lower right square. The output should be an 8x8 checkerboard, using only squares of the designated size, with the appropriate colors. A good strategy for this problem is to understand the Racket quick-indtroduction tutorial's checkerboard function and then write an appropriately altered version named cboard.

Here is a screenshot of four examples:


Be sure to have a header comment for your function! Also, if you'd to add features, consider trying the extra credit, below...!

Function #2: hcomb (21 points)

Write another function, named hcomb, whose definition will begin

(define (hcomb n color1 color2 color3)
where the inputs are the same as for cboard, except that there is an additional color. Then hcomb should create a nine-by-nine grid of three-by-three patches of filled-in circles of the appropriate colors and the appropriate size. Start from the existing functions and change things slowly! You will want to use (disk diameter): click on the circle link in the quickstart tutorial to see all of the graphical primitives available.

Here are two examples (Bears and Packers colors, perhaps...):


Again, add a header comment for your function... .

Extra-credit! alien and extra

As completely optional extra-credit (of up to +5 points each), create functions named alien and/or extra that composes Racket's graphics primitives into artistic images of your own.

alien

The alien function should output a picture of an alien, broadly interpreted, and should take one input: (alien input) - you may choose what input does, e.g., it can control size, color, or some other feature such as number of eyes... .

extra

You have almost complete leeway in designing extra, e.g., it can create abstract, geometrical pictures or even more elaborate representations of aliens. It has only two constraints:


Be sure to submit your hw0pr1.rkt at the submission site without including your name!






Problem 2: hw0pr2.rkt (55 points)

Running with racket

For this problem, you will want to start with this starter file

hw0pr2.rkt

which includes a few examples of Racket syntax and its testing interface, along with the functions we wrote in class this week. As with human languages, lots of examples are the most efficient way to start feeling comfortable with a new programming language! This problem asks you to write a number of mathematical functions.

Testing (10 points)

For each problem below, you should include at least one additional test in your file, beyond what we provide. In this assignment we will provide complicated test cases. Before you write code, you should write out some simple test cases (because complicated test cases aren't very helpful for initial debugging).

Please be sure these additional tests are clearly marked with a comment above them. For example, for the erdos function you might have in your code:

; provided tests
(check-expect (erdos 84) 42)
(check-expect (erdos 85) 256)

; additional tests
(check-expect (erdos 6) 3)
(check-expect (erdos 7) 22)

Problem 2.1:    erdos (6 points)

For this problem define a function, named erdos, with one argument, N. Thus, your definition might begin as follows:

;; erdos: the "3N+1 function"
;;   inputs: an integer, N
;;   output: 3N+1, if N is odd
;;           N/2, if N is even
(define (erdos N)

This function should compute the following:

Here are a couple of tests to try.
; provided tests
(check-expect (erdos 84) 42)
(check-expect (erdos 85) 256)
Remember that you need (generate-report) at the end of your file in order for Racket to print a summary of your tests' results.

Warning: Racket's built-in integer-division function is quotient, not the / symbol. If you try (/ 3 2) you will get the rational number three-halfs (three-halves?), instead of the floating-point number 1.5 or the integer 1. But (quotient 3 2) evaluates to 1, as expected with integer division. The "mod" function in Racket is modulo, so that (modulo 12 7) evaluates to 5. See Prof. Keller's Racket Reference Card for a listing of the most important library functions.

Problem 2.2:    erdos-count (8 points)

Write erdos-count, a function of one positive integer argument:

(define (erdos-count N)
where erdos-count should return the smallest number of times erdos must be iterated, when started with an input of N, in order to arrive at a value of 1. Let's use the symbol ==> to mean "evaluates to." Then, (erdos-count 3) ==> 7, because
(erdos (erdos (erdos (erdos (erdos (erdos (erdos 3))))))) ==> 1
and there are 7 applications of erdos above.

Here are a few Racket tests:

; provided tests
(check-expect (erdos-count 26) 10)
(check-expect (erdos-count 27) 111)

These are relatively complicated test cases. BEFORE writing code you should write out 2-3 exceptionally simple test cases, which will be helpful fo debugging. Here's one you might consider including:

(check-expect (erdos-count 1) 0)

Be sure to use recursion when writing erdos-count. As a starting point, consider how we wrote half-count in class.

Problem 2.3:    count1bits (8 points)

Write count1bits, a function of one nonnegative integer argument:

(define (count1bits N)
where count1bits should return the number of times the bit 1 appears in the binary representation of N. Remember that N will be a nonnegative integer. Feel free to review binary representation, if you have not seen it for a while - you might also try the tests below, by hand.

Here are a few Racket tests (you should write a few simpler test cases before writing your code):

; provided tests
(check-expect (count1bits 6) 2)
(check-expect (count1bits 7) 3)
(check-expect (count1bits 42) 3)
Hints: you do not need to actually convert N to binary. (In fact, don't.) Instead, consider if the input is odd - what does that say about its rightmost bit? What if it's even? Also, what arithmetic operation will "get rid of" that rightmost bit, thereby "shifting" all the bits to the right by one place? As with all things Racket, recursion will be key!


Problem 2.4:    power (8 points)

Write power, a function of two integer inputs (it's OK to presume non-negative integers):

(define (power b p)
where b is the base and p is the power: it should evaluate to bp. We also specify that, for this function, b0 should be 1 for any b. Note that using the built-in power function expt is not allowed here -- imagine you're implementing it for the Racket library... . Rather, you should implement power in terms of multiplication, addition/subtraction, and recursion using the formula bp = b*bp-1. If you know a fancier algorithm for computing powers, save it until the next problem!

Here are a few Racket tests (you should write a few simpler test cases before writing your code):

; provided tests
(check-expect (power 2 5) 32)
(check-expect (power 5 2) 25)
The factorial example from class is a good starting point.

Experimental Run-time

Run the timing command:


(time (power 1 N))
replacing N by 1000, 10000, 100000, and 1 million. In fact, you're welcome to use the built-in expt for this:

;; time trials
(time (power 1 (expt 10 3))) ;; 1^1000
(time (power 1 (expt 10 4)))
(time (power 1 (expt 10 5)))
(time (power 1 (expt 10 6))) ;; 1^1000000
In a clearly marked comment, report your results. Multi-line comments in Racket use #| at the start and |# at the end. The numbers returned by time are For this problem, only worry about the CPU-time (and you might run a few trials because they will vary slightly each run). Comment on whether these match your expectations. You'll want to keep the base 1, so that the return values don't get ludicrously large!


Problem 2.5:    fast-power (15 points)

Write fast-power, identical in its inputs and outputs to power:

(define (fast-power b p)
where b is the base and p is the power. This time, however, you should use the following idea:

Warning!    Just writing fast-power using the above technique will not necessarily make it fast! In particular, you'll need to be sure you don't repeat computation too much. One helpful construct in Racket is let, which is used for defining local variables. (You saw let in the graphics examples of problem 1.) Here is an example:

(define (f x)
  (let* (
         (y (+ x 1))
         )
    (* y y)))
Here, the function f computes (x+1)*(x+1), but only does the work of adding 1 once. Look over let in the Racket documentation or the reference sheet (or use this example as a guide) in order to see if you can get your fast-power to actually run fast! (And it does run really fast!)

Experimental Run-time In a comment in your code, run timing tests for fast-power that are analogous to the above tests for power, report the results for fast-power. You might see how big an exponent you can raise 1 to before things start slowing down... .

The test values will be the same as for power:

; provided tests
(check-expect (fast-power 2 5) 32)
(check-expect (fast-power 5 2) 25)


Extra! Problem 2.6:    factor

For completely optional extra credit of up to +5 points each, write two functions: first-factor and factor, each of which take one integer input, N, which will be greater than 1.

(define (first-factor N)

(define (factor N)
These should compute the smallest ("first") factor of N and a list of all the factors of N, respectively. (See the tests.) Note that these add several challenges! First, you'll need to use Racket's lists (there are lots of references in its documentation). In addition, you'll need helper functions, and you'll need to be creative in what those helper functions will be!

Here are two tests for each:

; provided tests
(check-expect (first-factor 41) 41)
(check-expect (first-factor 42) 2)

(check-expect (factor 41) '(1 41))
(check-expect (factor 42) '(1 2 3 6 7 14 21 42))
Note that factor's output should include the 1 at the front of its list. As with the previous problems, you should include at least one test of your own to earn full (extra) credit for these.

Submit!

Be sure to submit both hw0pr1.rkt and hw0pr2.rkt at the submission site!