Lab 2: Conditionals and Reading Code

9 September 2022

Today’s lab

The purpose of this lab is to give you practice:

For this lab, you’re encouraged to work with a partner, but it can be completed individually if you prefer.

Part 1: Warm up

You’ve been asked to review a program written by a coworker. The problem they were asked to solve was to turn a numeric grade into its corresponding letter grade.

Your coworker shows you this solution:

fun grade(percent :: Number) -> String:
  doc: "Return the letter grade for a percent."
  if percent > 0:
    "F"
  else if percent >= 60:
    "D"
  else if percent >= 70:
    "C"
  else if percent >= 80:
    "B"
  else if percent >= 90:
    "A"
  end
end

Task: Answer the following questions in multi-line Pyret comment, like

#|
   This is my answer...
   continuing ...
   as long as I need it to!
|#

Part 2: Weather alerts

Exercise 2.1: Saffir–Simpson

Consider making a simple weather app that alerts users of severe weather based on wind speed using the Saffir–Simpson scale:

Category Wind Speed (mph)
5 ≥ 157
4 130–156
3 111–129
2 96–110
1 74–95
Tropical storm 39–73
Tropical depression ≤ 38

Task: Write a function that takes in the average recorded recent wind speed (in miles per hour) and returns the category to which that wind speed belongs:

fun saffir-simpson(wind-speed :: Number) -> String:
  ...
end

Here are some examples of the desired behavior of the saffir-simpson function:

››› saffir-simpson(65)
"Tropical storm"
››› saffir-simpson(111)
"Category 3"
››› saffir-simpson(0)
"Tropical depression"

You can assume all inputs are integers (that is, no decimals or fractions). Be sure to write tests for your function that address each category.

Exercise 2.2: At Vassar

For your weather app, you want to get alerts only about weather happening where you are – at Vassar!

Task: Write the function

fun at-vassar(latitude :: Number, longitude :: Number) -> Boolean:
  ...
end

It should return true if the specified latitude and longitude correspond roughly to the Vassar campus, with

For testing, you may want to use the coordinates

Exercise 2.3: Severe alert

For your weather app, you wish to get a severe weather notification if the wind speed is classified as a hurricane (Category 1–5) and the classification is for Vassar.

Task: Write the function

fun severe-alert(wind-speed :: Number, latitude :: Number,
    longitude :: Number) -> Boolean:
  ...
end

It takes the current wind speed and the location of the wind (latitude and longitude), and returns true if the storm is a categorized hurricane (1–5) and over Vassar, and false otherwise.

Here are some tests you can try (or make your own!):

# Hurricane at Main Building
severe-alert(190, 41.686804, -73.895664) is true
# Gentler weather at Main Building
severe-alert(10, 41.686804, -73.895664) is false
# Hurricane at the Griffith Observatory, Los Angeles
severe-alert(190, 34.119108, -118.300388) is false

Your severe-alert function should call the at-vassar function you just wrote!

Exercise 2.4: Extreme alert

On the other hand, maybe you have a relaxed attitude toward danger, and you only to only get an alert if the storm is the worst type (Category 5) and over Vassar.

Task: Write the function

fun extreme-alert(wind-speed :: Number, latitude :: Number,
    longitude :: Number) -> Boolean:
  ...
end

It works the same way as the previous function, but only returns true if the wind speed is "Category 5".

Consider how this function would differ from severe-alert. Can you think of a way you can use the saffir-simpson function you’ve already written to avoid duplicate code?

Part 3: Code clean up

Oh no – your coworker’s back!

They’ve been asked to write a function to compute the price for a newspaper ad based on the number of characters (that is, letters, numbers, spaces, and punctuation).

This time they’re sure the function works right, and they have test cases to prove it. But, the result is … not pretty:

fun ad-charge(ad):
  short-length = 10
  medium-length = 40
  long-length = 70
  if ((string-length(ad) >= short-length) and (string-length(ad) < medium-length)):
    (string-length(ad) * (short-length / 2)) + (string-length(ad) * 5)
  else if ((string-length(ad) >= medium-length) and (string-length(ad) < long-length)):
    (string-length(ad) * (medium-length / 2)) + (string-length(ad) * 5)
  else if (string-length(ad) >= long-length) :
    (string-length(ad) * (long-length / 2)) + (string-length(ad) * 5)
  else: 0
  end
where:
  ad-charge("Big Sale!") is 0
  ad-charge("End of Year Clearance") is 210
  ad-charge("End of Year Clearance -- Buy! Buy! Buy! Buy!") is 1100
end

Task: Rewrite ad-charge to follow good Pyret style (see our guide). Do your best to make the code clear and avoid repetition. But don’t change how it works – the provided test cases should still pass!

Submitting the lab

Acknowledgments

This lab includes material adapted from Kathi Fisler and colleagues at Brown University.