;; CSC 151-NN (SEMESTER) ;; Lab: Conditionals ;; Authors: YOUR NAMES HERE ;; Date: THE DATE HERE ;; Acknowledgements: ;; ACKNOWLEDGEMENTS HERE (import image) ;; This lab consists of a number of programming and reasoning exercises ;; about booleans and conditionals. Start with the A-side exercises with ;; A-side driving and B-side navigating. Then switch back and forth as ;; indicated. ;; +---------------+-------------------------------------------------- ;; | Provided code | ;; +---------------+ (define ??? "UNDEFINED") ;;; kitten : image? ;;; Our favorite image (define kitten "kitten.jpg") ;; Some colors (define gray0 (rgb 0 0 0)) (define gray1 (rgb 96 96 96)) (define gray2 (rgb 192 192 192)) (define gray3 (rgb 255 255 255)) ;;; (rgb-brightness c) -> number? (between 0 and 100) ;;; c : rgb? ;;; Find the approximate perceived brightness of c. (define rgb-brightness (lambda (c) (round (* 100/255 (+ (* .30 (rgb-red c)) (* .59 (rgb-green c)) (* .11 (rgb-blue c))))))) ;;; (rgb-darker-32 c) -> rgb? ;;; c : rgb? ;;; Make c darker by subtracting 32 from each component (define rgb-darker-32 (lambda (c) (rgb (- (rgb-red c) 32) (- (rgb-green c) 32) (- (rgb-blue c) 32)))) ;;; (rgb-lighter-32 c) -> rgb? ;;; c : rgb? ;;; Make c ligher by adding 32 to each component (define rgb-lighter-32 (lambda (c) (rgb (+ (rgb-red c) 32) (+ (rgb-green c) 32) (+ (rgb-blue c) 32)))) ; +-------------+---------------------------------------------------- ; | Preparation | ; +-------------+ ;; 1. Introduce yourself to your partner. Make sure to discuss working ;; habits and other topics. ;; 2. Save this file as `conditionals.rkt`. ;; 3. Reload Scamper. ;; 4. Note that Partner A is the partner closer to the board and Partner ;; B is the partner further from the board. ;; 5. Optional: Review the Q&A from the readings. ;; Division of labor: ;; * A drives on 1, 4, 5 ;; * B drives on 2, 3, 6 ; +---------------------------------------------+-------------------- ; | Exercise 1: Mixing conditionals and numbers | ; +---------------------------------------------+ ; Driver: A ;; In this exercise, we continue to explore how to work with the ;; primitive types and their standard library functions. Use functions ;; from the Racket standard library to implement the following common ;; functions that utilize booleans. ;; When you are done, you should experiment with your function in the ;; interactions pane on a variety of inputs to verify that the program ;; works as expected. ;; a. Write a predicate `(is-even? n)` that takes an integer as input ;; and returns true if `n` is even and false otherwise. ;; > (is-even? 4) ;; #t ;; > (is-even? 5) ;; #f ;; > (is-even? -11) ;; #f ;; > (is-even? -22) ;; #t ;; You may not use the built-in `even?` or `odd?` predicates. ;; You may, however, use the `remainder` procedure you recently learned. ;; You need not check that the input is an integer. If given a non-integer ;; input, your procedure can fail. (define is-even? (lambda (n) ???)) ;; `is-even?` reports an error when `n` is not an integer. ;; > (is-even? 3.4) ;; Boom! ;; > (is-even? "four") ;; Boom! ;; Write a predicate, `(is-even-integer? n)`, that returns true when ;; `n` is an even integer and false otherwise. ;; Your procedure should return false when `n` is real number, ;; a string, an image, a color, and, well, anything that's not ;; an integer. ;; > (is-even-integer? 3.4) ;; #f ;; > (is-even-integer? "four") ;; #f ;; > (is-even-integer? 4) ;; #t ;; > (is-even-integer? -8) ;; #t ;; > (is-even-integer? 7) ;; #f (define is-even-integer? (lambda (n) ???)) ;;; c. Write a function (decimal-number? n) that returns true if `n` ;;; is a number that includes a decimal portion and false otherwise. ;; > (decimal-number? 3) ;; #f ;; > (decimal-number? 3.4) ;; #t ;; > (decimal-number? -2.5 ;; #t ;; > (decimal-number? "hello") ;; #f ; TODO: write your function here! ;; d. Write a function, `(median-of-three x y z)`, that takes three ;; real numbers as input and returns the number that is the middle ;; value of the three when put in numerical order. If two numbers are ;; the same, you can return that number. If all three are the same, ;; you can return that number. ;; Note that you need not put the numbers in order; the definition above ;; is for what the median is. ; TODO: write your function here! ;; +---------------------------------------------+-------------------- ;; | Exercise 2: Mixing conditionals and strings | ;; +---------------------------------------------+ ; Driver: B ;; In this exercise, we continue learning how to work with the primitive ;; types and their standard library functions. Use functions from the ;; Racket standard library to implement the following common functions ;; that utilize booleans. ;; When you are done, you should experiment with your function in the ;; interactions pane on a variety of inputs to verify that the program ;; works as expected. ;; a. In a particular company, employees are given IDs that consist of ;; a string of 6 digits, e.g., "419109". ;; Write a function, `(employee-id? str)`, that takes a string as input ;; and determines whether the string is a valid employee id. You need ;; not check that `str` is a string. ;; > (employee-id? "123456") ;; #t ;; > (employee-id? "1") ;; #f ;; > (employee-id? "000111") ;; #t ;; > (employee-id? "00011x") ;; #f ;; > (employee-id? 123456) ;; Boom! Crash! ;; > (employee-id? "123.45") ;; #f ;; > (employee-id? "123/45") ;; #f ;; Hint: `string->number` may help. `string-length` may help. `substring` ;; may help. (define employee-id? (lambda (str) ???)) ;; b. The founders of the company are given IDs where the first 3 ;; digits are 0s, e.g., "000110". ;; Write a function `(founder-id? str)` that takes a string as input and ;; determines whether the string is a valid founder's ID. ;; Note that you should use `employee-id?` to ensure that the id is a ;; valid employee id. ;; Hint: `substring` may help with the additional check. (define founder-id? (lambda (str) ???)) ;; +----------------------------------+------------------------------- ;; | Exercise 3: Exploring brightness | ;; +----------------------------------+ ;; At the top of this lab, you will find a procedure, `(rgb-brightness c)`, ;; gives the approximate perceived brightness of a color as a real number ;; between 0 and 100. ;; a. Write a procedure, `(rgb-bright? c)`, that takes an RGB color ;; as a parameter and returns true (#t) if the brightness of c is at ;; least 50 and returns false (#f) if the brightness is less than 50. ;;; (rgb-bright? c) -> boolean? ;;; c : rgb? ;;; Determines if c is bright (brightness at least 50) (define rgb-bright? (lambda (c) ???)) ;; b. Write a procedure, `(better-rgb-bright? c)`, that takes an RGB ;; color OR the name of a color as a parameter and returns true (#t) if ;; the brightness of c is at least 50 and returns false (#f) if the ;; brightness is less than 50. ;; You may find the `color-name?` and `color-name->rgb` procedures useful. ;;; (better-rgb-bright? c) -> boolean? ;;; c : (any-of rgb? color-name?) ;;; Determines if c is bright (brightness at least 50) (define better-rgb-bright? (lambda (c) ???)) ;; c. Pick five color names and determine if each is bright. Write ;; your answers below. (E.g., "white is bright", "black is not bright".) ;; i. ;; ii. ;; iii. ;; iv. ;; v. ;; +-----------------------------------+------------------------------ ;; | Exercise 4: Brightness, continued | ;; +-----------------------------------+ ;; Driver:: A ;; a. Write a procedure, `(rgb-brighter? c1 c2)`, that takes two RGB ;; colors as parameters and determines whether c1 is brighter than c2. ;;; (rgb-brighter? c1 c2) -> boolean? ;;; c1 : rgb? ;;; c2 : rgb? ;;; Determines if c1 is brighter than c2. (define rgb-brighter? (lambda (c1 c2) ???)) ;; b. Write a procedure, `(rgb-brighter c1 c2)`, that takes two ;; RGB colors as parameters and returns the brighter of c1 and c2. ;;; (rgb-brighter c1 c2) -> rgb? ;;; c1 : rgb? ;;; c2 : rgb? ;;; Find the brighter of c1 and c2. (define rgb-brighter (lambda (c1 c2) ???)) ;; +--------------------------------------+--------------------------- ;; | Exercise 5: A strange transformation | ;; +--------------------------------------+ ;; Consider the following procedure. ;;; (rgb-something c) -> rgb? ;;; c : rgb? ;;; ??? (define rgb-something (lambda (c) ((if (rgb-bright? c) rgb-lighter rgb-darker) c))) ;; a. To the best of your ability, explain what `rgb-something` does. ;; You might determine this through experimentation with individual ;; colors, by applying it to the kitten image, by reading the code, ;; or through other techniques. ;; Spend no more than two minutes on this part of the problem. ;; REPLACE THIS WITH YOUR ANSWER ;; b. To the best of your ability, explain *how* `rgb-something` ;; works. Spend no more than two minutes on this! ;; REPLACE THIS WITH YOUR ANSWER ;; +----------------------------------+------------------------------- ;; | Exercise 6: Simplified grayscale | ;; +----------------------------------+ ;; Using `cond` (and not nested `if` expressions), write a procedure, ;; `(rgb-4gray c)`, that converts a color into black, white, or ;; a shade of gray using the four `gray#` procedures defined above. ;; * Return `gray0` if the brightness of `c` is less than 25; ;; * Return `gray1` if the brightness of `c` is at least 25 but less than 50; ;; * Return `gray2` if the brightness of `c` is at least 50 but less than 75; ;; * Return `gray3` if the brightness of `c` is at least 75. ;;; (rgb->4gray c) -> rgb? ;;; c : rgb? ;;; Convert c to black, white, or a gray. (define rgb->4gray (lambda (c) ???)) ;; You should also try using `pixel-map` to apply this procedure to the ;; kitten. ;; +----------------------+------------------------------------------- ;; | Submitting your work | ;; +----------------------+ ;; Congratulations on finishing this lab! To turn in your work: ;; a. Ensure that your file runs properly. ;; b. Put your names at the top of the file. ;; c. Rename this file to `conditionals.scm` ;; name). ;; d. Submit this final file and the kitten image to Gradescope. Make sure, ;; if appropriate, to submit your work as a group submission and ;; include your partner in the submission. ;; +---------------------------+-------------------------------------- ;; | For those with extra time | ;; +---------------------------+ ;; If you find that you have extra time, you might want to attempt ;; one or more of these exercises (after you submit). ;; +------------------------------+----------------------------------- ;; | Extra 1: Conditional tracing | ;; +------------------------------+ ;; Driver: A ;; Consider the following code snippet: (define foo (lambda (x1 x2) (if (< x1 x2) #t #f))) (define bar (lambda (x1 x2) (< x1 x2))) ;; Here's a trace of two similar expressions. ;; (foo 2 4) ;; --> (if (< 2 4) #t #f) ;; ; Evaluate the test ;; --> (if #t #t #f) ;; ; The test is truish; Use the consequent ;; --> #t ;; ;; (bar 2 4) ;; --> (< 2 4) ;; --> #t ;; Remember that to trace an `if` expression, you first evaluate the guard ;; (the first "parameter" to `if`). If the guard holds, you replace the ;; `if` with the consequent (the second "parameter" to `if`). If the guard ;; does not hold, you replace the `if` with the alternate (the third "parameter" ;; to `if`). ;; Give execution traces for each of the following expressions. Check ;; with the interactions pane that your final value coincides with the ;; result of evaluating the expression in Racket. ;; a. (foo 5 3) ;; (foo 5 3) ;; --> ;; --> ;; ... ;; b. (bar 5 3) ;; (bar 5 3) ;; --> ;; --> ;; ... ;; c. What do you see as the similarities and differences between ;; `foo` and `bar`? ;; REPLACE WITH YOUR ANSWER ;; +------------------------+----------------------------------------- ;; | Extra 2: More tracing! | ;; +------------------------+ ;; Driver: B ;; Consider the following code snippet: (define baz (lambda (x1 x2 x3) (if (< x1 x2) (if (< x2 x3) #t #f) #f))) (define qux (lambda (x1 x2 x3) (and (< x1 x2) (< x2 x3)))) ;; Here are some execution traces. ;; (baz 2 3 4) ;; --> (if (< 2 3) (if (< 3 4) #t #f) #f) ;; ; Evaluate the test ;; --> (if #t (if (< 3 4) #t #f) #f) ;; ; The test is truish; use the consequent ;; --> (if (< 3 4) #t #f) ;; ; Evaluate the test ;; --> (if #t #t #f) ;; ; The test is truish; use the consequent ;; --> #t ;; (qux 2 3 4) ;; --> (and (< 2 3) (< 3 4)) ;; ; Evaluate the first argument to `and` ;; --> (and #t (< 3 4)) ;; ; The first argument is truish; drop it ;; --> (and (< 3 4)) ;; ; There's only one argument to and, use it ;; --> (< 3 4) ;; --> #t ;; (baz 3 2 4) ;; --> (if (< 3 2) (if (< 2 4) #t #f) #f) ;; ; Evaluate the test ;; --> (if #f (if (< 2 4) #t #f) #f) ;; ; The test is false, use the alternate ;; --> #f ;; (qux 3 2 4) ;; --> (and (< 3 2) (< 2 4)) ;; ; Evaluate the first argument to `and` ;; --> (and #f (< 2 4)) ;; ; When the first argument to `and` is false, the result is false. ;; --> #f ;; (baz 3 4 2) ;; --> (if (< 3 4) (if (< 4 2) #t #f) #f) ;; ; Evaluate the test ;; --> (if #t (if (< 4 2) #t #f) #f) ;; ; The test is true, use the consequent ;; --> (if (< 4 2) #t #f) ;; ; Evaluate the test ;; --> (if #f #t #f) ;; ; The test is false, use the alternate ;; --> #f ;; (qux 3 4 2) ;; --> (and (< 3 4) (< 4 2)) ;; ; Evaluate the first argument to `and` ;; --> (and #t (< 4 2)) ;; ; When the first argument to `and` is true or truish, we move on ;; ; to the remaining arguments ;; --> (and (< 4 2)) ;; ; Evaluate the first argument to `and`. ;; --> (and #f) ;; ; When the first argument to `and` is false, return false ;; --> #f ;; a. Why do you think we choose those three example inputs (that is, "2 3 4", ;; "3 2 4" and "3 4 2")? ;; REPLACE WITH YOUR ANSWER ;;; b. What do you see as the similarities and differences between ;;; `baz` and `qux`? ;; REPLACE WITH YOUR ANSWER ;; +----------------------+------------------------------------------- ;; | Extra 3: Boolean Zen | ;; +----------------------+ ;; Driver: B ;; a. In a previous exercise, you wrote a function, `is-even?` that ;; determines whether a number is even. Consider the following functions ;; that uses `is-even?` to determine if both of its parameters are even. (define really-bad-both-even? (lambda (n1 n2) (if (equal? (is-even? n1) #t) (if (equal? (is-even? n2) #t) #t #f) #f))) ;; For example: ;; > (really-bad-both-even? 2 4) ;; #t ;; > (really-bad-both-even? 1 2) ;; #f ;; We claim that this implementation is "really bad" not because it ;; produces the wrong answer, but because it is sylistically offensive! ;; First, rewrite this function as `bad-both-even?` below using `and` ;; and `or` to remove the need for a nested conditional expression. ;; Experiment with `better-even?` on a variety of examples to gain ;; confidence that your function works identically to ;; `really-bad-both-even?`. (define better-both-even? (lambda (n1 n2) ???)) ;; b. If your implementation of `better-both-even?` still contains a ;; conditional, then you still have more work to do! Rewrite the ;; function one more time as `both-even?` below that uses neither `if` ;; nor `cond` in its implementation. Again, experiement with `both-even?` ;; and a variety of examples to ensure that it works identically to ;; the previous implementations. (define both-even? (lambda (n1 n2) ???)) ;; c. The process of reimplementing `both-even?` so that it is better ;; designed while keeping its behaviror the same is called "refactoring". ;; Refactoring this function tells us something profound about booleans ;; and expressions, a concept that some faculty in the CS department ;; picked up from Stuart Reges at the University of Washington called ;; "boolean zen" (or "Boolean Zen"). In this class, we often use the ;; slightly more verbose "The Zen of Booleans". ;; Suppose that I have a piece of code that looks as follows: ;; (if #t #f) ;; where `` is a Boolean expression. Based on `both-even?` or ;; the code tracing exercises, describe what I can rewrite this code ;; to that is equivalent to the original version but more concise. In ;; a few sentences, describe and justify your answer. ;; REPLACE WITH YOUR CODE AND EXPLANATION ;; d. Finally, use the concept of the Zen of Booleans to write a concise ;; version of the function `(both-odd? n1 n2)` that returns true only ;; when both of its arguments are odd?. You may assume that both ;; parameters are integers. ;; Note: simply negating `both-even?` won't work since `both-even?` ;; will return false if one argument is even and the other is odd. ;; You may not use the `odd?` predicate here, but you may use the ;; `is-even?` procedure. (define both-odd? (lambda (n1 n2) ???)) ;; +-------------------------------------+---------------------------- ;; | Extra 4: Median of three, revisited | ;; +-------------------------------------+ ;; Driver: A ;; Earlier, you wrote `median-of-three`. Write a version of `median-of-three` ;; without conditionals. (You may not even use `and` or `or`.) ;; Hint: You may find that `max` and `min` help. (define new-median-of-three (lambda (x y z) ???))